键值编码是通过变量名读取和设置变量名的一种机制

变量的名字只能是字符串,但这里将名字作为键来引用。

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;