user3564870 user3564870 - 3 months ago 25
Objective-C Question

Why is this completion block correctly being called?

Why does this completion block correctly get called?

CompletionBlock comp = ^(BOOL enabled) {
//enabled is being correctly set
NSLog(@"result: %i", enabled);

@autoreleasepool {
Monitor *monitor = [[Monitor alloc]initWithCompletionBlock:comp];
monitor = nil;

The monitor will start a NSTimer to call the completion block 10 seconds after monitor is instantiated.

The monitor does have a reference to comp internally (by way of
@property (nonatomic) CompletionBlock compblock;
) but the ingredients for a circular reference don't appear to be there, as nothing is referencing monitor.

Is this normal behavior? And is it behavior I can count on? It really doesn't make sense to me.


Presumably the Monitor instance is the target here. NSTimer retains its target in order to avoid a crash caused by messaging a deallocated object when it fires.* The current run loop retains the timer when it's scheduled.

This is normal behavior, and you can rely on it:

The object to which to send the message [...] The timer maintains a strong reference to target...

In fact, you must take it into consideration so that you don't create a retain cycle between the timer and its target.

*NSTimer predates auto-nilling weak references by a long time.