KVC的查詢順序

一、自定義一個(gè)TestObject類,測(cè)試KVC取值的查詢順序

以下是TestObject的源碼,你沒看錯(cuò),就是這樣一個(gè)沒有實(shí)現(xiàn)任何方法,沒有任何屬性的類。我們用TestObject類來探究KVC取值的查詢順序。

.h
#import <Foundation/Foundation.h>

@interface TestObject : NSObject

@end

.m
#import "TestObject.h"

@interface TestObject()

@end

@implementation TestObject

@end


KVC不論取值還是賦值都會(huì)先去查詢相應(yīng)的方法,如果一個(gè)方法都沒找到,再按規(guī)則去找成員變量。

我們?cè)诖a中調(diào)用KVC的取值:
TestObject *obj = [TestObject new];
    
NSString *name = [obj valueForKey:@"name"];
    
NSLog(@"%@",name);
在未聲明屬性,未實(shí)現(xiàn)任何方法,類中無對(duì)應(yīng)成員變量時(shí)使用valueForKey:會(huì)直接崩潰。??(大家都知道)
直接崩潰.png

1.KVC取值查找的第一個(gè)方法getName

#import "TestObject.h"

@interface TestObject()

@end

@implementation TestObject

- (NSString *)getName {
    
    return @"getName";
}

@end

當(dāng)我們?cè)?code>TestObject類中實(shí)現(xiàn)了getName方法后,valueForKey:就不會(huì)再崩潰,而是調(diào)用getName方法,獲取返回值。


控制臺(tái)打?。?br>

image.png

2.TestObject類中如果沒有實(shí)現(xiàn)getName方法,KVC會(huì)查找第二個(gè)方法name,如果有getName方法,就不會(huì)繼續(xù)往下查找了,因?yàn)?code>getName方法已經(jīng)生效了。

#import "TestObject.h"

@interface TestObject()

@end

@implementation TestObject

//- (NSString *)getName {
//
//    return @"getName";
//}

- (NSString *)name {
    
    return @"name";
}



控制臺(tái)打?。?br>

image.png

3.TestObject類中如果沒有實(shí)現(xiàn)getName方法,也沒有實(shí)現(xiàn)name方法,KVC會(huì)查找第三個(gè)方法isName。

#import "TestObject.h"

@interface TestObject()

@end

@implementation TestObject

//- (NSString *)getName {
//
//    return @"getName";
//}
//
//- (NSString *)name {
//
//    return @"name";
//}

- (NSString *)isName {
    
    return @"isName";
}



控制臺(tái)打印:

image.png

4.若前三個(gè)方法都沒有實(shí)現(xiàn),KVC會(huì)查找第四個(gè)方法_name

#import "TestObject.h"

@interface TestObject()

@end

@implementation TestObject

//- (NSString *)getName {
//
//    return @"getName";
//}
//
//- (NSString *)name {
//
//    return @"name";
//}

//- (NSString *)isName {
//
//    return @"isName";
//}

- (NSString *)_name {
    
    return @"_name";
}



控制臺(tái)打?。?br>

image.png

5.如果上述方法都沒實(shí)現(xiàn),接下來KVC會(huì)將要取的值看做數(shù)組,調(diào)用下面的方法:

- (NSUInteger)countOfName(必須實(shí)現(xiàn))
以下兩個(gè)二選一
- (id)objectInNameAtIndex:(NSUInteger)index(優(yōu)先查找)
- (id)nameAtIndexes:(id)indexes(其次查找)

6.以上方法都沒有找到,那么KVC會(huì)按照集合(NSSet)來處理,調(diào)用下面三個(gè)方法:

- (NSUInteger)countOfName(必須實(shí)現(xiàn))
- (id)enumeratorOfName(必須實(shí)現(xiàn))
- (id)memberOfName:(id)name(必須實(shí)現(xiàn))

7.方法查詢到此為止,如果上述方法都沒有查找到,接下來會(huì)按照順序查找成員變量:

_name;
_isName;
name;
isName;

  • 第一次調(diào)用:
源碼:
#import "TestObject.h"

@interface TestObject(){
    NSString *_name;
    NSString *_isName;
    NSString *name;
    NSString *isName;
}

@end

@implementation TestObject

- (instancetype)init
{
    self = [super init];
    if (self) {
        _name = @"ivar : _name";
        _isName = @"ivar : _isName";
        name = @"ivar : name";
        isName = @"ivar : isName";
    }
    return self;
}
控制臺(tái):
image.png
  • 當(dāng)類中沒有_name成員變量時(shí),我們進(jìn)行第二次調(diào)用:
源碼:
#import "TestObject.h"

@interface TestObject(){
//    NSString *_name;
    NSString *_isName;
    NSString *name;
    NSString *isName;
}

@end

@implementation TestObject

