从块中调用[self methodName]?

73

我刚遇到了blocks,我觉得它们正是我想要的,除了一个问题:是否可以在block内调用一个方法[self methodName]?

这就是我想做的:

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

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

    [fader setFunction:tempFunction];
}

我已经搜索了几天,找不到任何证据表明这是可能的。

这个有可能吗,还是我试图用blocks做一些它们不应该做的事情?

我使用blocks的原因是我创建了一个Fader类,并且我想存储一个block,在淡出完成时执行它。

谢谢

编辑: 好的,我加入了建议,但仍然收到了EXC_BAD_ACCESS错误...

-(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];
}

也许我不允许把函数给 fader ...?


接受的回答已经过时。请接受我的答案,以免用错误的语法混淆人们。 - skywinder
6个回答

142

是的,你可以做到这一点。

不过请注意,该块将保留self。如果最终将此块存储在ivar中,你可能会很容易地创建一个保留循环,这意味着两者都永远不会被释放。

为了解决这个问题,可以这样做:

- (void) someMethodWithAParameter:(id)aParameter {

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

  [self doSomethingWithBlock:tempFunction];

}

__block关键字表示(除其他外)所引用的对象将不会被保留。


4
请确保您的按钮对象上的 function 属性是 copy 属性,而不是 retain 属性。 - Dave DeLong
37
请注意,这样做会引入self成为悬垂指针的可能性,如果在selfdealloc后调用该块,则会导致RTE。在ARC之前,您可以使用Mike Ash的MAZeroingWeakRef库来创建对self的安全引用。在ARC之后,在iOS 5.0及以上版本中,您可以使用额外的关键字__weak将对自身的引用变为零弱引用。 - prairiedogg
2
__block 关键字意味着(除其他外)所引用的对象将不会被保留。这在 ARC 中有所改变吗?"推断规则同样适用于 __block 变量,这是从非 ARC 到 ARC 的语义转变,其中 __block 变量在捕获期间不会隐式保留。" - Sergey Kalinichenko
1
@MobileMon 是的,因为 self.someProperty = ...[self setSomeProperty:...] 是同一件事。你仍然在 block 中捕获了 self,因此仍然存在强引用循环。 - Dave DeLong
1
@JayQ。这取决于情况。如果您看到它被释放,那么就没问题了。在我的答案中,会出现保留循环,因为“self”会强烈引用该块,但该块也会强烈引用“self”。这是一个保留循环,这意味着块和“self”都不会被释放(因为它们都希望对方保持活动状态)。如果您看到“self”被释放,则没有保留循环。 - Dave DeLong
显示剩余5条评论

27

被接受的答案已经过时。在那种情况下使用__block可能会导致错误!

为了避免这个问题,最好的做法是捕获一个弱引用self,像这样:

- (void)configureBlock {
    XYZBlockKeeper * __weak weakSelf = self;
    self.block = ^{
        [weakSelf doSomething];   // capture the weak reference
                                  // to avoid the reference cycle
    }
}
请查看苹果文档 - 在捕获self时避免强引用循环 以获取更多详细信息。

2
在那种情况下使用__block可能会导致错误!请告知是哪种类型的错误。 - Cristik
1
如果在“doSomething”函数内部有类似于“[self doStuff]”这样的东西,会导致保留循环吗?还是不会? - superpuccio
@Cristik 循环引用。由于 __block 使你在块内部拥有访问权,但并不使其弱化。 - skywinder
@superpuccio 不是方法本身。只有我们存储在块内的对象。 - skywinder

3
__block CURRENTViewController *blocksafeSelf = self;

[homeHelper setRestAsCheckIn:strRestId :^(NSObject *temp) {
    [blocksafeSelf YOURMETHOD:params];
}];

这被自动标记为“低质量”。您能否添加一些文本来解释代码以及它如何回答OP的问题? - gung - Reinstate Monica

1
能否在块内调用一个方法 [self methodName]?
可以的,如果你的 tempFunction 是一个实例方法,你就可以这样做。被调用的方法应该是可访问的,这是唯一的限制。

tempFunction 不是一个实例方法 - 它是一个块。 - user557219
我认为Mahesh的意思是:“如果您的tempFunction在实例方法内部...” - bbum
@bbum 确实如此;那样更有意义。 - user557219

0

考虑一下这个(我认为是最佳实践)

@implementaion ViewController

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

@end

此外,您可以定义包装器宏。
#define MakeWeakSelf __weak typeof(self) wself = self
#define MakeStrongSelf __strong typeof(wself) self = wself

-1

我想知道你是否[fader setFunction:tempFunction];后是同步还是异步的。 块会被推入堆栈中。在MRR中,如果您不保留它,它将弹出。

-(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.

在块内调用“self”会保留它。在块内使用之前,请使用__weak或__block创建对self的弱引用。 - Sathe_Nagaraja
现在您可以使用弱引用或未拥有的引用。 - Sathe_Nagaraja

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接