

このクラスのインスタンスを別クラスで更新した際の時間を覚えておこうと思うのですが、なにか良い方法はないでしょうか。

[code]

    class Testdata: NSObject {
       var data1 = Data1()
       var data2 = Data2()
    
       class Data1 {
         dynamic var version: UInt8 = 0x10
         dynamic ver ・・・
       }
       class Data2 {
         dynamic var no: UInt8 = 0x100
         dynamic ver ・・・
       }
    }
    
    
       var date: UInt64 = 0
       var data1 = Data1() {
           didSet {
               self.date = UInt64(NSDate().timeIntervalSince1970)
           }
       }
       var data2 = Data2() {
           didSet {
               self.date = UInt64(NSDate().timeIntervalSince1970)
           }
       }
    
[/code]

上記でとれないか…と試してみたのですが、  
data1.versionを書き換えてもdidSetが呼ばれることはありませんでした。  
なにかいい方法はないのでしょうか。


CC BY-SA 3.0
2016-02-16T08:27:56.060
22164
2016-02-17T10:44:25.950
12842
question
swift
インスタンス更新時刻を保持したい


特に「いい方法」と言うのはなさそうです。  
(ちなみにあなたのコードでは`data1`(または`data2`)そのものが書き換えられない限り(つまり別のインスタンスを代入しない限り)、それぞれの`didSet`が呼ばれることはありません。)

(1)更新日時を記録したいすべてのインスタンスのすべてのプロパティにKVO(キー値監視)を設定する。

[code]

    class Testdata: NSObject {
        var data1 = Data1()
        var data2 = Data2()
    
        var updateDate: NSDate = NSDate()
    
        class Data1: NSObject {
            dynamic var version: UInt8 = 0x10
            //dynamic ver ・・・
            //...
        }
        class Data2: NSObject {
            dynamic var no: UInt8 = 0x10
            //dynamic ver ・・・
            //...
        }
    
        override init() {
            super.init()
            data1.addObserver(self, forKeyPath: "version", options: [], context: nil)
            //data1.addObserver(self, forKeyPath: "...", options: [], context: nil)
            //...
            data2.addObserver(self, forKeyPath: "no", options: [], context: nil)
            //data2.addObserver(self, forKeyPath: "...", options: [], context: nil)
            //...
        }
    
        deinit {
            data1.removeObserver(self, forKeyPath: "version")
            //data1.removeObserver(self, forKeyPath: "...")
            //...
            data2.removeObserver(self, forKeyPath: "no")
            //data2.removeObserver(self, forKeyPath: "...")
            //...
        }
    
        override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
            if object === data1 || object === data2 {
                self.updateDate = NSDate()
            }
        }
    }
    
[/code]

(2)更新日時を記録したいすべてのクラスのすべてのインスタンスにdidSetで更新時間を記録させる。

[code]

    protocol MyDataObserver: class {
        func setUpdateDate()
    }
    class Testdata2: MyDataObserver {
        var data1 = Data1()
        var data2 = Data2()
    
        var updateDate: NSDate = NSDate()
    
        class Data1: NSObject {
            weak var observer: MyDataObserver?
            var version: UInt8 = 0x10 {
                didSet {
                    observer?.setUpdateDate()
                }
            }
            //ver ・・・ {
            //  didSet {
            //      observer?.setUpdateDate()
            //  }
            //}
            //...
        }
        class Data2: NSObject {
            weak var observer: MyDataObserver?
            var no: UInt8 = 0x10 {
                didSet {
                    observer?.setUpdateDate()
                }
            }
            //ver ・・・ {
            //  didSet {
            //      observer?.setUpdateDate()
            //  }
            //}
            //...
        }
    
        init() {
            data1.observer = self
            data2.observer = self
        }
    
        ///MyDataObserver
        func setUpdateDate() {
            self.updateDate = NSDate()
        }
    }
    
[/code]

あたりがすぐに思いつくところでしょうか。どちらも「いい方法」には思えませんが。

(3)更新を記録したいすべてのプロパティのセッターをprivateにして、値の変更は`setValue(_:forKeyPath:)`メソッドでしかできなくする、なんてのも面白そうです。

[code]

    class Testdata3: NSObject {
        dynamic var data1 = Data1()
        dynamic var data2 = Data2()
    
        var updateDate: NSDate = NSDate()
    
        class Data1: NSObject {
            dynamic private(set) var version: UInt8 = 0x10
            //dynamic private(set) ver ・・・
            //...
        }
        class Data2: NSObject {
            dynamic private(set) var no: UInt8 = 0x10
            //dynamic ver ・・・
            //...
        }
    
        override func setValue(value: AnyObject?, forKeyPath keyPath: String) {
            if keyPath.hasPrefix("data1.") || keyPath.hasPrefix("data2.") {
                self.updateDate = NSDate()
            }
            super.setValue(value, forKeyPath: keyPath)
        }
    }
    
    let myTestdata3 = Testdata3()
    myTestdata3.setValue(0x20, forKeyPath: "data1.version")
    print(myTestdata3.data1.version) //->32
    print(myTestdata3.updateDate) //->setValue(_:forKeyPath:)を呼んだ時刻
    
[/code]

私が同じような要件をもらったら、(3)の改造版ということで、更新記録が必要になるようなデータを全部保持するクラスを作って、限られたメソッドでしかそれらのデータ更新ができないようにして、そのメソッドについては呼ばれた時間を記録する、なんてことをやるでしょうか。

もしかしたら、「こんなうまい方法があるよ」というのをご存知の方がおられるかもしれませんが、私に思いつくのはこんなところです。

[修正]不要なdynamicをコード例から削除しました。


CC BY-SA 3.0
2016-02-16T12:36:05.833
22175
2016-02-17T10:44:25.950
2016-02-17T10:44:25.950
13972
13972
22164
answer