Swift 在调用 VC deinit 后闭包仍在内存中
Swift closure is still in memory after VC deinit is called
我有一个蓝牙 class,当 char 值更新为视图控制器中的闭包(以及单例 class 中的相同闭包)时,它会通过。当调用 VC deinit 时,更新 char 值时仍在执行 VC 中的闭包。我在 VC 中使用 [weak self] 作为闭包。我希望能够在取消初始化视图时阻止调用此 VC 闭包。但是我也不明白为什么在 VC 出现后单例中的另一个回调没有被执行!
下面包含 VC
中闭包的语法
bluetooth.updatedCharacteristicsValue { [weak self] char in
[weak self]
并不意味着可以丢弃闭包,它只是防止闭包保留 VC(因此防止 VC 被取消)。
只需以以下方式开始关闭:
guard let self = self else { return }
...如果 VC 不再存在则提前退出。
至于为什么 VC 提供的闭包被调用而单例中的闭包没有被调用,听起来你的蓝牙 class 不理解多重 'users'。谁最后注册回调,谁就被调用。
一种使用方便的自注销令牌处理您自己的观察者注册的方法:
class ObserverToken {
let id = UUID()
private let onDeinit: (UUID) -> ()
init(onDeinit: @escaping (UUID) -> ()) {
self.onDeinit = onDeinit
}
deinit {
onDeinit(id)
}
}
class BluetoothThing {
// Associate observers with the .id of the corresponding token
private var observers = [UUID: (Int) -> ()]()
func addObserver(using closure: @escaping (Int) -> ()) -> ObserverToken {
// Create a token which sets the corresponding observer to nil
// when it is deinit'd
let token = ObserverToken { [weak self] in self?.observers[[=11=]] = nil }
observers[token.id] = closure
return token
}
func tellObserversThatSomethingHappened(newValue: Int) {
// However many observers we currently have, tell them all
observers.values.forEach { [=11=](newValue) }
}
deinit {
print("")
}
}
// I've only made this var optional so that it can later be set to nil
// to prove there's no retain cycle with the tokens
var bluetooth: BluetoothThing? = BluetoothThing()
// For as long as this token exists, updates will cause this closure
// to be called. As soon as this token is set to nil, it's deinit
// will automatically deregister the closure
var observerA: ObserverToken? = bluetooth?.addObserver { newValue in
print("Observer A saw: \(newValue)")
}
// Results in:
// Observer A saw: 42
bluetooth?.tellObserversThatSomethingHappened(newValue: 42)
// A second observer
var observerB: ObserverToken? = bluetooth?.addObserver { newValue in
print("Observer B saw: \(newValue)")
}
// Results in:
// Observer A saw: 123
// Observer B saw: 123
bluetooth?.tellObserversThatSomethingHappened(newValue: 123)
// The first observer goes away.
observerA = nil
// Results in:
// Observer B saw: 99
bluetooth?.tellObserversThatSomethingHappened(newValue: 99)
// There is still one 'live' token. If it is retaining the
// Bluetooth object then this assignment won't allow the
// Bluetooth to deinit (no wavey hand)
bluetooth = nil
因此,如果您的 VC 将它的令牌存储为 属性,当 VC 消失时,令牌消失并且闭包被注销。
我有一个蓝牙 class,当 char 值更新为视图控制器中的闭包(以及单例 class 中的相同闭包)时,它会通过。当调用 VC deinit 时,更新 char 值时仍在执行 VC 中的闭包。我在 VC 中使用 [weak self] 作为闭包。我希望能够在取消初始化视图时阻止调用此 VC 闭包。但是我也不明白为什么在 VC 出现后单例中的另一个回调没有被执行!
下面包含 VC
中闭包的语法bluetooth.updatedCharacteristicsValue { [weak self] char in
[weak self]
并不意味着可以丢弃闭包,它只是防止闭包保留 VC(因此防止 VC 被取消)。
只需以以下方式开始关闭:
guard let self = self else { return }
...如果 VC 不再存在则提前退出。
至于为什么 VC 提供的闭包被调用而单例中的闭包没有被调用,听起来你的蓝牙 class 不理解多重 'users'。谁最后注册回调,谁就被调用。
一种使用方便的自注销令牌处理您自己的观察者注册的方法:
class ObserverToken {
let id = UUID()
private let onDeinit: (UUID) -> ()
init(onDeinit: @escaping (UUID) -> ()) {
self.onDeinit = onDeinit
}
deinit {
onDeinit(id)
}
}
class BluetoothThing {
// Associate observers with the .id of the corresponding token
private var observers = [UUID: (Int) -> ()]()
func addObserver(using closure: @escaping (Int) -> ()) -> ObserverToken {
// Create a token which sets the corresponding observer to nil
// when it is deinit'd
let token = ObserverToken { [weak self] in self?.observers[[=11=]] = nil }
observers[token.id] = closure
return token
}
func tellObserversThatSomethingHappened(newValue: Int) {
// However many observers we currently have, tell them all
observers.values.forEach { [=11=](newValue) }
}
deinit {
print("")
}
}
// I've only made this var optional so that it can later be set to nil
// to prove there's no retain cycle with the tokens
var bluetooth: BluetoothThing? = BluetoothThing()
// For as long as this token exists, updates will cause this closure
// to be called. As soon as this token is set to nil, it's deinit
// will automatically deregister the closure
var observerA: ObserverToken? = bluetooth?.addObserver { newValue in
print("Observer A saw: \(newValue)")
}
// Results in:
// Observer A saw: 42
bluetooth?.tellObserversThatSomethingHappened(newValue: 42)
// A second observer
var observerB: ObserverToken? = bluetooth?.addObserver { newValue in
print("Observer B saw: \(newValue)")
}
// Results in:
// Observer A saw: 123
// Observer B saw: 123
bluetooth?.tellObserversThatSomethingHappened(newValue: 123)
// The first observer goes away.
observerA = nil
// Results in:
// Observer B saw: 99
bluetooth?.tellObserversThatSomethingHappened(newValue: 99)
// There is still one 'live' token. If it is retaining the
// Bluetooth object then this assignment won't allow the
// Bluetooth to deinit (no wavey hand)
bluetooth = nil
因此,如果您的 VC 将它的令牌存储为 属性,当 VC 消失时,令牌消失并且闭包被注销。