ios KVC與KVO的探索研究

1. KVC

1.0 KVC的使用

  • LGStudent.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface LGStudent : NSObject
@property (nonatomic, copy)   NSString          *name;
@property (nonatomic, copy)   NSString          *subject;
@property (nonatomic, copy)   NSString          *nick;
@property (nonatomic, assign) int               age;
@property (nonatomic, assign) int               length;
@property (nonatomic, strong) NSMutableArray    *penArr;
@end

NS_ASSUME_NONNULL_END
  • LGPerson.h
#import <Foundation/Foundation.h>
#import "LGStudent.h"

NS_ASSUME_NONNULL_BEGIN

typedef struct {
    float x, y, z;
} ThreeFloats;

@interface LGPerson : NSObject{
   @public
   NSString *myName;
}

@property (nonatomic, copy)   NSString          *name;
@property (nonatomic, strong) NSArray           *array;
@property (nonatomic, strong) NSMutableArray    *mArray;
@property (nonatomic, assign) int age;
@property (nonatomic)         ThreeFloats       threeFloats;
@property (nonatomic, strong) LGStudent         *student;

@end

NS_ASSUME_NONNULL_END

我們?cè)谄綍r(shí)一般使用LGPerson *person = [[LGPerson alloc] init]; person.name = @"Cooci";這樣的setter方法來(lái)對(duì)對(duì)象的某一個(gè)屬性進(jìn)行賦值,但是,我們也可以采用[person setValue:@"KC" forKey:@"name"];這樣的Key-Value Coding (KVC)形式進(jìn)行賦值。

    1. 集合類型
    person.array = @[@"1",@"2",@"3"];
    // 修改數(shù)組
    // 第一種:搞一個(gè)新的數(shù)組 - KVC 賦值就OK
    NSArray *array = [person valueForKey:@"array"];
    array = @[@"100",@"2",@"3"];
    [person setValue:array forKey:@"array"];
    NSLog(@"%@",[person valueForKey:@"array"]);
    // 第二種
    NSMutableArray *mArray = [person mutableArrayValueForKey:@"array"];
    mArray[0] = @"200";
    NSLog(@"%@",[person valueForKey:@"array"]);
    1. 結(jié)構(gòu)體
    ThreeFloats floats = {1.,2.,3.};
    NSValue *value     = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)];
    [person setValue:value forKey:@"threeFloats"];
    NSValue *value1    = [person valueForKey:@"threeFloats"];
    NSLog(@"%@",value1);

    ThreeFloats th;
    [value1 getValue:&th];
    NSLog(@"%f-%f-%f",th.x,th.y,th.z);
    1. 通過(guò)keyPath訪問(wèn)
    LGStudent *student = [LGStudent alloc];
    student.subject    = @"大師班";
    person.student     = student;
    
    [person setValue:@"Swift" forKeyPath:@"student.subject"];
    NSLog(@"%@",[person valueForKeyPath:@"student.subject"]);
    1. 字典
    NSDictionary* dict = @{
                           @"name":@"Cooci",
                           @"nick":@"KC",
                           @"subject":@"iOS",
                           @"age":@18,
                           @"length":@180
                           };
    LGStudent *p = [[LGStudent alloc] init];
    // 字典轉(zhuǎn)模型
    [p setValuesForKeysWithDictionary:dict];
    NSLog(@"%@",p);
    // 鍵數(shù)組轉(zhuǎn)模型到字典
    NSArray *array = @[@"name",@"age"];
    NSDictionary *dic = [p dictionaryWithValuesForKeys:array];
    NSLog(@"%@",dic);

這些類型的使用在apple 官方文檔中都有詳細(xì)介紹。

1.2 KVC原理

KVC.png

