0
+ (id)packetWithType:(PacketType)packetType
{
    return [[[self class] alloc] initWithType:packetType];
}

- (id)initWithType:(PacketType)packetType
{
    if ((self = [super init]))
    {
        // code
    }
    return self;
}

なぜ最初のクラスのメソッドが必要なのですか?

4

2 に答える 2

6

便利なコンストラクター クラス メソッドを使用する理由は 2 つあります。1 つ目は、のイディオム[[Thing alloc] initWithFoo: xyz]は非常に一般的ですが、どこでも入力しなければならないのは不便だということです。だから、[Thing thingWithFoo: xzy]一般的な略語です。

より深い理由は、参照カウントに関係しています。で始まるメソッドinitは、インスタンスの参照を返すことになっており、その所有権は呼び出し元に譲渡されます。一方、コンビニエンス クラス メソッドは通常autoreleased 参照を返します。

+ (id)packetWithType:(PacketType)packetType
{
    return [[[[self class] alloc] initWithType:packetType] autorelease];
}

これは、ダングリング参照やメモリ リークを回避するために知っておくことが重要です。

Thing* thing = [[Thing alloc] initWithFoo: xyz];
// Now, *I* own the reference and *I* am responsible for releasing
// it, when I no longer need it.
[thing release]

一方、によって返される参照

Thing* thing = [Thing thingWithFoo: xyz];

「最も近い」が所有していNSAutoreleasePoolます。呼び出し元はそれを解放する責任はありません (実際、それは間違っています!)。参照を保持する場合、呼び出し元は実際retainにここで参照する必要があります。

self->myMember = [thing retain];

たとえ(ARCの下で)それらに従うコードを生成するのがコンパイラであっても、基礎となる規則は依然として有効であるため、ARCを使用する場合でもこれらの規則について知っておく必要があります。NARC頭字語は、どのメソッド名のプレフィックスが特定の責任を伴うかを覚えておくのに良い方法です。この回答には詳細があります。

于 2013-03-13T10:20:40.397 に答える
1

コンビニエンスコンストラクターは、いくつかの理由で言語にその役割を果たします。もちろん、それらを使用することは通常より短いですが、他の利点もあります:

  1. オブジェクトが呼び出されたときにオブジェクトはまだ割り当てられていないため、メソッドは割り当てるクラスを決定できます。クラスクラスターは、コンストラクターのパラメーターに応じて、これを使用して適切なクラスを見つける場合があります。
  2. このメソッドは、共有キャッシュから既存のオブジェクトを返すことも決定する場合があります。
  3. 戻り値は静的に入力できます。

通常、コンビニエンスコンストラクターは次のようになることに注意してください。

+ (Packet *)packetWithType:(PacketType)packetType
{
    return [[self alloc] initWithType:packetType];
}

これで、戻り型は静的に型指定され、(冗長)classメッセージをクラスオブジェクトに送信しません。最近のコンパイラバージョンinstancetypeでは、リターンタイプとして使用できます。

于 2013-03-13T10:35:07.640 に答える