首先定義一個測試用的類Test
Test.h
#import <Foundation/Foundation.h>
@interface Test : NSObject
@property (nonatomic, copy, readonly) NSString *testName;
@property (nonatomic, assign, readonly) NSInteger testAge;
- (instancetype)initWithTestName:(NSString *)name testAge:(NSInteger)age;
@end
Test.m
#import "Test.h"
@implementation Test
- (instancetype)initWithTestName:(NSString *)name testAge:(NSInteger)age{
self = [super init];
if (self) {
_testName = name;
_testAge = age;
}
return self;
}
@end
然后定義一個Test的類對象:
Test *test = [[Test alloc] initWithTestName:@"testName" testAge:22];
NSLog(@"%@",test.testName);
如果我們直接調用testName的setter方法拒担,test.testName = @"修改了";會直接報錯。提示這個屬性是只讀的。
報錯信息
如果我們使用KVC呢粟耻?
Test *test = [[Test alloc] initWithTestName:@"testName" testAge:22];
NSLog(@"-%@",test.testName);
[test setValue:@"修改了" forKey:@"testName"];
NSLog(@"---%@",test.testName);
輸出結果:
2017-05-17 14:20:36.404 iOS_readonlyTest[4076:115282] -testName
2017-05-17 14:20:36.404 iOS_readonlyTest[4076:115282] ---修改了
我們看到警儒,使用****KVC****成功修改了聲明為****readonly****的屬性椿肩。
如果我們不想讓 ****setValue:forKey:**** 方法改變對象的屬性值,那么重寫其類方法 ****+ (BOOL)accessInstanceVariablesDirectly**** 返回 NO (該方法默認返回 YES钩骇,即在不存在滿足條件的存取方法時比藻,允許直接訪問屬性對應的實例變量);在搜索實例變量時倘屹,會首先檢查帶下劃線的實例變量银亲,然后檢查不帶下劃線的實例變量。
****提示:****
重寫其類方法 ****+ (BOOL)accessInstanceVariablesDirectly**** 返回 NO的情況下纽匙,利用****KVC****修改聲明為****readonly****的屬性的值的時候會崩潰务蝠。我們可以重寫類的****setValue:forKey:**** 方法,判斷key是否是聲明為****readonly****的屬性烛缔,如果是直接返回馏段。
- (void)setValue:(id)value forKey:(NSString *)key{
if ([key isEqualToString:@"testName"]) {
NSLog(@"這個屬性不能被修改");
return;
}
[super setValue:value forKey:key];
}
2017-05-17 14:29:35.894 iOS_readonlyTest[4108:118687] -testName
2017-05-17 14:29:35.894 iOS_readonlyTest[4108:118687] 這個屬性不能被修改
2017-05-17 14:29:35.895 iOS_readonlyTest[4108:118687] ---testName