NSNotificationCenter removeObserver:在dealloc中和线程安全

2019-08-04 04:29发布

我使用ARC和我打电话[[NSNotificationCenter defaultCenter] removeObserver:someObserver]; 在观察者dealloc

从NSNotificationCenter类参考

一定要调用这个方法(或removeObserver:名称:对象:) notificationObserver之前或在指定的addObserver任何对象:选择:名称:对象:被释放。

NSNotificationCenter不保留观察员。

Q1:是NSNotificationCenter线程安全的?

在情况下,观察者被释放(并从通知中心去除观察者)和另一个线程在同一时间后的通知。

我遇到随机崩溃,我怀疑是这种情况。

问题2:这种情况可能吗?

Q3:是否导致EXC_BAD_ACCESS

Q4:那么,是不是安全地调用[[NSNotificationCenter defaultCenter] removeObserver:someObserver]; 在观察者的dealloc

Q5:如果它是不是安全,我应该在哪里打电话removeObserver:

Answer 1:

我只是偶然到这个问题我自己:我有一个通知只是处于发送(这总是发生在主线程),而对象是在从后台线程正在释放过程中的过程。 我固定它通过简单地执行removeObserver在主线程和等待:

- (void)removeNotificationCenterObserver
{
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter removeObserver:self];
}

- (void)dealloc
{
    [self performSelectorOnMainThread:@selector(removeNotificationCenterObserver) withObject:self waitUntilDone:YES];
}

这也是在等待,直到当前运行的循环周期结束,并在下次运行循环周期的开始执行此消息。 这确保了仍在运行的所有功能将结束。



Answer 2:

是的, NSNotificationCenter不保留观察员,但它仍然有一个指向它在它的调度表。

Q1:引用苹果文档

定期通知中心中通知已经张贴在线程上传递通知。 分布式通知中心主线程上传递通知。 有时,你可能需要将通知在由你,而不是确定的通知中心的特定线程交付。 例如,如果在后台线程中运行的对象正在监听从用户接口通知,诸如窗口关闭,你想接收在后台线程,而不是主线程的通知。 在这种情况下,你必须捕捉的通知,因为它们在默认线程交付并重定向到适当的线程。

Q2,3:是的。

Q4,5:据我所知,除非你再次陷入循环引用是安全的。 我通常添加/删除中-viewWillAppear: / -viewWillDisappear:为UIViewControllers和-init / dealloc其他类。



Answer 3:

我想知道同样的事情,我找不到它记录。 这是我认为正在发生的事情。

removeObserver:是不是线程,你希望它是一路安全。

想想下面的情况。 最后参考观察者被释放,而在线程A线程A执行代码调用观察者dealloc方法。 同时,观察到的对象执行[NSNotificcationCenter postNotificationName:object:]从螺纹B.这导致不可避免的竞争条件。 也就是说,通知将在飞行 ,而你的目标是其内dealloc方法。

- (void)init {
    ...
    [[NSNotificcationCenter defaultCenter] addObserver:self
                                              selector:@selector(callback:)
                                                  name:@"whatever"
                                                object:nil];
    ...
}

- (void)dealloc {

    // If the observed object posts the notification on thread B while 
    // thread A is here, there's a race! At best, thread B will be
    // in callback: while thread A is here in dealloc. That's probably
    // not what you expect. The worst case is that thread B won't make
    // make it to callback: until after thread A completes the dealloc
    // and the memory has been freed. Likely crash!

    [[NSNotificationCenter defaultCenter] removeObserver:self];

    // If the observed object does the post when thread A is here,
    // you'll be fine since the observation has been removed.
}

这不是主线程对象,因为只观察其他主线程对象,定义一个问题,你不能进入我所描述的线程A和B的场景。

对于多线程的情况下,只有这样才能保证你会避免这些问题是确保观察者的引用计数击中0 之前,如果有人负责观察的生命周期的观测站(即你有任何形式的termclose方法)很容易。 如果没有,我不知道一个解决方案。



文章来源: NSNotificationCenter removeObserver: in dealloc and thread-safety