blog

SwiftでKVOを使う詳細と、その内部実装。

クラス Person: NSObject {\n var name: String?\n オーバーライド init\n オーバーライド init }。\n}\nこのクラスはメモリアドレス0x00000...

Apr 28, 2020 · 3 min. read
シェア
class Person: NSObject {
 var name: String?
 override init() {
 super.init()
 }
}
このクラスは、メモリ・アドレス0x00000fbd00007fffeefbfc240を出力する。

このコードはエラーを報告せず、典型的なswiftのレガシーObjC構文ですが、NSObjectを削除してそのメモリアドレスを出力すると、次のようになります。

class Person {
 var name: String?
 init() {
 
 }
}
このクラスはメモリ・アドレス0x00007feefbfc240を出力する。
  • メモリアドレスは同じではありませんが、NSObjectクラスのオブジェクトのメモリアドレスから継承され、明らかに多くの長さ8長さである、なぜですか? 8余分なスペースは、isaポインタ内のObjCオブジェクトを格納することである、興味のある研究をダウンさせることができます。
  • NSObjectを継承したクラスは、OCのsoi操作の一部(KVC、KVO、runtimeなど)を使用することができますが、そうでない場合はsetValue-forKeyを使用するとエラーが報告されます。

このほかにもいろいろな違いがあるので、開発の際には注意してみてください。個人的には、特にKVOのような操作が必要な場合は、NSObjectを継承しない方がいいと思います。

KVOはOCのオブジェクト属性の機能で、文字列を指向しているため、開発には特に注意が必要で、この種のランオンは実行された場合にのみエラーとして報告されます。次のクラスを宣言します:

class Person: NSObject {
 @objc var age: Int 
 var name: String?
 var observation: NSKeyValueObservation?
 
 override init() {
 super.init()
 self.observation = observe(\Person.age, options: .new, changeHandler: { (person, change) in
 print("Person.ageの新しい値は = ", change.newValue as Any)
 })
 }
}

外部で、以下のようにオブジェクトを初期化し、ageに値を代入します。

let person = Person()
person.age = 18
person.setValue(100, forKey: "age")

プログラム実行後なぜprintが1つしかないのですか?Person.age new value = 18とPerson.age new value = 001が表示されるはずなのに、されない。結局のところ、swiftで値をリッスンする必要がある場合、覚えておかなければならないキーワードが2つあるということです。

  • @objc
  • dynamic

そうでなければ

objcプログラムでは、リスニング時にランアラウンドが発生することはありません

dynamicでないと、属性のsetメソッドが効きませんし、KVOの性質上、属性のsetメソッドを聞くだけで、ミュータブルな配列の追加や削除は効かないので、当然、上記のようなプリントアウトもありません

しかし、なぜKVCのオペレーションは機能するのでしょうか?それは、KVCの内部実装プロセスが

  • [person willChangeValueForKey:@"age"];
  • person->_age = 10;
  • [person didChangeValueForKey:@"age"];

つまり、正しい書き方は

class Person: NSObject {
 @objc dynamic var age: Int 
 var name: String?
 var observation: NSKeyValueObservation?
 
 override init() {
 super.init()
 self.observation = observe(\Person.age, options: .new, changeHandler: { (person, change) in
 print("Person.ageの新しい値は = ", change.newValue as Any)
 })
 }
}
Read next

Vue- Vue.directivesカスタムディレクティブ

ユーザ登録ページを例にとると、デフォルトでは、ユーザがページを開いたときに入力ボックスにフォーカスが当たるのではなく、ユーザが入力ボックスをクリックした後にフォーカスが当たります。 このプロパティをカスタマイズして、ページを開いたときに自動的に入力ボックスにフォーカスが当たるようにすることができます。これを行うには、VueのAPI()を使用します。()内の最初のパラメータは、カスタム属性の名前です。

Apr 28, 2020 · 3 min read