Objective C class initialization

2019-08-16 01:13发布

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

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

Why do we need first class method, isn't second one just enough for initialization ??

2条回答
来,给爷笑一个
2楼-- · 2019-08-16 01:51

There are two reasons for having convenience constructor class methods. The first one is, that the idiom of [[Thing alloc] initWithFoo: xyz] is really common but inconvenient to have to type anywhere. So, [Thing thingWithFoo: xzy] is a common abbreviation.

A deeper reason has to do with reference counting. Methods starting with init are supposed to return a reference of the instance, ownership of which is transferred to the caller. Wheras the convenience class methods usually return autoreleased references:

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

This is important to know in order to avoid dangling references and/or memory leaks:

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]

On the other hand, the reference returned by

Thing* thing = [Thing thingWithFoo: xyz];

is owned by the "nearest" NSAutoreleasePool. The caller is not responsible for releasing it (in fact, that would be wrong!). If the reference is to be kept around, the caller must actually retain it here:

self->myMember = [thing retain];

You should know about these conventions even when using ARC, as the underlying rules are still in effect, even if (under ARC) it's the compiler, who generates the code to obey them. The NARC acronym is a nice way to remember, which method name prefixes come with certain responsibilities. This answer has the details.

查看更多
SAY GOODBYE
3楼-- · 2019-08-16 01:56

Convenience constructors have their place in the language for some reasons. Of course using them is usually shorter but there are other advantages as well:

  1. The object is not yet allocated when they are called so the method can decide which class to allocate. Class clusters might use this to find the proper class depending on the parameters of the constructor.
  2. The method might also decide to return an already existing object from a shared cache.
  3. The return value can be statically typed.

Note that your convenience constructor would typically be:

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

Now the return type is statically typed and we don't send the (redundant) class message to the class object. With recent compiler versions one could use instancetype as the return type.

查看更多
登录 后发表回答