如圖上可知锦爵,KVC的源碼在Foundation庫(kù)內(nèi),而Foundation庫(kù)是未開(kāi)源的,所以我們需要從apple 官方文檔去探索延曙。

  • KVC設(shè)值流程
    官方文檔:
    KVC - setter.png

    根據(jù)文檔提示,第一步先要看是否實(shí)現(xiàn)了setKey方法或者_setKey方法亡哄。如果實(shí)現(xiàn)了setKey_setKey枝缔,則看accessInstanceVariablesDirectly方法中是否返回了YES,默認(rèn)是返回YES的蚊惯,如果你重寫(xiě)了此方法并返回NO愿卸,則代碼會(huì)調(diào)用setValue:forUndefinedKey并發(fā)生異常。當(dāng)accessInstanceVariablesDirectly方法返回了YES截型,則去找當(dāng)前對(duì)象是否有key,_isKey趴荸,keyisKey宦焦,如果有发钝,則設(shè)值完成,如果沒(méi)有波闹,則調(diào)用setValue:forUndefinedKey并發(fā)生異常酝豪。
    驗(yàn)證:
  • LGPerson.h
#import <Foundation/Foundation.h>
#import "LGStudent.h"

NS_ASSUME_NONNULL_BEGIN

@interface LGPerson : NSObject{
    @public

        NSString *_name;
        NSString *_isName;
        NSString *name;
        NSString *isName;
      
}

@end

NS_ASSUME_NONNULL_END
  • LGPerson.m
#import "LGPerson.h"

@implementation LGPerson

#pragma mark - 關(guān)閉或開(kāi)啟成員變量賦值
+ (BOOL)accessInstanceVariablesDirectly{
    return YES;
}

#pragma MARK:賦值 - setKey. 的流程分析
- (void)setName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

- (void)_setName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

- (void)setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

// 沒(méi)有調(diào)用
- (void)_setIsName:(NSString *)name{
    NSLog(@"%s - %@",__func__,name);
}

@end
  • 調(diào)用
  LGPerson *person = [[LGPerson alloc] init];

  [person setValue:@"jeffery_zc" forKey:@"name"];

首先,按照官方文檔精堕,最先調(diào)用的是_Key孵淘,為了驗(yàn)證這個(gè)猜想,我們打印一下輸出結(jié)果NSLog(@"%@-%@-%@-%@",person->_name,person->_isName,person->name,person->isName);發(fā)現(xiàn)只有person->_name有值歹篓,其他為null,于是瘫证,我們屏蔽LGPerson.h_name,再次輸出打印結(jié)果NSLog(@"%@-%@-%@",person->_isName,person->name,person->isName);,發(fā)現(xiàn)person->_isName有值了滋捶,其他依舊是null痛悯。依次操作打印輸出結(jié)果,得出結(jié)論與官方文檔一致重窟,設(shè)值流程為_key,_isKey载萌,key,isKey

  • KVC取值流程
    官方文檔:
    KVC取值01.png

KVC取值02.png

根據(jù)官方文檔扭仁,首先查詢是否有getKey垮衷,key,isKey乖坠,_key方法搀突,如果有,先判斷當(dāng)前實(shí)例對(duì)象是否為集合類型熊泵,緊接著仰迁,判斷accessInstanceVariablesDirectly是否返回YES,如果是顽分,則尋找是否有_key徐许,_isKey,key卒蘸,isKey的成員變量雌隅,如果有,判斷是否為集合類型并做處理缸沃,如果沒(méi)有恰起,則調(diào)用setValue:forUndefinedKey并發(fā)生異常。
驗(yàn)證:
LGPerson.m中的setter驗(yàn)證方法屏蔽趾牧,添加如下代碼:


#pragma MARK: 取值 - valueForKey 流程分析 - get<Key>, <key>, is<Key>, or _<key>,

- (NSString *)getName{
    return NSStringFromSelector(_cmd);
}

- (NSString *)name{
    return NSStringFromSelector(_cmd);
}

- (NSString *)isName{
    return NSStringFromSelector(_cmd);
}

- (NSString *)_name{
    return NSStringFromSelector(_cmd);
}
  • 驗(yàn)證getter方法取值的調(diào)用順序
    NSLog(@"取值:%@",[person valueForKey:@"name"]);

