Analysis of the realization principle of KVO

Source: Internet
Author: User

Recently read some about the iOS runtime related information, see someone on the internet on the implementation of the principle of kvo, just have time to study it, and organize to share to the beginner's friends.

The full name of KVO is Key-value observing, which implements a mechanism for adding observers to the object of interest, which is notified when the value of the attribute changes, and we can handle the change accordingly. Students who have seen design patterns should know that this is a typical observer pattern. The biggest advantage of KVO is that the underlying framework has been supported, and developers do not need to implement a scheme to send notifications when property values change, thus greatly reducing the amount of development effort. Second, the KVO framework is powerful, enabling multiple observers to observe the same attribute, or an observer to listen for different properties.

The use of KVO is relatively simple, basically three steps:

1. Registered Observer

AddObserver:forKeyPath:options:context:

2. The Observer realizes

ObserveValueForKeyPath:ofObject:change:context:

3. Remove the viewer

Removeobserver:forkeypath:

The use of the method is relatively simple, we do not explain in detail here, do not know where the SDK can be consulted, then we look at the implementation of the principle of KVO, which requires you to objective-c of the object model has a certain understanding.

When we studied KVO, we found that the system implemented this function using Objective-c's powerful runtime function. The attribute class does not implement the related scheme of KVO notification, but instead defines the property setter method in the subclass Subclass,subclass of the attribute class after calling Addobserver, and implements the function of initiating notification in setter method. Then the class function is implemented in subclass, and the class of the property classes is returned, and the Isa of the attribute class object is pointed to subclass, which is disguised as the notification function that the property class implements itself. We can see from the principle that you must assign a value using the attribute method or the Setvalue:forkey method to send a notification, and the direct assignment is not notified.

Next we write a demo program to see how KVO is implemented:

@interface classtest:nsobject{  IntX  IntY int z;}@property (nonatomic, assign)IntX@property (nonatomic, assign)IntY@property (nonatomic, assign)int z;@end@implementation Classtest@synthesizeXy,z;-(void) Observevalueforkeypath: (nsstring*) KeyPath Ofobject: (ID) object change: (nsdictionary*) Change context: (void *) context{ if ([KeyPath isequaltostring:@ "x"]) {  nsobject* new = [Change Objectforkey:@ "new"];  NSLog (@ "New x is%@", new); } else { [super Observevalueforkeypath:keypath Ofobject:object Change:change context:context]; } }@end                  

Defines the Classtest class, which defines three properties x, Y, Z.

Static nsarray* Classmethodlist ( class c) { nsmutablearray* span class= "keyword" >array = [Nsmutablearray arraywithcapacity:5]; unsigned int count = 0; method* methodlist = Class_copymethodlist (c, &count);  for (int i = 0; i < count; ++i)  {  sel sel = method_getname (* (methodlist+i));   [array addobject:nsstringfromselector (SEL)];} free (methodlist);  return array;}          
Define the Classmethodlist function to traverse class using the OBJECTIVE-C runtime function to get a list of methods
static void Printdescription (nsstring* name, id obj) {    nsstring* string = [NSString stringWithFormat:@ "%@: %@\n", name, obj, [obj class], object_getclass (obj), [Classmethodlist (Object_getclass (obj)) Componentsjoinedbystring:printf ("%s", [string utf8string]);}        
Define all the information for the Printdescription function to print the object, including the function class information and runtime dynamic class information, note that object_getclass (obj) and Obj->isa are equivalent, except Objective-c 2.0 does not support direct call to ISA at first.
int main (int argc, char * argv[]) {@autoreleasepool {classtest*x = [[Classtest alloc] init];classtest*y = [[Classtest alloc] init];classtest* xy = [[Classtest alloc] init];classtest* control = [[Classtest alloc] init]; [X addobserver:X Forkeypath:@"X"Options:nskeyvalueobservingoptionnew Context:nil];[Y addobserver:y Forkeypath:@ "Y" options:nskeyvalueobservingoptionnew Context:nil];[XY addobserver:xy Forkeypath:@"X"Options:nskeyvalueobservingoptionnew Context:nil];[XY addobserver:xy Forkeypath:@ "Y" options:nskeyvalueobservingoptionnew Context:nil]; Printdescription (@"X", x);Printdescription (@ "Y",y);Printdescription (@ "XY", XY);Printdescription (@ "Control", control);  printf"Using NSObject method, Normal SetX is%p, Overrite SetX is %p\n ", [Control Methodforselector: @selector (SetX:)], [x methodforselector: @selector (SetX:)] );  printf ( "Using Libobjc method, normal SetX is %p, Overrite SetX is %p\n ",  Class_ Getmethodimplementation (Control),  @selector (SetX:)),  Class_getmethodimplementation (Object_getclass (x),  @selector (SetX:));   return uiapplicationmain (argc, argv, Nil, Nsstringfromclass ([Appdelegate class])); }} 

We define the Classtest object x, Y, Z, control,x in the main function, add the observer to the attribute x, y Add the Observer to the attribute Y, XY adds to the observer for attribute x and attribute y, control does not add any observers, Then we look at the final printing results by printdescription the information of the object and finally printing the address of the SETX function.

x:<Classtest:0x8951690>  ClassClasstestObjclassNskvonotifying_classtestImplementmethodSety:,SetX:,Class,Dealloc,_iskvoay:<Classtest:0x89516c0> ClassClasstestObjclassNskvonotifying_classtestImplementmethodSety:,SetX:,Class,Dealloc,_iskvoaxy:<Classtest:0x89516d0> ClassClasstestObjclassNskvonotifying_classtestImplementmethodSety:,SetX:,Class,Dealloc,_iskvoacontrol:<classtest: 0x89516e0> Span class= "class" >class classtest Objclass classtest Implementmethod Z, x, SETX:, y, sety:, setz: observevalueforkeypath: Ofobject:change:context:using nsobject method, normal SetX is 0x4ae0, Overrite SetX is 0x1134526using Libobjc method, normal SetX is 0x4ae0, Overrite SetX is Span class= "number" >0x1134526            

From the printed results we see that the system actually has a subclass called Nskvonotifying_classtest, which implements the

Sety:, SetX:, Class, Dealloc, _iskvoa function, this _ISKVOA function should be a private function to determine whether the KVO framework generated classes, x, Y, XY object run-time classes are all pointing to Nskvonotifying_class Test, the class returned by the class function still points to classtest, but the class returned by the control object, regardless of the runtime class or class function, points to classtest. This verifies that the system is sending notifications by defining the subclass of the Classtest class to implement the property method, and the system is smart, and the Setz method is not implemented in the subclass because we do not add observers to attribute Z.

Looking at the results of the last two lines of printing, the SETX function address of the control object is not the same as the SETX function address of the X object, stating that the SETX function is rewritten. Look at other people's previous article, through the NSObject method to print control and X setx function address is the same, now verify the result address is not the same, and using the runtime method to print the result is exactly the same, this estimate is the new system bottom has been modified, Let the Methodforselector method using NSObject get the function to be a subclass of the function.

Analysis of the realization principle of KVO

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.