Iphone 如何存储对对象和块的引用

Iphone 如何存储对对象和块的引用,iphone,objective-c,memory-management,objective-c-blocks,Iphone,Objective C,Memory Management,Objective C Blocks,我想实现类似于NSNotificationCenter的-addObserverForName:object:queue:usingBlock:的行为。使用一种叫做 - (void)addRefetchObserver:(id)observer handler:(FJRefetchHandler)handler; 应存储块以供以后调用(FJRefetchHandler的定义如下:typedef void(^FJRefetchHandler)(void))

我想实现类似于
NSNotificationCenter
-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
以某种方式存储观察者而不保留它-否则我将无法在
-dealoc
中调用
[center removeObserver:self]
,因为
-dealoc
永远不会被调用

另外,在块中引用
self
时,是否有方法使用
\uu unsafe\u unrepaired
绕过?例如:

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

在块内调用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];
显然,NSNotificationCenter以某种方式存储了观测者,而没有 保留它-否则我将无法呼叫[中心] removeObserver:self]in-dealloc,因为-dealloc永远不会得到 打电话来

是的,它们保留了一个弱引用。您也可以很容易地将弱引用引用到类中的观察器中:如果需要有弱引用的集合,可以使用NaskFoundation函数创建非数组的NStase/NSSET或NS字典,以创建CFARTA/ CFSet / CFDictionary。(它们是免费桥接的,即与NS等价物相同),这允许您明确指定保留/释放行为;因此,为了没有强引用,您只需让它在保留和释放时不做任何操作即可

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

NSNotificationCenter只有一个对“观察者”的引用,而您的系统有两个引用——一个作为传入的“观察者”,但您也有一个对块的引用,这很可能是对“观察者”的引用另外,如果你想让它以与NSNotificationCenter相同的方式工作,你需要确保这两个都是弱引用。我想你已经解决了这个问题——你使用我在第一段中描述的方法保持弱引用的直接“观察者”引用;块对“观察者”的引用也必须是弱引用

还有,有没有办法在不安全的情况下使用未恢复的 在块中引用self?例如:

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

您所拥有的是从块中弱引用某些内容的正确方法。更具体地说,如果您使用的是ARC且仅针对iOS 5+,则应使用
\uuuuu-weak
。您应该使用
\uu-safe\u-unrepaired
(就像您所拥有的那样)如果您使用的是ARC,则不使用ARC,则应使用
\uu block

我从未想过检查控制器是否仍然存在,谢谢。还有一件事,块内的弱对象可以随时进行垃圾收集。为此,在块内对变量进行强引用,使其保持until块的生存期。由于控制器现在在块内的作用域有限,因此可以避免保留周期。您可以避免“当块仍在进行时,控制器可能会被释放”如果确保在保留/释放控制器的同一线程上执行块,则会出现问题。是的,确实如此。如果您正在使用NSOperationQueue或gcd并在另一个线程中执行某些操作,则控制器可能会同时被释放。但是,即使我不在后台队列中,这是否重要。测试对象是否存在并向其发送消息是一件好事,不是吗?谢谢你的回答。我将使用CF来存储我的对象。你是对的,我存储“observer”只是为了有一种稍后删除它的方法。我只是认为它很方便,因为用户不必担心创建一个唯一的对象作为观察者传递,只需传递
self
。存储块需要用户尊重它,我认为这很不方便-我宁愿将块声明到位。但我会考虑更多。