第一次輸出打印為getName检盼,于是,我們屏蔽getName輸出打印結(jié)果為name,依次屏蔽操作武氓,得出官方文檔第一步的結(jié)論梯皿,getter取值的調(diào)用順序?yàn)?code>getKey,key县恕,isKey东羹,_key。

  • 驗(yàn)證成員變量取值順序
    屏蔽LGPerson.msetter,getter方法忠烛,在調(diào)用代碼中加入如下代碼:
    person->_name = @"_name";
    person->_isName = @"_isName";
    person->name = @"name";
    person->isName = @"isName";

    NSLog(@"取值:%@",[person valueForKey:@"name"]);

第一次打印結(jié)果為_name属提,然后屏蔽成員變量_nameperson->_name = @"_name";,打印結(jié)果為_isName美尸,依次操作冤议,打印結(jié)果分別為_name,_isName师坎,name恕酸,isName,正好與官方文檔第四步一致。

2. KVO

2.1 KVO的使用

KVO(Key-value observing)是一種鍵值觀察機(jī)制胯陋,它允許將其他對(duì)象的指定屬性的更改通知給對(duì)象蕊温。我們通常使用KVO在控制器中觀察某一對(duì)象的屬性變化袱箱。

  • 注冊(cè)通知:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;

observer:觀察者,一般寫(xiě)self义矛;
keyPath:觀察的鍵值发笔,一般是對(duì)象的成員變量;
options:一種枚舉值凉翻,比如新值舊值這些了讨;
context:上下文,用來(lái)保存一些信息制轰,contextvoid *類型前计,當(dāng)只有一個(gè)觀察者時(shí),一般直接傳null垃杖,當(dāng)有多個(gè)觀察者時(shí)残炮,一般會(huì)定義多個(gè)void *類型的值用來(lái)區(qū)分。例:static void *PersonNickContext = &PersonNickContext;

  • KVO回調(diào)函數(shù)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
   //處理事件
}
  • 移除觀察者
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

移除觀察者.png

根據(jù)官方文檔描述缩滨,移除觀察者是必須要進(jìn)行的,如果你沒(méi)有移除觀察者泉瞻,可能會(huì)報(bào)錯(cuò)NSRangeException脉漏。

  • 手動(dòng)添加觀察
    默認(rèn)情況下,自動(dòng)觀察都是打開(kāi)的袖牙,當(dāng)我們需要手動(dòng)進(jìn)行觀察某一個(gè)對(duì)象時(shí)侧巨,可以使用+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey方法將自動(dòng)觀察關(guān)閉。
    關(guān)閉自動(dòng)觀察.png

    然后在觀察的屬性的賦值前添加willChangeValueForKey:方法鞭达,賦值后添加didChangeValueForKey :方法司忱,這樣,這一屬性就變?yōu)槭謩?dòng)觀察了畴蹭。
    手動(dòng)觀察.png

    官方文檔還介紹了更多了的使用方法坦仍,這里我就不過(guò)多介紹了。
  • 路徑處理
    假設(shè)我們需要檢測(cè)當(dāng)前的下載進(jìn)度downloadProgress,而下載進(jìn)度 = 已下載 / 總下載叨襟,所以我們可以利用集合將totalData總下載合并成一個(gè)downloadProgress繁扎,這樣,我們就只需要觀察downloadProgress就可以了糊闽。
// 下載進(jìn)度 -- writtenData/totalData

