键-值编码和键值观察
键值编码是通过变量名读取和设置变量名的一种机制
变量的名字只能是字符串,但这里将名字作为键来引用。
setValue:forkey
valueForKey
两个方法都是在NSObject中定义的
7.1 键值编码
// AppDelegate.h
@interface AppDelegate : NSObject <NSApplicationDelegate> {
int fido ;
}
// AppDelegate.m
-(id) init {
self = [super init] ;
if (self) {
[ self setValue:[NSNumber numberWithInt:5] forKey:@"fido"] ;
NSNumber * n = [self valueForKey:@"fido"] ;
NSLog(@"fido = %@" ,n) ;
}
return self ;
}
假如已经使用 accessor来设置和获取fido的值,
// AppDelegate.h
-(int) fido ;
-(void) setFido:(int)x ;
// AppDelegate.m
-(int) fido {
NSLog(@"fido is returning %d" ,fido) ;
}
-(void) setFido:(int)x {
NSLog(@"setFido: is called with %d" , x) ;
fido = x ;
}
7.2 绑定
Cocoa 很多图形对象都是用了绑定,当开发者绑定了一个键(前面的fido),到一个图形的的属性(如它的值和字体颜色)上时,显示视图会自动让他们同步
编译程序运行,滑动条使用valueForKey 来获得他的初始值,(这里就出发了fido方法)
当移动滑动条时候,调用setValue:Forkey来更新的fido的值,(着出发了setFido方法)
7.3 键-值观察KVO
假如fido的值不是被滚动条而是其他对象改变之后发生的呢 ?滑动条施如何知道他有一个新的值。 当滚动条创建好,他将考苏AppDelegate对象,他正在观察fido对象,当fido的值被accessor方法或者看KVC改变后,AppDelegate就发送一个一消息给滚动条,通知fido已经改变。
7.4 使对象的值可观察
前面提到,当使用accessors方法 和键-值编码的方法来改变键的值时,观察者将自动被通知变化产生,那如果直接改变便来的值又会发生什么呢? // 演示是对象的值可以被观察
- (IBAction)incrementFido:(id)sender {
[self willChangeValueForKey:@"fido"] ;
fido++ ;
NSLog(@"fido is now %d" ,fido) ;
[self didChangeValueForKey:@"fido"] ;
}
另外的2种方法
使用键值编码
- (IBAction)incrementFido:(id)sender {
NSNumber *n = [self valueForKey:@"fido"] ;
NSNumber *npp = [NSNumber numberWithInt:[n intValue] + 1] ;
[self setValue:npp forKey:@"fido"] ;
}
使用 accessor方法改变fido的值
-(IBAction)incrementFido:(id)sender {
[self setFido:[self fido] + 1] ;
}
7.5 Properties
Objective-C 给程序员使用点标记的方法来调用accessors的选择
例如 指针指向一个对象,该对象有一个getter方法rex
NSLog(@"Rover's rex is %@" , rever.rex) ;
调用setRex:
rover.rex = [NSDate date] ;
Objective-C 程序员关于点的标记法是否是一个好的功能有着不同的观点,有些人为他是句法的上的提高,即可以提升消息发送的功能,有不同于在结构体中的复制,
其他程序员则认为标志风险大于他带来的便利,为了便于理解,本书不适用点的标记法。
那accessor方法怎么样呢 ?假如有12个成员变量,是不是真的需要些12个setter方法和12个getter方法?
Properties提高了一个非常理想的方法来减少代码
// AppDelegate.h
@property(readwrite, assign) int fido ;
// AppDelegate.m
@implementation AppDelegate
@synthesize fido ;
@property (attribute) type name
属性科包括readwrite和readonly两种,默认readwrite。设置为readonly的property没有setter方法
assign默认创建一个赋值语句,这个属性通常用于标量变量,而为指针类型的变量
strong 说明property是强引用类型,让对象在指针设置就一直被指向,避免重新分配,特别针对ARC代码,如果没有使用ARC,则与retain属性相同。
weak表示弱引用,除了在指向的对象被释放的情况下,property将被设置为nil。支持ARC方式。
copy 常见新值的复制,这个属性常用于字符串及mutable子类情况下property
属性还可以 包括非原子性的。 假如使用应用程序是多线程的,那么setter方法与原子操作就很重要。默认synthesize操作将产生这个property的accessor操作,包括使用锁来确定保同一时刻只有一个setter在执行,创建和使用锁带来一些额外的开销,假如开发者能够确实不需要使用原子操作,可将属性设置为非原子性减少开销。
@synthesize
假如property的名字和成员变量一样,可使用如下的代码
@synthesize fido ;
加入开发者倾向在变量命名是使用前置(XCODE就倾向使用下划线前缀)可使用下面来制定成员变量
@synthesize fido=_fido;