一、自定義一個TestObject類,測試KVC取值的查詢順序
以下是TestObject
的源碼,你沒看錯垃你,就是這樣一個沒有實(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不論取值還是賦值都會先去查詢相應(yīng)的方法,如果一個方法都沒找到少辣,再按規(guī)則去找成員變量凌摄。
我們在代碼中調(diào)用KVC的取值:
TestObject *obj = [TestObject new];
NSString *name = [obj valueForKey:@"name"];
NSLog(@"%@",name);
在未聲明屬性,未實(shí)現(xiàn)任何方法漓帅,類中無對應(yīng)成員變量時使用valueForKey:
會直接崩潰锨亏。??(大家都知道)
1.KVC取值查找的第一個方法getName
#import "TestObject.h"
@interface TestObject()
@end
@implementation TestObject
- (NSString *)getName {
return @"getName";
}
@end
當(dāng)我們在TestObject
類中實(shí)現(xiàn)了getName
方法后,valueForKey:
就不會再崩潰忙干,而是調(diào)用getName
方法器予,獲取返回值。
控制臺打泳杵取:
2.TestObject
類中如果沒有實(shí)現(xiàn)getName
方法乾翔,KVC會查找第二個方法name
,如果有getName
方法施戴,就不會繼續(xù)往下查找了反浓,因?yàn)?code>getName方法已經(jīng)生效了萌丈。
#import "TestObject.h"
@interface TestObject()
@end
@implementation TestObject
//- (NSString *)getName {
//
// return @"getName";
//}
- (NSString *)name {
return @"name";
}
控制臺打印:
3.TestObject
類中如果沒有實(shí)現(xiàn)getName
方法雷则,也沒有實(shí)現(xiàn)name
方法辆雾,KVC會查找第三個方法isName
。
#import "TestObject.h"
@interface TestObject()
@end
@implementation TestObject
//- (NSString *)getName {
//
// return @"getName";
//}
//
//- (NSString *)name {
//
// return @"name";
//}
- (NSString *)isName {
return @"isName";
}
控制臺打忧缮簟:
4.若前三個方法都沒有實(shí)現(xiàn)乾颁,KVC會查找第四個方法_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";
}
控制臺打右照弧:
5.如果上述方法都沒實(shí)現(xiàn)英岭,接下來KVC會將要取的值看做數(shù)組,調(diào)用下面的方法:
- (NSUInteger)countOfName
(必須實(shí)現(xiàn))
以下兩個二選一
- (id)objectInNameAtIndex:(NSUInteger)index
(優(yōu)先查找)
- (id)nameAtIndexes:(id)indexes
(其次查找)
6.以上方法都沒有找到湿右,那么KVC會按照集合(NSSet
)來處理诅妹,調(diào)用下面三個方法:
- (NSUInteger)countOfName
(必須實(shí)現(xiàn))
- (id)enumeratorOfName
(必須實(shí)現(xiàn))
- (id)memberOfName:(id)name
(必須實(shí)現(xiàn))
7.方法查詢到此為止,如果上述方法都沒有查找到毅人,接下來會按照順序查找成員變量:
_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;
}
控制臺:
-
當(dāng)類中沒有
_name
成員變量時吭狡,我們進(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;
}
控制臺:
-
當(dāng)類中沒有
_isName
成員變量時,我們進(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;
}
控制臺:
-
當(dāng)類中沒有
name
成員變量時丈莺,我們進(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;
}
控制臺:
8.如果上述方法和成員變量都沒找到划煮,KVC會走最后一步(id)valueForUndefinedKey:(NSString *)key
,若次方法依然沒有找到缔俄,程序崩潰弛秋。
二、定義一個TestObject2
類俐载,測試KVC賦值的查詢順序
以下是TestObject2
的源碼:
.h
#import <Foundation/Foundation.h>
@interface TestObject2 : NSObject
@end
.m
#import "TestObject2.h"
@interface TestObject2()
@end
@implementation TestObject2
@end
我們在代碼中調(diào)用KVC的賦值:
TestObject2 *obj = [TestObject2 new];
[obj setValue:@"TestString" forKey:@"name"];
在未聲明屬性蟹略,未實(shí)現(xiàn)任何方法,類中無對應(yīng)成員變量時使用setValue: forKey:
會直接崩潰遏佣。??(這個大家也知道)
1.KVC賦值查找的第一個方法setName:
#import "TestObject2.h"
@interface TestObject2()
@end
@implementation TestObject2
- (void)setName:(NSString *)name {
NSLog(@"%s\t%@",__func__,name);
}
@end
控制臺打油诰妗:
2.如果setName:
沒有找到,KVC會查找第二個方法_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
控制臺打印:
3.如果前面兩個方法都沒有找到状婶,接下來會調(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
控制臺:
-
當(dāng)類中沒有
_name
成員變量時空闲,我們進(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
控制臺:
后面兩個成員變量我就不貼出來了,以此類推走敌。