I know that calling [self methodName] from within a block will lead to a retain cycle.
That is not true in general. The block will retain self
, yes. But there will only be a "retain cycle" if self
somehow retains the block. In this case, it does.
but will super be retained
Yes, self
will be retained (super
is a call on self
with a different method lookup pathway).
I have tried with SEL & IMP and function pointers. Problem is that IMP and function pointers require as a parameter an instance, and this renders the hole point mute:
NSString * (*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[super methodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)]; NSString *reply = getFuncPtr(_weak_self,@selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
This simply calls the inherited method. Trying to use it with super simply gives an error. At this point I will go ahead and simply use super within the block, and try and profile to see if it leads to any retain cycle.
There are many wrong points here. First, as said above, super
is a call on self
(there is no such thing as a super
object), so it would be sufficient to get the IMP for the method in the superclass, and call it on self
.
BUT, [super methodForSelector:...
does not get the method in the superclass. It actually gets the method in this class. The super
in [super methodForSelector:...
affects which methodForSelector:
method is called. However, no class ever overrides methodForSelector:
, so there is actually no difference between [super methodForSelector:...
and [self methodForSelector:...
. As said above, super
calls the method on self
, so it still finds the method based on the class of the current object.
You can get the right IMP by using the class method +instanceMethodForSelector:
:
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[[self class] superclass] instanceMethodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)];
However, using the above will not work correctly if the current object is an instance of a subclass, because then [self class]
will be the subclass. So to make sure it does what we want, we need to hard-code the name of our current class, or the superclass:
NSString *(*getFuncPtr)(id,SEL,id,id) = (NSString * (*)(id,SEL,id,id))[[SyncArrayMT superclass] instanceMethodForSelector:@selector(sendObjectsPassingTest:withAuthBlock:)];
NSString *reply = getFuncPtr(_weak_self,@selector(sendObjectsPassingTest:withAuthBlock:),predicate,authBlock);
It is also possible to do it using objc_msgSendSuper
directly, but that function is not really that easy to use either. So I think you should stick with the IMP approach above.