0

我想实现类似于NSNotificationCenter's 的行为-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?即像这样:

__unsafe_unretained MyObject *blockSelf = self;
[controller addRefetchObserver:self handler:^{
    blockSelf.data = [blockSelf updateData];
}];
4

2 回答 2

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];
于 2012-11-21T22:18:30.753 回答
1

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

是的,他们对它的引用很弱。你也可以很容易地在你的类中保留对观察者的弱引用:如果你需要一个弱引用的集合,你可以制作一个非保留版本的 NSArray 或 NSSet 或 NSDictionary,使用 Core Foundation 函数来创建 CFArray / CFSet / CFDictionary(它们与 NS 等效项是免费桥接的,即与 NS 等效项相同),允许您明确指定保留/释放行为;所以没有强参考,你只是让它在保留和释放上什么都不做。

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

虽然 NSNotificationCenter 只有一个对“观察者”的引用,但您的系统有两个引用——一个作为传入的“观察者”,但您也有一个对块的引用,它很可能引用了“观察者”还。如果你想让它和 NSNotificationCenter 一样工作,你需要确保它们都是弱引用。我想你已经弄清楚了——使用我在第一段中描述的内容,你保持弱的直接“观察者”引用;该块对“观察者”的引用也必须是弱的。

另外,在块中引用 self 时,有没有办法绕过使用 __unsafe_unretained ?即像这样:

您所拥有的是从块中弱引用某些内容的正确方法。更具体地说,__weak如果您使用 ARC 并且仅针对 iOS 5+,则应该使用。如果您正在使用 ARC,则应该使用__unsafe_unretained(就像您拥有的那样)。__block如果您不使用 ARC,则应该使用。

于 2012-11-22T23:27:00.840 回答