KVC
常用方法
//赋值
- (void)setValue:(nullable id)value forKey:(NSString *)key;
//取值
- (nullable id)valueForKey:(NSString *)key;
参数key类型NSString value类型id(nullable 可以为nil)
eg:
MyClass
#import "MySubclass.h"
@interface MyClass : NSObject
@property (nonatomic, copy) NSString *myClassName;
@property (nonatomic, strong) MySubclass *mySubclass;
@end
@implementation MyClass
@end
MySubclass
@interface MySubclass : NSObject
@property (nonatomic, copy) NSString *MySubclassName;
@end
@implementation MySubclass
@end
MyClass *myClass = [[MyClass alloc]init];
NSLog(@"myClass.myClassName: %@",myClass.myClassName);
[myClass setValue:@"name" forKey:@"myClassName"];
NSLog(@"myClass.myClassName: %@",[myClass valueForKey:@"myClassName"]);
修赋值和取值成功
对不存在的key进行赋值和取值
MyClass *myClass = [[MyClass alloc]init];
NSLog(@"don't exit variable: %@",[myClass valueForKey:@"don't exit"]);
[myClass setValue:@"name" forKey:@"don't exit"];
对不存在的key进行操作就是抛出异常:
- (nullable id)valueForKey:(NSString *)key; 对应异常
'NSUnknownKeyException', reason: '[<MyClass 0x17402e840> valueForUndefinedKey:]: this class is not key value coding-compliant for the key don't exit.'
- (void)setValue:(nullable id)value forKey:(NSString *)key;对应异常
'NSUnknownKeyException', reason: '[<MyClass 0x170026f80> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key don't exit.'
处理方式
- 不对不存在的成员变量进行操作
- 通过以下方法进行操作
@implementation MyClass
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
NSLog(@"class: %@, cmd: %@, key:%@",self.class, NSStringFromSelector(_cmd), key);
}
-(id)valueForUndefinedKey:(NSString *)key{
NSLog(@"class: %@, cmd: %@, key: %@",self.class ,NSStringFromSelector(_cmd) , key);
return nil;
}
@end
通过这两个方法系统就不会抛异常,在这两个方法里对key不存在情况特殊处理。
禁止访问class的成员变量
//default return YES, return NO 不能访问成员变量
+(BOOL)accessInstanceVariablesDirectly{
return NO;
}
通过成员变量操作就会抛NSUnknownKeyException异常
MyClass *myClass = [[MyClass alloc]init];
[myClass setValue:@"name" forKey:@"_myClassName"];
'NSUnknownKeyException', reason: '[<MyClass 0x17003d3a0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key _myClassName.'
重写setter/getter
key为属性名 key为成员变量则操作失败
在MyClass 中
-(void)setMyClassName:(NSString *)myClassName{
NSLog(@"setter %@", myClassName);
}
-(NSString *)myClassName{
return @"getter name";
}
进行key的赋值和取值操作!
进行赋值是会调用setter方法
进行取值是会调用getter方法
key的多个名称
对key赋值取值顺序依次为:
_key, _isKey, key, isKey
interface MyClass (){
NSString *_myClassName;
NSString *_isMyClassName;
NSString *myClassName;
NSString *isMyClassName;
}
@end
@implementation MyClass
-(instancetype)init{
self = [super init];
if (self) {
_myClassName = @"_myClassName";
_isMyClassName = @"_isMyClassName";
myClassName = @"myClassName";
isMyClassName = @"isMyClassName";
}
return self;
}
@end
MyClass *myClass = [[MyClass alloc]init];
NSLog(@"myClass.myClassName: %@",[myClass valueForKey:@"myClassName"]);
按顺序注释掉key的取值顺序可证
若按照对应的名称取值
MyClass *myClass = [[MyClass alloc]init];
NSLog(@"myClass.myClassName: %@",[myClass valueForKey:@"_myClassName"]);
NSLog(@"myClass.myClassName: %@",[myClass valueForKey:@"_isMyClassName"]);
NSLog(@"myClass.myClassName: %@",[myClass valueForKey:@"myClassName"]);
NSLog(@"myClass.myClassName: %@",[myClass valueForKey:@"isMyClassName"]);
除了key为原名称进行取值 其他情况下取值是对应的值.
key为原名称按照顺序进行取值
同理 setValue操作也是如此
补充
根据点语法keypath操作
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- (nullable id)valueForKeyPath:(NSString *)keyPath;
示例
MyClass *myClass = [[MyClass alloc]init];
myClass.mySubclass = [[MySubclass alloc]init];
myClass.mySubclass.MySubclassName = @"oldName";
[myClass setValue:@"newName" forKeyPath:@"mySubclass.MySubclassName"];
NSLog(@"myClass.mySubclass.MySubclassName: %@",[myClass valueForKeyPath:@"mySubclass.MySubclassName"]);
集合运算符
KVC Collection Operators