In a class, I put all members read/write in a serial dispatchQueue to protect multi-thread access. But I got a fatal error of unowned reference to self
when I pass [unowned self]
to dispatchQueue's task in deinit.
In the following example, I can still read self
and refCount(self)
is still not 0 in deinit{}
before calling self.q.sync{...}
. Then fatal error raised immediately when passing [unowned self]
to queue's task
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
Is the class.deinit{}
a special scope where we should not pass self
to another thread or task?
I also try to pass using [weak self]
, and the self
is still a nil
. Don't know why its reference count reached zero at another task.
What is deinit
? It is when a reference type instance is being deallocated. Why is it being deallocated? Because its reference count reached 0. That is what reference count memory management is .
Don't know why its reference count reached zero at another task.
I don't know what you mean by "at another task". Its reference count is zero in deinit
by definition.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.