+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
    
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    if ([key isEqualToString:@"downloadProgress"]) {
        NSArray *affectingKeys = @[@"totalData", @"writtenData"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}
- (NSString *)downloadProgress{
    if (self.writtenData == 0) {
        self.writtenData = 10;
    }
    if (self.totalData == 0) {
        self.totalData = 100;
    }
    return [[NSString alloc] initWithFormat:@"%f",1.0f*self.writtenData/self.totalData];
}
  • 數(shù)組觀察
    self.person.dateArray = [NSMutableArray arrayWithCapacity:1];
    [self.person addObserver:self forKeyPath:@"dateArray" options:(NSKeyValueObservingOptionNew) context:NULL];

當(dāng)我們給數(shù)組賦值時(shí)梳玫,不能直接進(jìn)行addObject,而是需要valueForKey做一步轉(zhuǎn)換才能觀察到數(shù)組變化右犹,代碼如下:

    [[self.person mutableArrayValueForKey:@"dateArray"] addObject:@"1"];

2.2 KVO原理探究

官方文檔:

KVO 實(shí)現(xiàn)原理.png

根據(jù)文檔提示提澎,KVO是使用了isa-swizzling的方法。在為某個(gè)對(duì)象注冊(cè)觀察者時(shí)念链,將這個(gè)對(duì)象的isa指向了一個(gè)中間類盼忌,而不是原生的類积糯,所以,我們不能依靠isa確定類碴犬,而是應(yīng)該通過(guò)class去確定絮宁。

  • LGPerson.h
NS_ASSUME_NONNULL_BEGIN

@interface LGPerson : NSObject{
    @public
    NSString *name;
}
@property (nonatomic, copy) NSString *nickName;

@end

NS_ASSUME_NONNULL_END
  • LGPerson.m
#import "LGPerson.h"

@implementation LGPerson
- (void)setNickName:(NSString *)nickName{
    _nickName = nickName;
}
@end

我們分別對(duì)屬性nickName和成員變量name添加觀察者:

    self.person = [[LGPerson alloc] init];
    [self.person addObserver:self forKeyPath:@"nickName" options:(NSKeyValueObservingOptionNew) context:NULL];
    [self.person addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew) context:NULL];

當(dāng)點(diǎn)擊屏幕時(shí)對(duì)nickNamename進(jìn)行賦值,然后進(jìn)行觀察:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSLog(@"實(shí)際情況:%@-%@",self.person.nickName,self.person->name);
    self.person.nickName = @"KC";
    self.person->name   = @"jeffery";
}

#pragma mark - KVO回調(diào)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"%@",change);
}

KVO-檢測(cè)setter.png

通過(guò)輸出發(fā)現(xiàn)服协,打印出來(lái)的change只有KC绍昂,也就是說(shuō)只監(jiān)測(cè)到了nickName,而nickNamename的區(qū)別則在于是否實(shí)現(xiàn)了setter方法偿荷,也就是窘游,KVO實(shí)際上是對(duì)setter方法的監(jiān)聽(tīng)。
由官方文檔可知跳纳,在為對(duì)象注冊(cè)了觀察者時(shí)忍饰,改變了對(duì)象的isa指針,并將對(duì)象的isa指針指向了一個(gè)中間類,這時(shí)寺庄,我們不能通過(guò)isa去獲取類了艾蓝,而是應(yīng)該通過(guò)class,此時(shí)斗塘,我們?cè)谧?cè)觀察者后設(shè)置了一個(gè)斷點(diǎn)赢织,打印出當(dāng)前的類:
KVO_中間類.png

通過(guò)打印可以看到,在添加了觀察者之后馍盟,生成了LGPerson的子類NSKVONotifying_LGPerson于置,正如文檔所說(shuō),self.person改變了isa指針指向,接下來(lái)研究這個(gè)中間類實(shí)現(xiàn)了哪些方法:

#pragma mark - 遍歷方法-ivar-property
- (void)printClassAllMethod:(Class)cls{
    unsigned int count = 0;
    Method *methodList = class_copyMethodList(cls, &count);
    for (int i = 0; i<count; i++) {
        Method method = methodList[i];
        SEL sel = method_getName(method);
        IMP imp = class_getMethodImplementation(cls, sel);
        NSLog(@"%@-%p",NSStringFromSelector(sel),imp);
    }
    free(methodList);
}

在添加觀察者后添加方法[self printClassAllMethod:objc_getClass("NSKVONotifying_LGPerson")];將這個(gè)中間類的實(shí)現(xiàn)方法打印出來(lái):

KVO中間類所實(shí)現(xiàn)的方法打印.png

通過(guò)打印可以看到中間類實(shí)現(xiàn)了setNickName,class乓梨,dealloc,_isKVOA4個(gè)方法话速。既然setNickName方法有打印,那就說(shuō)明中間類重寫(xiě)了此方法芯侥。也就是說(shuō)尿孔,我們將nickName傳給了中間類,但是發(fā)生改變的卻是父類LGPerson筹麸,所以可能在這里面的某個(gè)時(shí)間有傳值操作活合。因?yàn)樘O(píng)果建議通過(guò)class來(lái)獲取類,所以這里中間類的重寫(xiě)是獲取原類的class物赶,dealloc是釋放方法白指,_isKVOA則是判斷是否為KVO類。
KVO移除觀察者isa變化.png

