15

I am trying to call a method on super class inside a block. In order to avoid a retain-cycle I need a weak reference to super. How would I get a weak reference to super?

[self somethingWithCompletion:^(){
   [super doStuff];
}];

I tried the following but gives a compile error.

__weak MySuperClass *superReference = super;
aryaxt
  • 76,198
  • 92
  • 293
  • 442
  • 4
    "super" is a fiction. – Hot Licks Dec 13 '13 at 18:23
  • Is [super doStuff] different than [self doStuff]? – Farski Dec 13 '13 at 18:27
  • 1
    @farski Um... well... Is eating an apple different from eating an orange? –  Dec 13 '13 at 18:27
  • @farski yes they are different. self would go through the method in current class, and then it calls super (if specified), calling super would directly call super class without going through the logic in my inheriting class – aryaxt Dec 13 '13 at 18:31

2 Answers2

18

You could define a helper method

-(void) helperMethod
{
    [super doStuff];
    // ...
    [super doOtherStuff];
    // ...
}

and then do

__weak MyClass *weakSelf = self;
[self somethingWithCompletion:^(){
    MyClass *strongSelf = weakSelf;
   [strongSelf helperMethod];
}];

A direct solution using the runtime methods looks like this:

__weak MyClass *weakSelf = self;
[self somethingWithCompletion:^(){
    MyClass *strongSelf = weakSelf;
    if (strongSelf) {
        struct objc_super super_data = { strongSelf, [MyClass superclass] };
        objc_msgSendSuper(&super_data, @selector(doStuff));
    }
});

Disadvantages (in my opinion):

  • More (complicated) code.
  • According to the "Objective-C Runtime Programming Guide", you should never call the messaging functions directly in your code.
  • Depending on the return type of the method, you would have to use objc_msgSendSuper or objc_msgSendSuper_stret.
  • For methods taking arguments, you have to cast objc_msgSendSuper to the proper function type (thanks to @newacct).
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • I know I could do a helper, but there are a couple of methods in super i call, I don't want to do helper methods for all of them. I like the second solution – aryaxt Dec 13 '13 at 18:40
  • @aryaxt: You can move all the super calls to the helper method, so you have to call only *one* helper method. I have updated the answer to make that more clear. – Martin R Dec 13 '13 at 18:47
  • @MartinR I don't understand why he needs this. He could just do `[super doStuff];` from within the block. –  Dec 13 '13 at 18:49
  • @H2CO3 Wouldn't that cause a retain cycle since the current class is retaining my block, and the block would retain the strong reference? – aryaxt Dec 13 '13 at 18:53
  • @H2CO3: `[super doStuff];` would send the message to `self` (starting the method resolution at the superclass, of course). - And it does not compile in my test method. – Martin R Dec 13 '13 at 18:54
  • @MartinR Well, it compiles for me, but that's marginal. It sounds logical that it retains `self`, though - I didn't think of that. (Guess who hates ARC!) –  Dec 13 '13 at 18:55
  • @H2CO3: I know who! The same person that hates Xcode and regular expressions :-) – Martin R Dec 13 '13 at 18:57
  • @MartinR Aw, how did you know that? :D (Forgot about C++, though... :P) –  Dec 13 '13 at 18:57
  • @H2CO3: I am on your side when it comes to C++, but I love ARC. This is going to be off-topic now ... – Martin R Dec 13 '13 at 18:59
  • Your `super_data` is wrong. `[strongSelf superclass]` may not be the superclass of the class the code is in. – newacct Dec 16 '13 at 23:58
  • @newacct: You are right! - I hope that it is fixed now (it seems to work correctly in my test app). - Once again, thank you for your feedback. – Martin R Dec 17 '13 at 06:26
  • To use `objc_msgSendSuper`, you should cast it to the proper function pointer type, similar to what you do with `objc_msgSend`, except with `objc_super *` instead of `id`. – newacct Dec 17 '13 at 07:51
  • @newacct: You mean like here http://stackoverflow.com/a/2573949/1187415 ? That makes sense. - Actually I added the messaging part only for the sake of completeness, perhaps I should have limited the answer to the first part :-) I have now rewritten the code for the special case used in the question, where the method takes no arguments. – Martin R Dec 17 '13 at 08:32
3

Your problem can be solved by using an Objective-C runtime function objc_msgSendSuper to send a "supermessage" to weak self.

It's not possible to "get a weak reference to super", as super is a language construct rather than a separate object. Take a look at this explanation of super:What exactly is super in Objective-C?.

Community
  • 1
  • 1
ilya n.
  • 18,398
  • 15
  • 71
  • 89
  • This should be a comment. –  Dec 13 '13 at 18:34
  • @H2CO3, I clarified which part answers question as asked and which one helps to get the job done. Better now? – ilya n. Dec 13 '13 at 18:40
  • that doesn't change the fact that this "answer" is a link-only one. –  Dec 13 '13 at 18:41
  • I'm not following you. The main answer part is *using an Objective-C runtime function objc_msgSendSuper to send a "supermessage" to weak self*. It has no links. – ilya n. Dec 13 '13 at 18:42