0

私は iPhone 用の Objective-C / Cocoa-Touch でコーディングしています。たとえば、親クラスには 3 つのイニシャライザがあり、これらはすべて子クラスから継承する必要があります。この場合、連鎖しなくても大丈夫ですか?たとえば、この 1 つのクラスでは、次のように設定しています。

- (id)initWithGraphic:(Graphic*)graphic size:(CGSize)size
{
    self = [super initWithFrame:CGRectZero];
    if (self) 
    {
      ...

    }
    return self;
}

- (id)initWithGraphic:(Graphic*)graphic maximumDimension:(CGFloat)maximumDimension
{
    self = [super initWithFrame:CGRectZero];
    if (self) 
    {
      ...

    }
    return self;
}

- (id)initWithGraphic:(Graphic*)graphic 
{
    self = [super initWithFrame:CGRectZero];
    if (self) 
    {
      ...

    }
    return self;
}

したがって、基本的に指定されたイニシャライザは 1 つもありません。それらを連鎖させるのは難しいためです。基本的には 3 つです。

4

1 に答える 1

6

簡単な答え: コードを理解しやすく保守しやすくしたい場合は、常にの指定された初期化子を呼び出す必要があります。super

長い答え...

-[NSObject init]メソッドは何もしないように文書化されています:

initクラスで定義されたメソッドはNSObject初期化を行いません。単純に を返しますself

したがって、理論的には、それを呼び出す必要はありません。実際には、コードをより均一にする (したがって理解しやすくする) ため、それを呼び出すことNSObjectをお勧めします。

いくつかの継承チェーンがあり、 とMyGrandparent > MyParent > MyObjectの両方の実装者であり、 のすべての初期化子をオーバーライドしない場合、初期化子から のオーバーライドされていない初期化子の1 つを直接呼び出すことができます。しかし、繰り返しますが、これは悪い考えです。あなたや他の誰かが後でコードを再検討しなければならないときに混乱し、後で実装を変更すると壊れる可能性があります。MyParentMyObjectMyParentMyGrandparentMyGrandparentMyObjectMyParent

また、複数のイニシャライザを作成している場合は、ここここで指定されたイニシャライザ について学ぶ必要があります。イニシャライザの 1 つを指定イニシャライザとして選択し、すべてのサブクラス イニシャライザがスーパークラスの指定イニシャライザを直接呼び出すようにすることが重要です。そうしないと、無限再帰が発生する可能性があります。この問題は、この回答この回答で徹底的に説明しました。

アップデート

あなたの例では、次のように指定された初期化子を設定できます。

static CGFloat const kMaximumDimensionNone = 0; // or NAN if 0 is a valid max dimension
static CGSize const kSizeNone = { 0, 0 }; // or NAN, NAN if 0x0 is a valid size

- (id)initWithGraphic:(Graphic *)graphic size:(CGSize)size maximumDimension:(CGFloat)maximumDimension {
    if (self = [super init]) {
        _graphic = graphic;
        if (!CGSizeEqualToSize(size, kSizeNone)) {
            [self configureWithSize:size];
        }
        else if (maximumDimension != kMaximumDimensionNone) {
            // Use if(!isnan(maximumDimension)) instead if you use NAN as the placeholder
            [self configureWithMaximumDimension:maximumDimension];
        }
        else {
            [self configureWithDefaultDimensions];
        }
    }
    return self;
}

- (id)initWithGraphic:(Graphic *)graphic {
    return [self initWithGraphic:graphic size:kSizeNone maximumDimension:kMaximumDimensionNone];
}

- (id)initWithGraphic:(Graphic *)graphic size:(CGSize)size {
    return [self initWithGraphic:graphic size:size maximumDimension:kMaximumDimensionNone];
}

- (id)initWithGraphic:(Graphic *)graphic maximumDimension:(CGFloat)maximumDimension {
    return [self initWithGraphic:graphic size:kSizeNone maximumDimension:kMaximumDimensionNone];
}

指定された初期化子をパブリック ヘッダー ファイルで公開する必要はありません。インポートするサブクラスの指定された初期化子を公開する別のヘッダー ファイルを追加できます。たとえば、Apple は、カテゴリを onUIGestureRecognizerSubclass.hで宣言するヘッダーでこれを行います。ForSubclassEyesOnlyUIGestureRecognizer

または、メソッドをサブクラスに公開することもできconfigureWith...ます。おそらく、それらに初期化子をオーバーライドさせる必要さえないでしょう。

于 2012-10-13T07:23:17.767 に答える