deinit中的调用dispatchQueue.sync导致自身的未拥有引用

问题描述 投票:0回答:1

在一个类中,我将所有成员读/写到串行dispatchQueue中,以保护多线程访问。但是,当我在deinit中将self传递给dispatchQueue的任务时,出现了一个致命错误,该错误涉及对[unowned self]的无主引用。

在下面的示例中,在调用self之前,我仍然可以在refCount(self)中读取deinit{},并且self.q.sync{...}仍不为0。然后在将[unowned self]传递到队列的任务

时立即引发致命错误

示例

class Host {
  let text = "Hello"
  let q = DispatchQueue(label: "workingloop")
  deinit {
    // `self` is ok to be read
    print("begin count: \(CFGetRetainCount(self)), ptr: \(Unmanaged.passUnretained(self).toOpaque())")

    self.q.sync { [unowned self] in // <- callstack stop here
      print(self.text)
    }

    // not reach
    print("end count: \(CFGetRetainCount(self)), ptr: \(Unmanaged.passUnretained(self).toOpaque())")
  }
}

func foo() {
  let host = Host() 
  // <- trigger Host.deinit()
}

输出

begin count: 2, ptr: 0x000000010871fb00
Fatal error: Attempted to read an unowned reference but object 0x10871fb00 was already deallocated 2020-01-13 10:31:11.758734+0800 xctest[29473:2710298] Fatal error: Attempted to read an unowned reference but object 0x10871fb00 was already deallocated

class.deinit{}是否有特殊的作用域,我们不应该将self传递给另一个线程或任务?

我也尝试使用[weak self]通过,并且self仍然是nil。不知道为什么它的引用计数在另一项任务中达到零。

swift
1个回答
1
投票

什么是 deinit?这是在释放引用类型实例时。 为什么被释放?因为它的引用计数达到0。这就是引用计数内存管理is

不知道为什么在另一项任务中其引用计数达到零。

我不知道您的意思是“在另一项任务上”。根据定义,它的参考计数在deinit中为零。

© www.soinside.com 2019 - 2024. All rights reserved.