0

次のような自己生成クラスを作成しようとしています。

Test *test = [[Test alloc] init];
[test setFrame:frame];
[test setBackgroundColor:[UIColor redColor]];
[self addSubview:test];

これはUIViewサブクラスであり、このコードはinitWithFrame:メソッド内にあります。クラスTestはそれ自身の名前であり、自己生成します。

私が遭遇した問題は、上記の最初の行にブレークポイントを追加したところ、最初の行を通過せず、新しいインスタンスを作成するだけでビューに追加されないことがわかります。これは不可能ですか、それとも適切に行う方法をもっと「勉強」する必要がありますか?

それがどのように見えるかをイメージしてください:xCodeの画像

ご覧のとおり、最初の行を超えることはありません。

4

3 に答える 3

4

わかった。initWithFrame:コードの問題は、それがUIViewの指定された初期化メソッドであることを忘れていることです。したがって、[[Test alloc] init]そのinit呼び出しを呼び出しても、initWithFrame:それ自体が呼び出されるため、無限ループが作成されます。

編集

iOS には、「指定された」初期化子の概念があります。いくつかの「init」メソッドがある場合は、そのうちの 1 つを「指定された」init にする必要があります。たとえば、UIViewの指定された初期化子はinitWithFrameです。これは、他のすべての init メソッドが内部でそれを呼び出すことを意味します。

UIViewinitメソッドは次のようになります。

-(id)init {
    return [self initWithFrame:CGRectMake(0,0,0,0)];
}

これは、クラスを [[Test alloc] init] としてインスタンス化したとしても、initWithFrameとにかく によって呼び出されることを意味しますUIView

ここで、クラス内でオーバーライドし、そのメソッド内で別のインスタンスを作成しinitWithFrame:て、再度呼び出していますTestTestinitWithFrame:

// the init call you have inside this method is calling initWithFrame again beacause
// you're referring to the same Test class...
-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) 
    {
        // This line here is creating the infinite loop. Right now you're inside
        // Test's initWithFrame method. Here you're creating a new Test instance and
        // you're calling init... but remember that init calls initWithFrame, because
        // that's the designated initializer. Whenever the program hits this line it will 
        // call again initWithFrame which will call init which will call initWithFrame 
        // which will call init... ad infinitum, get it?
        Test *test = [[Test alloc] init];

        [test setFrame:frame];
        [test setBackgroundColor:[UIColor redColor]];
        [self addSubview:test];
    }
}

EDIT2: 考えられる回避策の 1 つ

これを防ぐためにできることの 1 つは、変数 (フラグ) を宣言して、それ自体のインスタンスをさらに作成し続けるstatic boolかどうかを示すことです。Test

static BOOL _keepCreating = YES;

@implementation Test

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) 
    {
        // Remember to set _keepCreating to "NO" at some point to break
        // the loop
        if (_keepCreating) 
        {
            Test *test = [[Test alloc] init];
            [test setFrame:frame];
            [test setBackgroundColor:[UIColor redColor]];
            [self addSubview:test];
        }
    }
}

@end

お役に立てれば!

于 2013-10-22T22:05:30.147 に答える
1

無限ループを作成しました。-initまたはについてではありません-initWithFrame:。init を呼び出すたびに別の Test インスタンスが作成され、別の Test インスタンスが作成され、別の Test インスタンスが作成されます...

代わりに、次のようにサブビューを Test のプロパティとして作成します。

@interface Test : UIView
@property ( nonatomic, readonly ) Test * testSubview ;
@end

次に、 の遅延初期化アクセサーを作成しますtestSubview

@implementation Test

-(Test*)testSubview
{
    if ( !_testSubview )
    {
        Test * view = [ [ Test alloc ] initWithFrame:CGRectZero ] ;
        [ self addSubview:view ] ;
        _testSubview = view ;
    }
    return _testSubview ;
}

-(void)layoutSubviews
{
    [ super layoutSubviews ] ;
    [ self.testSubview setFrame:self.bounds ] ; // testSubview will be created if it doesn't exist...
}

@end
于 2013-10-22T23:04:49.783 に答える
0

あなたが達成しようとしていることは何ですか?

あなたはコールinitWithFrameしているだけでなくinit、少し奇妙です。

コードの残りの部分がどのように見えるかに応じて、無限ループの領域に入り、Testオブジェクトの無限のストリームを作成し、それ自体のサブビューとして追加することができます。

おそらく、クラスの新しいインスタンスを返すクラス メソッドを探しているのでしょTestうか? それは次のようになります。

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setBackgroundColor:[UIColor redColor]];
    }
    return self;
}

+ (id)testWithFrame:(CGRect)frame
{
    Test * test = [[Test alloc] initWithFrame:frame];
    return test;
}

別のオブジェクトTestのサブビューとして追加されたオブジェクトを本当に探している場合は、メソッドでそれを行います。TesttestWithFrame:

于 2013-10-22T22:09:16.630 に答える