當(dāng)我們?cè)?code>dealloc中移除觀察者后酵紫,通過(guò)打印發(fā)現(xiàn)告嘲,·isa指針指向已經(jīng)由中間類NSKVONotifying_LGPerson只回了LGPerson错维,那么NSKVONotifying_LGPerson類是否會(huì)從內(nèi)存中移除呢?
KVO中間類存儲(chǔ).png
通過(guò)打印發(fā)現(xiàn)橄唬,當(dāng)我們移除了觀察者之后赋焕,生成的中間類會(huì)一直存儲(chǔ)在內(nèi)存當(dāng)中。當(dāng)我們?cè)俅芜M(jìn)入觀察時(shí)仰楚,就不需要重新開(kāi)辟內(nèi)存了隆判。
總結(jié)
1.當(dāng)對(duì)象在注冊(cè)了觀察者之后,其isa指針會(huì)由原生類指向中間類僧界;
2.KVO實(shí)際觀察的是setter方法侨嘀;
3.移除觀察者之后,實(shí)例對(duì)象的isa指針會(huì)指回原生類捂襟;
4.中間類在創(chuàng)建之后咬腕,會(huì)一直存在于內(nèi)存中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末葬荷,一起剝皮案震驚了整個(gè)濱河市涨共,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宠漩,老刑警劉巖煞赢,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異哄孤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)吹截,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)瘦陈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人波俄,你說(shuō)我怎么就攤上這事晨逝。” “怎么了懦铺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵捉貌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我冬念,道長(zhǎng)趁窃,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任急前,我火速辦了婚禮醒陆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘裆针。我一直安慰自己刨摩,他們只是感情好寺晌,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著澡刹,像睡著了一般呻征。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上罢浇,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天陆赋,我揣著相機(jī)與錄音,去河邊找鬼己莺。 笑死奏甫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的凌受。 我是一名探鬼主播阵子,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼胜蛉!你這毒婦竟也來(lái)了挠进?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤誊册,失蹤者是張志新(化名)和其女友劉穎领突,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體案怯,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡君旦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嘲碱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片金砍。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖麦锯,靈堂內(nèi)的尸體忽然破棺而出恕稠,到底是詐尸還是另有隱情,我是刑警寧澤扶欣,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布鹅巍,位于F島的核電站,受9級(jí)特大地震影響料祠,放射性物質(zhì)發(fā)生泄漏骆捧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一髓绽、第九天 我趴在偏房一處隱蔽的房頂上張望凑懂。 院中可真熱鬧,春花似錦梧宫、人聲如沸接谨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脓豪。三九已至巷帝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扫夜,已是汗流浹背楞泼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笤闯,地道東北人堕阔。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像颗味,于是被迫代替她去往敵國(guó)和親超陆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • KVC定義 KVC(Key-value coding)鍵值編碼浦马,就是指iOS的開(kāi)發(fā)中时呀,可以允許開(kāi)發(fā)者通過(guò)Key名直...
    SheIsMySin_72e7閱讀 380評(píng)論 0 0
  • iOS 底層探索: 學(xué)習(xí)大綱 OC篇[/p/9d73ee7aae64] 前言 在Key-Value Observi...
    歐德?tīng)栘己?/span>閱讀 260評(píng)論 0 2
  • KVO,全稱為Key-Value observing晶默,中文名為鍵值觀察谨娜,KVO是一種機(jī)制,它允許將其他對(duì)象的指定屬...
    Gumball_a45f閱讀 786評(píng)論 0 0
  • 《iOS底層原理文章匯總》[http://www.reibang.com/p/15af435341ce] 1.觀...
    一畝三分甜閱讀 342評(píng)論 0 0
  • KVC KVC定義 KVC(Key-value coding)鍵值編碼磺陡,就是指iOS的開(kāi)發(fā)中趴梢,可以允許開(kāi)發(fā)者通過(guò)K...
    jackyshan閱讀 51,903評(píng)論 9 200