73

I've just run into blocks and I think they are just what I'm looking for, except for one thing: is it possible to call a method [self methodName] from within a block?

This is what I'm trying to do:

-(void)someFunction{
    Fader* fader = [[Fader alloc]init];

    void (^tempFunction)(void) = ^ {
        [self changeWindow:game]; 
        //changeWindow function is located in superclass
    };

    [fader setFunction:tempFunction];
}

I've been searching for a couple of days and I can't find any evidence that this is possible.

Is this at all possible, or am I trying to use blocks for something they aren't meant for?

The reason I'm using blocks is that I've created a Fader class, and I want to store a block for it to execute when it finishes fading out.

Thank you

EDIT: Okay, I added in the suggestion, but I'm still getting an EXC_BAD_ACCESS error...

-(void)someFunction{
    Fader* fader = [[Fader alloc]init];

    __block MyScreen* me = self;

    void (^tempFunction)(void) = ^ {
        [me changeWindow:game]; 
        //changeWindow function is located in superclass
    };

    [fader setFunction:tempFunction];
    [fader release];
}

Maybe I'm not allowed to give fader the function...?

dandan78
  • 13,328
  • 13
  • 64
  • 78
Marty
  • 1,077
  • 1
  • 10
  • 14
  • The accepted answer is **outdated**. Please, accept my [answer](http://stackoverflow.com/a/27736864/1698467) to not confuse people with wrong syntax. – skywinder Mar 27 '15 at 16:39

6 Answers6

142

Yes, you can do this.

Note, however, that the block will retain self. If you end up storing this block in an ivar, you could easily create a retain cycle, which means neither would ever get deallocated.

To get around this, you can do:

- (void) someMethodWithAParameter:(id)aParameter {

  __block MySelfType *blocksafeSelf = self;
  void (^tempFunction)(void) = ^ {
      [blocksafeSelf changeWindow:game];
  };

  [self doSomethingWithBlock:tempFunction];

}

The __block keyword means (among other things) that the referenced object will not be retained.

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • You should add the surrounding method declaration; I think that is what is confusing OP. – bbum Feb 17 '11 at 00:33
  • Okay, so I've done that, but I'm still getting an EXC_BAD_ACCESS error. Could it be that instead of the last line of code you have, I'm sending the function somewhere else? [button setFunction:tempFunction]; – Marty Feb 17 '11 at 04:11
  • 4
    @Marty make sure the `function` property on your button object is a `copy` property, and not a `retain` property. – Dave DeLong Feb 17 '11 at 07:24
  • 37
    Note that by doing this you do introduce the possibility of `self` becoming a dangling pointer and causing an RTE if the block is called after `self` has been `dealloc`d. Before ARC you could use Mike Ash's MAZeroingWeakRef library to create a safe reference to `self` within the block. After ARC, on iOS 5.0 and up, you can use the extra keyword `__weak` to make your reference to self a zeroing weak reference. – prairiedogg Dec 01 '11 at 14:20
  • 2
    "The __block keyword means (among other things) that the referenced object will not be retained." Has this change with the ARC? ["The inference rules apply equally to __block variables, **which is a shift in semantics from non-ARC, where __block variables did not implicitly retain during capture.**"](http://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-ownership-inference) – Sergey Kalinichenko Dec 14 '13 at 11:12
  • @DaveDeLong does the same hold true for properties? Like if I do "self.someProperty = 88;" will this also create a retain cycle? – MobileMon Mar 27 '14 at 15:19
  • 1
    @MobileMon Yes, because `self.someProperty = ...` is the same thing as `[self setSomeProperty:...]`. You are still capturing `self` in the block, thus you still have a strong reference cycle. – Dave DeLong Mar 27 '14 at 16:15
  • @Prairiedogg nice comment. I think this point should be changed in original answer, too :) – hqt Aug 14 '14 at 17:44
  • The answer explicitly says that a retain cycle may occur if the block is stored in an ivar. What if it's not? Will it still cause retain cycle? When I run a profiler, it looks like "self" is being deallocated just fine. – Jay Q. Aug 27 '14 at 23:19
  • 1
    @JayQ. it depends. If you're seeing it get deallocated then you're OK. In my answer, there'd be a retain cycle because "self" would strongly reference the block, but the block would strongly reference self. That's a retain cycle, and it would mean that neither the block nor "self" would ever get deallocated (because they'd both want each other to stay alive). If you're seeing "self" be deallocated, then you don't have a retain cycle. – Dave DeLong Aug 27 '14 at 23:21
27

The accepted answer is outdated. Using __block in that case can cause errors!

To avoid this problem, it’s best practice to capture a weak reference to self, like this:

- (void)configureBlock {
    XYZBlockKeeper * __weak weakSelf = self;
    self.block = ^{
        [weakSelf doSomething];   // capture the weak reference
                                  // to avoid the reference cycle
    }
}

Please, look at Apple Documentation - Avoid Strong Reference Cycles when Capturing self for more details.

skywinder
  • 21,291
  • 15
  • 93
  • 123
3
__block CURRENTViewController *blocksafeSelf = self;

[homeHelper setRestAsCheckIn:strRestId :^(NSObject *temp) {
    [blocksafeSelf YOURMETHOD:params];
}];
chiwangc
  • 3,566
  • 16
  • 26
  • 32
Ketan Patel
  • 550
  • 4
  • 11
1

Is it possible to call a method [self methodName] from within a block?

Yes, why not. If your tempFunction is an instance method, you can do it. The called method should be accessible is the only restriction.

Pang
  • 9,564
  • 146
  • 81
  • 122
Mahesh
  • 34,573
  • 20
  • 89
  • 115
0

Consider this (which I think is the best practice)

@implementaion ViewController

- (void) viewDidLoad {
  __weak typeof(self) wself = self;
  [xxx doSomethingUsingBlock: ^{
    __strong typeof(wself) self = wself;
    [self anotherMessage];
  }];
}

@end

Moreover, You can define wrapper macros.

#define MakeWeakSelf __weak typeof(self) wself = self
#define MakeStrongSelf __strong typeof(wself) self = wself
karlbsm
  • 347
  • 4
  • 9
-1

I wonder whether you [fader setFunction:tempFunction]; then is synchronous or asynchronous. blocks push onto stack.so in MRR,if you don't retain it,it will pop off.

-(void)someFunction{
    Fader* fader = [[Fader alloc]init];

    void (^tempFunction)(void) = ^ {
        [self changeWindow:game]; 
        //changeWindow function is located in superclass
    };

    [fader setFunction:tempFunction];
    //if the tempFunction execute there will be right.
}//there the tempFunction pop off
 //....some thing go on
 //execute the tempFunction will go wrong.