【问题标题】:Is dealloc guaranteed to be called on the same thread that created the object?是否保证在创建对象的同一线程上调用 dealloc?
【发布时间】:2015-09-26 17:26:07
【问题描述】:

dealloc 是否保证在创建NSObject 实例的同一线程上被调用?例如,如果我在主线程上调用[[MyFluffyBunny alloc] init],是否保证dealloc也能在主线程上被调用,或者一旦MyFluffyBunny不再保留,是否可以在任何线程上调用它?

我在我的应用程序中看到零星的崩溃,这表明它无法保证,但我无法找到任何确认它的文档。

【问题讨论】:

  • 出于好奇,这有什么关系?
  • 我必须调用需要在主线程(第 3 方 API)上执行的 dealloc 中的某些代码。在添加线程检查和 dispatch_sync 调用之前,我想确定上述内容
  • 何必担心呢?使用dspatch_sync 并确保它无论如何都能正常工作。它已经在主线程上,它基本上是一个空操作。
  • dispatch_sync 的文档说,如果在传递的同一队列上使用它会导致死锁。我并不太担心,我只是想先确定一下。
  • 或者直接使用dispatch_async...

标签: objective-c


【解决方案1】:

该对象在释放最后一个强引用的线程上被释放。也就是说,无论哪个线程最后一次调用-release。实际上是在期间 -release 调用对象被释放。

NSObject 协议中的documentation for the -release method 表示:

减少接收者的引用计数。 …当引用计数达到0时,接收者会收到dealloc消息。

高级内存管理编程指南:实用内存管理文章在reasons to not use -dealloc to manage scarce resources 中包含此内容:

  1. 在错误的线程上执行清理逻辑。

    如果一个对象在意外的时间被自动释放,它将在它碰巧所在的任何线程的自动释放池块中被释放。这对于只能从一个线程中访问的资源来说很容易致命。

【讨论】:

  • 只是为了确认 - 我假设您的意思是在调用 release 期间该对象已释放?如果在调用release 期间没有释放该对象,我会非常担心。 ;-)
【解决方案2】:

没有这样的保证,事实上,它在使用 KVO(以及 OS X 上的绑定)时会产生一些微妙的错误。

您可以通过创建一个在initdealloc 期间记录[NSThread currentThread] 的对象,然后运行以下代码,相当容易地看到它的实际效果:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    Testing *testing = [[Testing alloc] init];
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
        NSLog(@"Use testing in background: %@", testing);
    });
    testing = nil;
    return YES;
}

【讨论】:

    【解决方案3】:

    我不知道文档中有一行对此有任何说明,但这里有一些逻辑要点:

    • 如果您在某处找不到保证,就假设它不存在。 (听起来您已经意识到这一点,并且希望其他人可以为您指出可以为您提供所需答案的东西)

    • 这个要求是不可能的,因为你可以在一个线程上构造一些东西,然后结束那个线程,然后让最后一个引用在其他线程的其他地方超出范围。此时无法在旧线程上使用dealloc,因为它不再存在。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      • 2011-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多