簡體   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