KVO and ioskvo

Source: Internet
Author: User

KVO and ioskvo
1. KVO Concept

KVO is the key-value observation. It provides a mechanism for the observed object to receive notifications when its attributes change, so as to make corresponding changes.

2. KVO implementation principle

Here is an isa pointer. In Objective-C, the definition of any class is an object. There is no essential difference between a class and a class instance (object. Any object has an isa pointer.

So what is a class? In xcode, use the shortcut key Shift + Cmd + O to open the file objc. h to see the class definition:

  

We can see that:

Class is a pointer of the objc_class structure type, and id is a pointer of the objc_object structure type.

Let's take a look at the definition of objc_class:

 

 

Explain the meaning of each parameter a little:

Isa: A Class pointer. each instance object has an isa pointer pointing to the object Class, and the Class also has an isa pointer pointing to meteClass ). The metadata class saves the list of class methods. When a class method is called, it first looks for the implementation of the class method. If no, the Meta class will look for the method from its parent class. Note that meteClass is also a class and an object. The Meta class also has an isa pointer. Its isa pointer eventually points to a root meteClass. The isa pointer of the root Meta class points to itself, forming a closed internal loop.

Super_class: parent class. If this class is already the top-level root class, it is NULL.

Version: version of the class. The default value is 0.

Info: Bit IDs used during runtime.

Instance_size: instance variable size of this class

Ivars: array of member variables

Let's take a look at the inheritance relationships of various class instance variables:

 

Each object is essentially an instance of a class. The class defines the list of member variables and member methods. The object points to the class through the isa pointer of the object.

Each class is essentially an object, and the class is actually an instance of meteClass. The meta-class defines the list of class methods. Class points to the metaclass through the isa pointer of the class.

All Metadata classes ultimately inherit a root Meta class. The isa pointer of the root Meta class points to itself to form a closed internal loop.

 

  Principle:Every object has an isa pointer. This object searches for the class it belongs to based on the isa pointer. When we register an observer for an object, the system will create a subclass for this object at runtime. This subclass inherits from the class to which the current object belongs and points the isa pointer of the current object to this subclass, the current object becomes an instance of this subclass. So what operations are performed inside this subclass? In fact, this subclass overrides the set method. When the original object calls the set Method to assign values, it searches for the IMP of the set Method Based on the isa pointer to the method list of the new subclass, at this time, the set Method of this rewrite will send a notification to all objects that observe this attribute, so the original object will change.

 

In-depth analysis:

Apple uses isa-swizzling to implement KVO. When observing object A, the KVO mechanism dynamically creates A new class named NSKVONotifying_A, which inherits from the class of object A, and KVO is NSKVONotifying_A to override the setter method of the observation attribute, the setter method notifies all changes to the observed object property values before and after calling the original setter method.

 

  • NSKVONotifying_A Class Analysis: In this process, the isa pointer of the observed object points to the original Class A, and the KVO mechanism changes to the NSKVONotifying_A class that points to the new subclass of the system, to monitor changes to the current class property value;
  • So from the perspective of the application layer, we are not aware of the emergence of new classes. This is the underlying implementation process of the system "hiding" KVO, which makes us mistakenly think it is the original class. However, if we create a new class named "NSKVONotifying_A" (), we will find that the program crashes when the system runs the code registered with KVO, the system dynamically creates an intermediate class named NSKVONotifying_A when registering the listener and points to this intermediate class.
  • Therefore, the call to setter on this object calls the rewritten setter to activate the key-value notification mechanism.

 

  • KVO key value observation relies on two NSObject Methods: willChangeValueForKey and didChangevlueForKey, that is, the two methods are called before and after the key value changes, call the set Method of the parent class to assign values between the two methods.
  • Before the observed attribute changes, willChangeValueForKey is called to notify the system that the keyPath attribute value is about to change. After the change, didChangeValueForKey is called to notify the system that the keyPath attribute value has changed; after that, observeValueForKey: ofObject: change: context: will also be called. In addition, the setter Method for rewriting observation attributes is implemented at runtime rather than during compilation.

KVO is a subclass of the observer attribute. The principle of calling the access method is equivalent:

