日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

KVO-基本使用方法-底层原理探究-自定义KVO-对容器类的监听

發布時間:2023/12/31 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 KVO-基本使用方法-底层原理探究-自定义KVO-对容器类的监听 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

書讀百變,其義自見!

將KVO形式以代碼實現呈現,通俗易懂,更容易掌握 :GitHub? ?-鏈接如果失效請自動搜索:https://github.com/henusjj/KVO_base

代碼中有詳細的注釋

一、KVO-常用方法

?

//注冊 - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;//監聽方法 - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;//移除 - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0)); - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;//監聽模式(手動,自動),默認是自動Yes +(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key;//屬性的依賴,返回監聽屬性類的集合+(NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key;

?

二、KVO-基本使用

KVO監聽屬性值變化,從而做業務邏輯處理,監聽屬性變化,我們需要實現三步走

1.注冊監聽對象

2.實現監聽方法

3.移除監聽對象,避免crash

?

?

// // ViewController.m // KVO-基本用法 // // Created by GuoYanjun on 2019/1/9. // Copyright ? 2019年 shiyujin. All rights reserved. // #import "ViewController.h" #import "Person.h" @interface ViewController () @property(nonatomic,strong)Person *p; @end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];_p=[[Person alloc]init]; // 注冊 [_p addObserver:self forKeyPath:NSStringFromSelector(@selector(name)) options:NSKeyValueObservingOptionNew context:nil];}//監聽方法 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{NSLog(@"%@",change); } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{// 自動模式static int a =0;_p.name = [NSString stringWithFormat:@"%d",a++];// 手動 // [_p willChangeValueForKey:@"name"]; // _p.name = [NSString stringWithFormat:@"%d",a++]; // [_p didChangeValueForKey:@"name"]; // } -(void)dealloc{[_p removeObserver:self forKeyPath:@"name"]; } @end

?

?

?

三、底層原理探究

這里我總結三個地方

1.創建一個子類,名字是:NSKVONotifying_Person ?,person是本項目中的類

  這里為什么是子類不是分類呢,這里說明以下,如果使用分類 ,他會覆蓋set方法,導致原set方法中的邏輯處理失效

2.重寫了set方法

  這里的重寫不是重寫父類的的set,而是重寫子類的

3.外界改變isa指針

  此處可以在注冊方法打一個斷點,觀察其isa指針的變化

self->_p->isa:Person改變為self->_p->isa:NSKVONotifying_Person

?

? ?

?

四、對容器的監聽

對于數組,我們添加元素的時候,都是addObject........

但是我們知道,KVO是針對set方法從而監聽的,因為,

addObject........是不會響應的,此時,蘋果給我提供了

?

// [_p.arry addObject:[NSString stringWithFormat:@"%d",a++]];//這一步不會觸發監聽方法因為監聽是監聽set的方法,addObject不是set方法//解決方法NSMutableArray *tenp =[_p mutableArrayValueForKey:@"arry"];[tenp addObject:[NSString stringWithFormat:@"%d",a++]];

?

?

五、自定義KVO

此處需要用到Runtime,KVO文檔中,我們會發現,相關方法是在NSobjet的分類,所以

1.創建一個NSObject的分類,定義注冊方法

?

#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface NSObject (JK_KVO) - (void)JK_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context; @endNS_ASSUME_NONNULL_END

?

2.實現該方法

?

#import "NSObject+JK_KVO.h" #import <objc/message.h>@implementation NSObject (JK_KVO)- (void)JK_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context{// 1.創建一個類 -- self.class 就是PersonNSString *oldname = NSStringFromClass(self.class);NSString *newNem = [@"JKKVO_" stringByAppendingString:oldname];Class myclass = objc_allocateClassPair(self.class, newNem.UTF8String, 0);// 注冊類 objc_registerClassPair(myclass);// 2.重寫子類set方法 -- 所謂的重寫就是給子類添加f這個方法 setName,因為子類沒有父類的setName方法!!!/* class :給那個類添加方法*sel:方法編號*imp :方法實現(函數指針)*type :返回值類型*/class_addMethod(myclass, @selector(setName:), (IMP)setName, "v@:@");// 3.修改isa指針 object_setClass(self, myclass);// 4.將觀察保存到當前對象objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_ASSIGN);}void setName(id self,SEL _cmd,NSString *newName){NSLog(@"來了--%@",newName); // 調用父類的setName方法Class class =[self class];object_setClass(self, class_getSuperclass(class));//改成父類 objc_msgSend(self,@selector(setName:),newName);//發送消息給父類// 觀察者id observer = objc_getAssociatedObject(self, @"observer");if (observer) {objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:),@"name",self,@{@"new:":newName,@"kind:":@"1"},nil);}// 改回子類object_setClass(self, class); } @end

3.調用

[_p JK_addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

----!!!!!!!!

OK,結束。代碼已經整理完畢。下班

轉載于:https://www.cnblogs.com/henusyj-1314/p/10245363.html

總結

以上是生活随笔為你收集整理的KVO-基本使用方法-底层原理探究-自定义KVO-对容器类的监听的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。