Introduction to the

KVO is sure that iOS developers have heard of it and are often asked about it in interviews, but for KVO, the system does more of the work. It depends on the runtime. Compared to Notification and delegate, it is simpler to provide observation properties with old and new values The principle of rough understanding, with the RunTime rewrite KVO, there is an improper understanding of the place, please put forward, thank you


KVO basic usage and usage scenarios < Observer mode perfectly decouples the target object from the observer object >

A. First, let’s talk about the usage scenarios:

A target object manages all observers that depend on the target object, and actively notifies observers when its state changes -> can listen for changes in an object’s property value <1 to many >

B. Basic steps:

1. Add an observer to the target object

Code examples:

[dog addObserver:self forKeyPath:@”name” options:NSKeyValueObservingOptionNew context:nil];

2. Process change notifications

When KVO after listening to the target object property values change, can call this method, change the dictionary keeps a change information, what are the specific information depends on the NSKeyValueObservingOptions when registering

– (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object chan

ge:(NSDictionary *)change context:(void *)context;

3. Remove

– (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;


Discussion:

When the target object call addObserver: self forKeyPath: < # (nonnull nsstrings *) # > options: < # # (NSKeyValueObservingOptions) > Context :<#(nullable void *)#> what happened to the method, so will it still work when we change it to a member variable?

Answer: What does Runtime do, that is, dynamically add a subclass to the target object class, override the set method, and change the ISA pointer

Code examples:






KVO principle

KVO – key (key) and value (value) observation (observing) — – > the observer design pattern mode;

A class was observed for the first time, the system will dynamically at run time to create a subclass of the class, and then rewrite observed attribute setter methods in subclasses, rewrite the setter method in a subclass of the true notification mechanism, subclasses in addition to rewrite the setter method also rewrite the class method the cheat the caller subclass is originally The parent class becomes the object of the derived class, so calls to setter methods of the overridden class invoke the notification mechanism. In addition, the subclass overrides dealloc to release resources

How to rewrite KVO with RunTime

1. Write in our own definition of a mock KVO method

Sample code:

– (void)MBXB_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{

/ / do things

}


2. Implementation steps

A. Dynamically generate a class

Dynamic class name

NSString * oldClassName = NSStringFromClass([self class]);

NSString * newName = [@”NSMBXB_” stringByAppendingString:oldClassName];

const char * newClassName = [newName UTF8String];

B. Define a class

Class MyClass = objc_allocateClassPair([self class], newClassName, 0);

C. Add the setName method —->, also known as the override method

class_addMethod(MyClass, @selector(setName:), (IMP)setName, “v@:@”);

D. Register the class

objc_registerClassPair(MyClass);

E. Modify the observed ISA pointer to the custom class

object_setClass(self, MyClass);

F. Dynamically bind attributes

objc_setAssociatedObject(self, (__bridge const void *)@”123″, observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);


3. Implement the setName override method

void setName(id self,SEL _cmd,NSString * newName){

/ / do something

}

A. Save the current type

id class = [self class];

B. Point to the parent class

object_setClass(self, class_getSuperclass([self class]));

C. Call the setName method of the parent class

objc_msgSend(self, @selector(setName:),newName);

D. Bring out the observer

id observer = objc_getAssociatedObject(self, (__bridge const void *)@”123″);

E. notice

objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:),self,@”name”,@{@”new”:newName},nil);

F. Change back to subclasses

object_setClass(self, class);


Summary:

At this point we’re rewriting KVO with Runtime and it’s pretty easy to do, so let’s experiment

Sample code:

/ / add

Dog * dog = [[Dog alloc]init];

[dog MBXB_addObserver:self forKeyPath:@”name” options:NSKeyValueObservingOptionNew context:nil];

_dog = dog;

/ / implementation

– (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context{

NSLog(@”%@===>YES successful %@”,change,_dog.name);

}

// Tap the screen to test:

– (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event {

     static int i = 0;

      i++;

      _dog.name = [NSString stringWithFormat:@”%d”,i];

}

Click the screen test results, is it successful?






Finally, I will dedicate the code link of this article to you, and give you a lot of thumbs up on the demo. I hope you can download star