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)
})
}
}





