Search code examples
objective-cobjective-c-blocksvariable-initialization

Referencing self in Block passed to constructor


I have an Objective-C object where I'm passing a Block to it's constructor. It's a special case where I want to fire that Block in a view controller when it loads completely. However, in that Block I also want to reference the object that I'm passing the Block into. Consider this example:

typedef void (^MyBlock)();

//constructor of my object
-(id)initMyObjectWithBlock:(MyBlock)block{
    self = [super init];
    if(self){
        myivar = block; //to be used later
    }
}

//somewhere else in my app
MyObject *obj = [[MyObject alloc] initMyObjectWithBlock:^{
   [obj doSomething];
}];

At that [obj doSomething] line, I am getting "Variable is uninitialized when captured by block" warning, which makes sense. In that Block, I need a reference to the "parent" object (obj in this case). Is there any way to achieve this? I do know workarounds and patterns to my specific problem, but I wanted to know if such a reference is possible.


Solution

  • If you simply set your object to nil before creating an instance as following, it should take care of your warning.

    __block TestClass *obj = nil;
    obj = [[TestClass alloc] initMyObjectWithBlock:^{
        [obj doSomething];
    }];
    

    Regarding object, it does exit since you are not calling block inside your initMyObjectWithBlock initializer.

    Although above code works, but as Josh mentioned, there is a retain cycle. To get around retain cycle, you can do something like:

    TestClass *obj = nil;
    __block __weak TestClass *objWeak = nil;
    
    obj = [[TestClass alloc] initMyObjectWithBlock:^{
        TestClass *newObj = objWeak;
    
        [newObj doSomething];
    }];
    
    objWeak = obj;
    

    Where you are simply creating a dummy variable to pass in to your block.