- (instancetype)init
{
    self = [super init];
    if (self) {
//        _name = @"ivar : _name";
        _isName = @"ivar : _isName";
        name = @"ivar : name";
        isName = @"ivar : isName";
    }
    return self;
}
控制臺(tái):
image.png
  • 當(dāng)類中沒有_isName成員變量時(shí),我們進(jìn)行第三次調(diào)用:
源碼:
#import "TestObject.h"

@interface TestObject(){
//    NSString *_name;
//    NSString *_isName;
    NSString *name;
    NSString *isName;
}

@end

@implementation TestObject

- (instancetype)init
{
    self = [super init];
    if (self) {
//        _name = @"ivar : _name";
//        _isName = @"ivar : _isName";
        name = @"ivar : name";
        isName = @"ivar : isName";
    }
    return self;
}
控制臺(tái):
image.png
  • 當(dāng)類中沒有name成員變量時(shí),我們進(jìn)行第四次調(diào)用:
源碼:
#import "TestObject.h"

@interface TestObject(){
//    NSString *_name;
//    NSString *_isName;
//    NSString *name;
    NSString *isName;
}

@end

@implementation TestObject

- (instancetype)init
{
    self = [super init];
    if (self) {
//        _name = @"ivar : _name";
//        _isName = @"ivar : _isName";
//        name = @"ivar : name";
        isName = @"ivar : isName";
    }
    return self;
}

控制臺(tái):
image.png

8.如果上述方法和成員變量都沒找到,KVC會(huì)走最后一步(id)valueForUndefinedKey:(NSString *)key,若次方法依然沒有找到,程序崩潰。


二、定義一個(gè)TestObject2類,測(cè)試KVC賦值的查詢順序

以下是TestObject2的源碼:
.h
#import <Foundation/Foundation.h>

@interface TestObject2 : NSObject

@end

.m
#import "TestObject2.h"

@interface TestObject2()

@end

@implementation TestObject2

@end

我們?cè)诖a中調(diào)用KVC的賦值:
TestObject2 *obj = [TestObject2 new];
    
[obj setValue:@"TestString" forKey:@"name"];

在未聲明屬性,未實(shí)現(xiàn)任何方法,類中無對(duì)應(yīng)成員變量時(shí)使用setValue: forKey:會(huì)直接崩潰。??(這個(gè)大家也知道)

1.KVC賦值查找的第一個(gè)方法setName:

#import "TestObject2.h"

@interface TestObject2()

@end

@implementation TestObject2

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

@end



控制臺(tái)打?。?br>

image.png

2.如果setName:沒有找到,KVC會(huì)查找第二個(gè)方法_setName:

#import "TestObject2.h"

@interface TestObject2()

@end

@implementation TestObject2

//- (void)setName:(NSString *)name {
//    NSLog(@"%s\t%@",__func__,name);
//}

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

@end



控制臺(tái)打印:

image.png

3.如果前面兩個(gè)方法都沒有找到,接下來會(huì)調(diào)用(BOOL)accessInstanceVariablesDirectly,如果返回NO則不去查找成員變量,如果返回YES則接下來按照下列順序規(guī)則查找成員變量。

_name;
_isName;
name;
isName;

  • 第一次調(diào)用:
源碼:
#import "TestObject2.h"

@interface TestObject2(){
    NSString *_name;
    NSString *_isName;
    NSString *name;
    NSString *isName;
}
@end

@implementation TestObject2

+ (BOOL)accessInstanceVariablesDirectly {
    return YES;
}

- (void)printName {
    NSLog(@"_name : %@",_name);
    NSLog(@"_isName : %@",_isName);
    NSLog(@"name : %@",name);
    NSLog(@"isName : %@",isName);
}

@end
控制臺(tái):
image.png
  • 當(dāng)類中沒有_name成員變量時(shí),我們進(jìn)行第二次調(diào)用:
源碼:
#import "TestObject2.h"

@interface TestObject2(){
//    NSString *_name;
    NSString *_isName;
    NSString *name;
    NSString *isName;
}
@end

@implementation TestObject2

+ (BOOL)accessInstanceVariablesDirectly {
    return YES;
}

- (void)printName {
//    NSLog(@"_name : %@",_name);
    NSLog(@"_isName : %@",_isName);
    NSLog(@"name : %@",name);
    NSLog(@"isName : %@",isName);
}

@end
控制臺(tái):
image.png

后面兩個(gè)成員變量我就不貼出來了,以此類推。

4.如果上述方法和成員變量都沒找到,并且(BOOL)accessInstanceVariablesDirectly返回NO,KVC會(huì)走最后一步setValue:(id)value forUndefinedKey:(NSString *)key,若次方法依然沒有找到,程序崩潰。


以上均為手打,如果錯(cuò)誤敬請(qǐng)指正交流。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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