There are many situations where a class may want to support a callback selector, to notify another class of some event. Normally, it would be implemented like:
@interface SomeClass
@property (nonatomic, weak) callbackTarget;
@property (nonatomic, assign) callbackSelector;
@endThis would be the most convenient form from the caller's perspective because it can freely set any selector it wants for the callback. However, when using ARC, the implementation of SomeClass would obviously do something like this:
if(_callbackTarget && _callbackSelector)
[_callbackTarget performSelector: _callbackSelector]However, this produces the warning "PerformSelector may cause a leak because its selector is unknown". With ARC, the warning is technically speaking correct, because in principle the selector may decide to return an object, for whatever reason, which may then be leaked.
performSelector is no good with ARC. But what is the proper way to do this with ARC?
Apple seems to be promoting blocks for everything that would normally use callback selectors, and using a block is a common response to this question on the internets. However, if I understand correctly, this can easily cause an inadvertent recursive reference, and the objects may never be freed. In other words, if the class were like:
@interface SomeClass
@property (strong) void(^callbackBlock)();
@endand then the calling code would be something like:
@interface CallingClass
{
SomeClass someClass;
}
@end
@implementation CallingClass
- (void) foo
{
someClass = [SomeClass new];
someClass.callbackBlock = ^ { [self bar]; }
}
- (void) bar { ... }
@endit's my understanding that there's an inadvertent recursive reference there, which will cause instances of CallingClass (and its SomeClass member) to never be freed. (CallingClass has a strong reference to an object of type SomeClass, which has a strong reference to the block, which has a strong reference to the same CallingClass object, thus forming a strong reference loop.)
If this is not the proper way of doing it, then what is?