Weird Swift 4 ошибка на основе замыкания KVO на устройствах iOS 10 - PullRequest
0 голосов
/ 17 февраля 2019

Когда я использую следующий способ KVO на основе замыкания Swift 4, я получаю сбой на устройствах iOS 10

class A: NSObject {
    @objc dynamic var value: Int = 0

    var observation: NSKeyValueObservation?

    override init() {
        super.init()

        // Crash
        self.observation = self.observe(\A.value, options: [.new], changeHandler: { (_, change) in

        })
    }
}

var a: A? = A()
a = nil

Информация о сбое:

*** Из-за завершения приложениячтобы исключить исключение NSInternalInconsistencyException, причина: «экземпляр 0x класса A был освобожден, в то время как наблюдатели значения ключа все еще были зарегистрированы в нем.Информация о текущем наблюдении: (Контекст: 0x, Свойство: 0x>

Я гуглил и получил ошибку Swift: https://bugs.swift.org/browse/SR-5816,, и обходной путь будет добавлять следующие строки внутри deinit

deinit {
    if #available(iOS 11.0, *) {

    } else {
        if let observation = self.observation {
            self.removeObserver(observation, forKeyPath: "value")
        }
    }
}

Мой вопрос:

  1. Почему следующий код не сработает? (Простое изменение наблюдения A на наблюдение B, являющегося членом A)

    class A: NSObject {
        @objc dynamic var value: Int = 0
    
        var observation: NSKeyValueObservation?
    
        let b = B()
    
        override init() {
            super.init()
            self.observation = self.b.observe(\B.value, options: [.new], changeHandler: { (_, change) in
    
            })
        }
    }
    
    class B: NSObject {
        @objc dynamic var value: Int = 0
    }
    
    var a: A? = A()
    a = nil
    
  2. Тем временем, если я добавляю предыдущий обходной путь к приведенному выше коду, я получаю новый сбой, почему?

    deinit {
        if let observation = self.observation {
            self.b.removeObserver(observation, forKeyPath: "value")
        }
    }
    

Новыйсбой:

*** Завершение работы приложения из-за необработанного исключения «NSRangeException», причина: «Невозможно удалить наблюдателя для ключевого пути« значение »из-за того, что он не зарегистрирован в качестве наблюдателя».

...