1, KVO is based on the runtime mechanism to achieve;
2. When a property of an object of a class is first observed, a derived class of the class is dynamically created during run time, and in this derived class, the setter method of any observed property of the base class is overridden, and the derived class implements a true notification mechanism within the overridden setter method;
3, if the original class is person, then the generated derived class name is Nskvonotifying_person;
4, we know that each object has an Isa pointer (that is, the first member variable) points to the current class, so the system is the first time when the object of a class is observed, secretly the ISA pointer to dynamically generated derived classes, so that the "Listen Property" assignment is performed by the derived class setter method ;
5, in addition, Apple also secretly rewrite the class method of this derivative, this time po personobj, printing is still person, but using PO object_getclass (personobj), You can print out the type of the object Nskvonotifying_person; This is the current class that Apple made to hide the generated derived class, and let us mistakenly assume that it is still used;
6, the key value observation notification relies on the NSObject two methods: Willchangevalueforkey: and Didchangevlueforkey:; Before a observed attribute changes, Willchangevalueforkey: Must be called, this will record the old value, and when the change occurs, Didchangevalueforkey: It will be called, and then ObserveValueForKey:ofObject:change:context: it will be called.
7, note: Willchangevalueforkey: and Didchangevlueforkey: indispensable;
Just take the code to explain it, say a lot of, it is estimated that everyone can see the reason why.
1, Scene: We declare a person class, there are two properties, name and age, we want to use KVO to listen to the person object's age changes;
2. Create the person class and declare the properties:
1 #import<Foundation/Foundation.h>2 3 /**4 Person Model Class5 */6 @interfacePerson:nsobject7 8 /**9 nameTen */ One@property (nonatomic,copy) NSString *name; A - /** - Age the */ - @property (nonatomic,assign) Nsinteger age; - - @end
3. Create Person object, add Kvo Listener Object Age Property
1 #import "ViewController.h"2 #import "Person.h"3 4 @interfaceViewcontroller ()5 6 @end7 8 @implementationViewcontroller9 Ten- (void) Viewdidload { One [Super Viewdidload]; A -Person *per =[[Person alloc] init]; -Per.name =@"xiaoming"; thePer.age = -; - - //observe the change of the age property of the per object -[Per addobserver:self Forkeypath:@" Age"options:nskeyvalueobservingoptionnew Context:null]; + - //Modifying the value of the Age property will be observed +Per.age = -; A at //This is the result of PO per:<person:0x608000026960> - //however: Po object_getclass (PER) results: Nskvonotifying_person - //so: Apple secretly rewritten the class method of the derived class, but with the runtime you can see what type the current object belongs to - - //Remove Kvo -[Per removeobserver:self Forkeypath:@" Age"]; in } - to /** + KVO monitoring: Called when the Listener property of the listener is changed - the @param keypath the monitored properties * @param object being listened to $ changes in the change of @paramPanax Notoginseng @param the parameters that the context carries, this example passes in NULL to - */ the- (void) Observevalueforkeypath: (NSString *) KeyPath Ofobject: (ID)ObjectChange: (nsdictionary *) Change context: (void*) Context + { ANSLog (@"The %@ property of the%@ object has changed%@",Object, keypath,change); the + //Printing results: - //The Age property of the <Person:0x608000026960> object has changed { $ //kind = 1; $ //new =; - // } - } the - Wuyi @end
In fact, the implementation of KVO is the 2 methods: Willchangevalueforkey: And Didchangevlueforkey:
As long as we call these two methods, the property values do not change and are also observed.
1. Add a method to the person class Kvotest:
1 #import<Foundation/Foundation.h>2 3 /**4 Person Model Class5 */6 @interfacePerson:nsobject7 8 /**9 nameTen */ One@property (nonatomic,copy) NSString *name; A - /** - Age the */ - @property (nonatomic,assign) Nsinteger age; - - /** + monitoring the Age property has changed - */ +- (void) kvotest; A at @end
1 #import "Person.h"2 3 @implementation Person4 5- (void) kvotest{6 7[Self Willchangevalueforkey:@" Age"];8 9[Self Didchangevalueforkey:@" Age"];Ten } One A @end
2. Call the Kvotest method to listen for changes in the object property age:
1 #import "ViewController.h"2 #import "Person.h"3 4 @interfaceViewcontroller ()5 6 @end7 8 @implementationViewcontroller9 Ten- (void) Viewdidload { One [Super Viewdidload]; A -Person *per =[[Person alloc] init]; -Per.name =@"xiaoming"; thePer.age = -; - - //observe the change of the age property of the per object -[Per addobserver:self Forkeypath:@" Age"options:nskeyvalueobservingoptionnew Context:null]; + - //kvotest inside called Willchangevalueforkey: and Didchangevalueforkey + //so: Do not change the value of age, will still be heard A [per Kvotest]; at - //This is the result of PO per:<person:0x608000026960> - //however: Po object_getclass (PER) results: Nskvonotifying_person - //so: Apple secretly rewritten the class method of the derived class, but with the runtime you can see what type the current object belongs to - - //Remove Kvo in[Per removeobserver:self Forkeypath:@" Age"]; - } to + /** - KVO monitoring: Called when the Listener property of the listener is changed the * @param keypath the monitored properties $ @param object being listened toPanax Notoginseng changes in the change of @param - @param the parameters that the context carries, this example passes in NULL to the */ +- (void) Observevalueforkeypath: (NSString *) KeyPath Ofobject: (ID)ObjectChange: (nsdictionary *) Change context: (void*) Context A { theNSLog (@"The %@ property of the%@ object has changed%@",Object, keypath,change); + - //Printing results: $ //The Age property of the <Person:0x608000032ca0> object has changed { $ //kind = 1; - //new =;//because the value of age doesn't change at all, it's new or - // } the } - Wuyi the @end
The underlying implementation of KVO