如何存储对象和块的引用

时间:2012-11-21 22:12:02

标签: iphone objective-c memory-management objective-c-blocks

我想实现类似于NSNotificationCenter的{​​{1}}的行为。使用类似

的方法
-addObserverForName:object:queue:usingBlock:

应存储一个块以供以后调用(- (void)addRefetchObserver:(id)observer handler:(FJRefetchHandler)handler; 定义如下:FJRefetchHandler

因为我想稍后删除该块,我还存储typedef void(^FJRefetchHandler)(void),并声明以下方法:

observer

用法如下:

- (void)removeRefetchObserver:(id)observer;

我的问题是:我应该如何实施// some place in code [controller addRefetchObserver:self handler:^{ // refetch some stuff, i.e. self.data = [self updateData]; }]; // some other place in code: [controller removeRefetchObserver:self]; 以便我不会创建任何保留周期?我应该如何存储观察者和处理者?

显然,-addRefetchObserver:handler:以某种方式存储观察者而不保留它 - 否则我将无法在NSNotificationCenter中调用[center removeObserver:self]因为-dealloc永远不会被调用。

此外,在引用块中的-dealloc时,是否可以使用__unsafe_unretained?即是这样:

self

2 个答案:

答案 0 :(得分:1)

在块中调用self的更好方法是将self的引用复制到相同的弱变量中并在块内使用它;

MyController __weak *__weakController = controller;
[__weakController addRefetchObserver:self handler:^{
    // refetch some stuff, i.e.
    __weakController.data = [__weakController updateData];
}];    
// some other place in code:
[controller removeRefetchObserver:self];

但是,有时您可能正在处理长时间持续操作,同时控制器可能会在块仍在进行时被释放。由于块被放置在堆栈上并继续执行,更好的想法是在调用控制器上的某些方法之前检查控制器是否仍然存在;

 MyController __weak *__weakController = controller;
    [__weakController addRefetchObserver:self handler:^{
         // some long on going tasks ...
        MyController __strong *strongController = __weakController;
        if(strongController)
          strongController.data = [strongController updateData];
    }];    
    // some other place in code:
    [controller removeRefetchObserver:self];

答案 1 :(得分:1)

  

显然,NSNotificationCenter以某种方式存储了观察者   保留它 - 否则我将无法打电话给[中心   remove -bserver:self] in -dealloc因为-dealloc永远不会得到   调用。

是的,他们对它的参考不足。您也可以轻松地在类中保留对观察者的弱引用:如果您需要一组弱引用,则可以使用Core Foundation函数创建NSArray或NSSet或NSDictionary的非保留版本来创建CFArray / CFSet / CFDictionary(它们是免费的桥接,即与NS等价物相同),允许您明确指定保留/释放行为;所以为了没有强有力的参考,你只需要在保留和释放方面做任何事情。

你正在存储观察者有点奇怪。使用NSNotificationCenter,它们存储观察者,因为他们需要观察者和选择器来进行调用。使用你的块,块已经足够进行调用,并且块封装了使用观察者的所有逻辑,因此单独存储“观察者”似乎很奇怪。看起来你拥有它的唯一原因就是有办法将其删除。就此而言,它可以是任何对象,只要您传递相同的对象即可添加。

虽然NSNotificationCenter只有一个对“观察者”的引用,但你的系统有两个引用 - 一个作为传入的“观察者”,但你也有一个对该块的引用,它很可能引用了“观察者”也。如果您希望它的工作方式与NSNotificationCenter相同,则需要确保这些都是弱引用。我想你已经想到了这一点 - 直接的“观察者”参考你使用我在第一段描述的东西保持弱势;该块对“观察者”的引用也必须是弱的。

  

此外,有没有办法在__unsafe_unretained时使用   在块中引用self?即是这样:

你所拥有的是从块中弱引用某些东西的正确方法。更具体地说,如果您使用ARC并且仅定位到iOS 5+,则应使用__weak。如果您使用ARC,则应使用__unsafe_unretained(与您一样)。如果您不使用ARC,则应使用__block