iOS中的关键值编码与访问器方法
我试图理解与KVC相关的Objective C中的一些理论部分。 以下是我所做的例子。
我有类调用Cookie,它有一个像下面的属性
@property NSString *name;
接下来,我有另一个类调用Person,它有以下属性
@property Cookie *cookie;
内部Person实现文件
#import "Cookie.h" - (id)init { self = [super init]; if (self) { _cookie = [[Cookie alloc] init]; } return self; }
在我的ViewContrtoller中,我可以编写以下两个选项来获得相同的结果。
使用KVC:
[me valueForKeyPath:@"cookie.name"]
使用访问器方法:
[[me cookie] name]
为了编写访问器方法,我不得不导入Cookie类,但在使用KVC时不需要。
除此之外,使用KVC代替或使用访问器方法有什么好处? 是否有任何性能问题或安全问题,良好的编码习惯或其他好处?
我发现KVC非常方便的一种情况是,当我不得不对某个集合对象执行某种操作时,例如find某个特定值的平均值。具体而言,我使用了KVC操作符。
例如
[myDict valueForKey:@"gamePoints"] valueForKey:@"doubleValue"] valueForKeyPath:@"@max.self"];
这将帮助您从字典/对象数组中find属性“gamePoints”的最大值。
这是一个很好的文章,由马特汤普森希望这有助于你在找什么。
根据苹果文件 :
尽pipe键值编码是有效的,但它增加了一个间接的级别,比直接方法调用稍慢。 只有当您可以从其提供的灵活性中受益时,才应使用键值编码。
但我认为这可能有些过于谨慎了; 我怀疑你不需要太担心,除非你的应用程序对性能非常敏感。
在这种情况下使用KVC没有特别的好处。 一般来说,当你可以的时候,你应该更喜欢使用访问器或者点语法(比如me.cookie.name
)。
KVC是用来当您想要访问的属性的名称是dynamic的。 在编译时不知道。 它来自数据(包括一个NIB,在OS X绑定的情况下)或被计算。
除了给定的答案(+1)之外,您还可以在Xcode中获得标识符完成的优势,从而降低错别字的可能性。 如果你在语义上使用它,导入这个类是一个很好的策略。 把它看作是“我使用的东西”,这可以帮助你理解你的代码。
使用KVO的好地方是unit testing。 当你有以下的类接口:
@interface ServerCommunicationManager : NSObject { NSMutableArray *commandQueue; BOOL chanelFree; } - (void)send:(NSDictionary *)dictionary; @end
然后发送执行:
- (void)send:(NSDictionary *)json { if ( YES == chanelFree ) { // send command immediately } else { [commandQueue addObject:json]; } }
如果我们想testing发送实现而不暴露commandQueue(因此没有制动封装),我们可以使用KVO:
-(void)testSend { ServerCommunicationManager* aTestObj = [ServerCommunicationManager new]; //prepare conditions [aTestObj setValue:@NO forKey:@"channelFree"]; NSDictionary* dummyReq = @{}; [aTestObj send:dummyReq]; //check commandQueue state XCTAssertEqualObjects(dummyReq, [[aTestObj valueForKey:@"commandQueue"] firstObject]); XCTAssertTrue(1 == [[aTestObj valueForKey:@"commandQueue"] count]); //more tests }
KVC允许你做KVO:也就是说,如果你正在观察一个variables,当且仅当这个变化发生在KVC上的时候,你才会被通知它的变化。 如果你直接使用setter修改一个variables,你将不会被通知它的变化