1-(void) setName :( NSString *) newName2 {3 [self willChangeValueForKey: @ "name"]; // KVO always calls 4 [super setValue: newName forKey: @ "name"]; // call the access method of the parent class 5 [self didChangeValueForKey: @ "name"]; // KVO calls 6 after calling the access method}

 

 

Sample Verification
1 // Person Class 2 @ interface Person: NSObject 3 @ property (nonatomic, copy) NSString * name; 4 @ end 5 6 // controller 7 Person * per = [[Person alloc] init]; 8 // breakpoint 1 9 [per addObserver: self forKeyPath: @ "name" options: NSKeyValueObservingOptionNew context: nil]; 10 // breakpoint 211 per. name = @ "James"; 12 [per removeObserver: self forKeyPath: @ "name"]; 13 // breakpoint 3
View Code

Run the project,

  • InBreakpoint 1Location:

 

 

  • We can see thatisaPointPersonClass, we can also uselldbCommand to view:
    (lldb) po [per class]Person(lldb) po object_getClass(per)Person(lldb)

 

  • InBreakpoint 2Location:

 

(lldb) po [per class]Person(lldb) po object_getClass(per)NSKVONotifying_Person(lldb)

 

  • InBreakpoint 3Location:
(lldb) po [per class]Person(lldb) po object_getClass(per)Person(lldb)

 

 

The above results show that when the per object is observed, framework dynamically creates a subclass NSKVONotifying_Person of the Person class using runtime, and in order to hide this behavior, NSKVONotifying_Person overwrites the-class method to return the previous class, as if nothing had happened. But it is exposed when object_getClass () is used, because this method returns the isa pointer of this object, which must be a class object of this object.

 

3. Features of KVO

Because the KVO internal implementation principle is to override the set method, the KVO callback method is executed only when the property of the observed object calls the set method value assignment. Therefore, if you directly assign values to the attribute member variables, KVO is not triggered.

4. KVO call steps

1. register the observer
2. Process events in the callback Method
3. Remove the observer

5. Code practice
1 self. changeStr = @ "hello"; 2 [self addObserver: self forKeyPath: @ "changeStr" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context: nil]; 3 self. changeStr = @ ""; 4 5 6-(void) observeValueForKeyPath :( NSString *) keyPath ofObject :( id) object change :( NSDictionary <NSKeyValueChangeKey, id> *) change context :( void *) context 7 {8 NSLog (@ "The changed attribute is % @", keyPath); 9 NSString * str = [change objectForKey: NSKeyValueChangeNewKey]; 10 NSString * odlStr = [change objectForKey: NSKeyValueChangeOldKey]; 11 NSLog (@ "Old attribute is % @", odlStr); 12 NSLog (@ "new attribute is % @", str); 13}
View Code

 

Output result:
A Demo: In the LYXItem. h file
1 #import <Foundation/Foundation.h>2 3 @interface LYXItem : NSObject4 5 @property(nonatomic, copy) NSString *name;6 @property(nonatomic, copy) NSString *price;7 8 @end

 

In the LYXItemView. h file

 1 #import <Foundation/Foundation.h> 2 #import "LYXItem.h" 3  4 @interface LYXItemView : NSObject 5  6 @property(nonatomic, weak) LYXItem *item; 7  8 - (void) showItemInfo; 9 10 @end

 

In LYXItemView. m

1 # import "LYXItemView. h "2 3 @ implementation LYXItemView 4 5 @ synthesize item = _ item; 6 7-(void) showItemInfo 8 {9 NSLog (@" item name: % @, price: % @ ", self. item. name, self. item. price); 10} 11 12 13-(void) setItem :( LYXItem *) item14 {15 self-> _ item = item; 16 // Add a listener for the item, listen to changes in the attribute of item name 17 [self. item addObserver: self forKeyPath: @ "name" options: NSKeyValueObservingOptionNew context: nil]; 18 19 [self. item addObserver: self forKeyPath: @ "price" options: NSKeyValueObservingOptionNew context: nil]; 20} 21 22 23-(void) observeValueForKeyPath :( NSString *) keyPath ofObject :( id) object change :( NSDictionary <NSKeyValueChangeKey, id> *) change context :( void *) context24 {25 NSLog (@ "descriobservevalueforkeypath ------------------------"); 26 NSLog (@ "modified keyPath: % @", keyPath); 27 NSLog (@ "modified object: % @", object ); 28 NSLog (@ "the new attribute value is: % @", [change objectForKey: @ "new"]); 29 NSLog (@ "the modified context is: % @ ", context); 30} 31 32 33 @ end
View Code

 

In the running File

 

1 LYXItem * item = [[LYXItem alloc] init]; 2 item. name = @ "IOS"; 3 item. price = @ "6888"; 4 5 LYXItemView * lyxView = [[LYXItemView alloc] init]; 6 lyxView. item = item; 7 [lyxView showItemInfo]; 8 9 // change the item value. Method 10 of the listener is triggered. name = @ "Android"; 11 item. price = @" 1999 ";

 

Print result:

 

Related Article

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.