Search code examples
objective-csuperclasslazy-initialization

What is the proper way to lazy initialize an abstract property in Objective-C


In super class:

@property (strong, nonatomic) Foo *foo;

In sub class:

- (Foo *) foo
{
     if(!super.foo) super.foo = [[Foo alloc] init];
     return super.foo;
}

Does this make sense? Is it even a good idea to have abstract properties?


Solution

  • Strictly speaking, there is no "abstract class" or "abstract property" in Objective-C, see for example this thread Creating an abstract class in Objective-C for a good overview.

    Your approach is not optimal, because it requires that the superclass implements foo and setFoo:, which contradicts the idea of "abstractness".

    A better solution is to define a "dynamic property" in the superclass:

    @interface SuperClass : NSObject
    @property (strong, nonatomic) Foo *foo;
    @end
    
    @implementation SuperClass
    @dynamic foo;
    @end
    

    and explicitly synthesize it in the subclass:

    @interface SubClass : SuperClass
    @end
    
    @implementation SubClass
    @synthesize foo = _foo;
    @end
    

    Now you can access foo on a subclass object, but on a superclass object it will cause a runtime exception.

    For lazy initialization, you can use the usual pattern, without any "super-tricks":

    - (Foo *) foo
    {
        if(!_foo) _foo = [[Foo alloc] init];
        return _foo;
    }
    

    An alternative approach (also mentioned in above thread) is to use a "protocol" instead of a common superclass:

    @protocol HasFoo <NSObject>
    - (Foo *)foo;
    @end
    
    @interface MyClass : NSObject<HasFoo>
    @property(strong, nonatomic) Foo *foo;
    @end
    
    @implementation SubClass
    - (Foo *) foo
    {
        if(!_foo) _foo = [[Foo alloc] init];
        return _foo;
    }
    @end