繁体   English   中英

调用 VC deinit 后,Swift 闭包仍在内存中

[英]Swift closure is still in memory after VC deinit is called

我有一个蓝牙类,当一个 char 值更新为视图控制器中的闭包(以及单例类中的相同闭包)时,它会通过。 当调用 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 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[$0] = nil }
        observers[token.id] = closure
        return token
    }

    func tellObserversThatSomethingHappened(newValue: Int) {
        // However many observers we currently have, tell them all
        observers.values.forEach { $0(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 消失时,令牌消失并且闭包将被取消注册。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM