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

拥有便利的构造函数类方法有两个原因。第一个是,这个习语[[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 回答