KVO

一.原理
KVO是系統(tǒng)用運行時機(jī)制給需要觀察的對象增加一個子類的方法實現(xiàn)的,如果一個對象被觀察,系統(tǒng)會給他增加以各子類,重寫它的set方法,從而實現(xiàn)觀察對象屬性變化的功能,為了使外部看不出來,系統(tǒng)還重寫了被觀察對象的-class,-isEqual:等方法。
二.自定義KVO(僅實現(xiàn)key,未實現(xiàn)keyPath)
1.這個方式是給要觀察的類添加一個子類

- (Class)achiveNewSubClass:(NSString *)className
          withCurrentClass:(Class)currentClass
{
  Class newClass = objc_allocateClassPair([self class],
                                          className.UTF8String,
                                          0);
  
  // 可以在這里給類添加成員變量等
  objc_registerClassPair(newClass);
  return newClass;
}

2.這個是重寫被觀察對象的set方法

void kvo_setter(id self, SEL selecter, id newValue) {
  
  KHHandle handle = objc_getAssociatedObject(self,
                                             @"123".UTF8String);
  NSString * key = achiveKeyPath(selecter);
  
  
  struct objc_super superclazz = {
    .receiver = self,
    .super_class = class_getSuperclass(object_getClass(self))
  };
  
    id oldValue = [self valueForKey:key];

  void (* objc_msgSendToSuper)(struct objc_super * ,SEL , id) = (void *)objc_msgSendSuper;
  // 在這里調(diào)取運行時創(chuàng)建的子類的父類的set方法賦值
  objc_msgSendToSuper(&superclazz, selecter, newValue);
    
  NSDictionary * dict = @{KHKeyValueNew : newValue ?:  @"",
                          KHKeyValueOld : oldValue ?: @"",
                          };
  handle(dict);
}

3.這個是提供給外部調(diào)用的方法

- (void)KH_addObserverWithKeyPath:(NSString *)keyPath
                        withBlock:(KHHandle)handle
{
  Class currentClass = [self class];
  NSString * className = NSStringFromClass(currentClass);
  if ([className hasPrefix:CLASS_PREFIX]) return;
  className = [CLASS_PREFIX stringByAppendingString:className];
  Class subClass =NSClassFromString(className);
  if (subClass) return;
  objc_setAssociatedObject(self,
                           @"123".UTF8String,
                           handle,
                           OBJC_ASSOCIATION_COPY_NONATOMIC);
  subClass = [self achiveNewSubClass:className
                    withCurrentClass:currentClass];
  
  object_setClass(self, subClass);
  
  SEL selecter = NSSelectorFromString(achiveMethodName(keyPath));
  
  Method me = class_getInstanceMethod(currentClass, selecter);
  
  const char * types =  method_getTypeEncoding(me);
  
 BOOL isSuccess = class_addMethod(subClass, selecter, (IMP)kvo_setter, types);
  
  
  NSLog(@"%d",isSuccess);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本篇會對KVO的實現(xiàn)進(jìn)行探究,不涉及太多KVO的使用方法,但是會有一些使用時的思考。 一、使用上的疑問 1.key...
    奮拓達(dá)閱讀 566評論 0 2
  • 上半年有段時間做了一個項目,項目中聊天界面用到了音頻播放,涉及到進(jìn)度條,當(dāng)時做android時候處理的不太好,由于...
    DaZenD閱讀 3,100評論 0 26
  • FBKVOController是一個簡單易用的鍵值觀察框架,KVOController 對于 Cocoa 中 KV...
    我有小尾巴快看閱讀 1,430評論 0 0
  • 本篇會對KVO的實現(xiàn)進(jìn)行探究,不涉及太多KVO的使用方法,但是會有一些使用時的思考。 一、使用上的疑問 1.key...
    孢子菌閱讀 2,259評論 7 13
  • KVO屬性依賴 看一個例子:我們的模型類 LabColor 代表一種 lab色彩空間里的顏色。和 RGB 不同,這...
    毅個天亮閱讀 809評論 0 1

友情鏈接更多精彩內(nèi)容