web-dev-qa-db-ja.com

Swift 3でKVOを使用して値が変更されたかどうかを確認する

Swiftオブジェクトのプロパティのセットがいつ変更されるかを知りたい。以前はObjective-Cでこれを実装していましたが、Swiftに変換するのに少し苦労しています。

以前のObjective-Cコードは次のとおりです。

- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
    if (![change[@"new"] isEqual:change[@"old"]])
        [self edit];
}

Swiftソリューションでの最初のパスは:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if change?[.newKey] != change?[.oldKey] {    // Compiler: "Binary operator '!=' cannot be applied to two 'Any?' operands"
        edit()
    }
}

ただし、コンパイラは「2項演算子 '!='は2つの 'Any?'に適用できません」と文句を言います。オペランド」

私の2回目の試み:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let newValue = change?[.newKey] as? NSObject {
        if let oldValue = change?[.oldKey] as? NSObject {
            if !newValue.isEqual(oldValue) {
                edit()
            }
        }
    }
}

しかし、これについて考えると、Swift NSObjectを継承せず、Objective-Cバージョンとは異なり、Intなどのオブジェクトのプリミティブに対しては機能しません。変更ディクショナリに配置されたときにNSNumberにボックス化されません。

だから、質問は、Swift3のKVOを使用して値が実際に変更されているかどうかを判断する一見簡単なタスクをどのように行うのですか?

また、ボーナスの質問、「オブジェクト」変数をどのように利用しますか?名前を変更することはできません。もちろん、スペースを含む変数は好きではありません。

18
aepryus

私の元の「2回目の試行」には、値がnilに変更されたときとnilから変更されたときに検出に失敗するバグが含まれています。最初の試みは、「変更」のすべての値がNSObjectであることを認識すると、実際に修正できます。

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    let oldValue: NSObject? = change?[.oldKey] as? NSObject
    let newValue: NSObject? = change?[.newKey] as? NSObject
    if newValue != oldValue {
        edit()
    }
}

または、必要に応じてより簡潔なバージョン:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if change?[.newKey] as? NSObject != change?[.oldKey] as? NSObject {
        edit()
    }
}
0
aepryus