Home > Articles > Programming > C/C++

  • Print
  • + Share This
From the author of

Method Families

Part of the new memory model includes formalization of the method families that are used informally in OpenStep. Methods that return objects are now expected to return a non-owning reference, with a few exceptions, grouped into method families. A method family is based on an archetypal method, such as +new or -init. Methods implicitly belong to the family if they begin with the name of the archetype (optionally prefixed with an underscore), optionally followed by an uppercase letter. For example, -_init and -initWithObject: both belong to the init family, but -initialize would not.

Methods that start with new or alloc, such as +newObject or +allocWithZone: are expected to return an owning reference to an instance of the receiver. This is not just part of ARC, and it allows some extra type checking in Objective-C. For example, the +new method itself is defined on NSObject as returning id, but with clang now you will get an error if you do this:

NSMutableArray *array = [NSArray new];

Clang will infer the type of the return value, and assume that it is an NSArray, which cannot be implicitly cast to an NSMutableArray and so will raise a warning. This is even more useful in Objective-C++0x, where you can do:

auto array = [NSMutableArray new];

The type of array will then be inferred as NSMutableArray, rather than id, and the compiler will check all message sends to array are valid with an NSMutableArray receiver.

The next method family is the copy family, with -copy and -mutableCopy both serving as archetypes. These methods are expected to return an owning reference to an instance of the same class as the receiver.

The most interesting method family is -init. In -init methods, it's common to write something like this:

    self = [super init];
    if (nil == self) { return nil; }

This is tricky in ARC mode. In most methods in ARC mode, self is const: assignment to it is not allowed. The reason for this is slightly ugly: Treating self as a normal variable made a lot of optimizations difficult and prevented the optimizer from removing retain and release operations, making ARC a lot slower.

The init method family is an exception to this rule. Assignment to self is permitted in ARC mode, but you are then not allowed to use the old value. For example, this has undefined behavior:

    id tmp = self;
    self = [super init];
    [tmp log];

To accommodate this pattern, the init method is assumed to consume its receiver and return a new owning reference, which may be to the same object. This is already informally assumed. The static analyzer will warn you in non-ARC code if you do something like this:

    SomeClass *obj = [SomeClass alloc];
    [obj init];

The return value for -init is not assumed to be the receiver—and frequently isn't in the case of class clusters—so the -init call here may invalidate obj and then leak the returned object. If you subsequently use obj, then you are using an invalid object.

  • + Share This
  • 🔖 Save To Your Account