键值编码(key_value coing)是通过变量名读取和设置变量值的一种机制。变量的名字只是字符串而已。但这里将名字最为键(key)来引用。例如,假设有一个命名为Student 的类,该类有一个字符串类型的变量firstName。如下
@interface Student:NSObject{
NSString *firstName
}
......
如果设置Student实例的成员变量firstNAme。
Student* s=[Student alloc]init];
[s setValue:@"Larray"forKey:@"firstName'];
如果是取值的话
NSString *s=[s valueForKey@"firstName"];
其实在NObject中定义的set 和get 方法跟上面的setValue:forKey: &valueForKey:是一个道理,,尽管我们知道,通过变量名存取值并不是什么高新的技术,但威力不是 一般的强大。
键值编码
首先先创建一个工程,命名为KvcFun 前缀为KvcFun 打开KvcFun Delegate添加int类型的实例变量fido
@interface kvcFunDelegate:NSObject
int fido;
}
@propery (assign)IBOutlet NSWindow *window;
@end
???????这边的实例变量和属性有哪些区别;还有window为什么用assign
.m文件中,使用KVC方法创建init方法来设置和读取变量fido值。这使用了麻烦的方法,以下的例子只具有示例意义,实践中通常不这么做。
///////注意 由于kvc方法只能处理对象似的代码有点长,因此,当传入数值时,不是传一个int类型值,而是创建了一个NSNUmber 对象。将这个方法添加到KvcFunAppDelegate.m中。
-(id)init{
if([self=super init]){
[self setValue:[NSNumber numberWithInt:5]forKey:@"ifdo"];
NsNumber *n=[self valueForKey:@"fido"];
Nslog(@"fido=%@",n);
}
return self;
}
在将NSNumber对象用于设置fido值之前,将由Kvc机制自动将NSNumber转为int类型。编译运行程序,当出现空白窗口时,,fido=5 也出现在控制台上。
假如已经使用accessor 来设置和获取fido的值,那么,就会用上它,但是必须进行正确的命名,如getter 必须命名为fido 而setter 必须命名为setFido:。注意,这不仅仅是习惯问题。假如开发者设置的accessor 方法的名字不规范,这些方法将不会被KVC方法调用。将fido&setFido:方法添加到KVCFunApp-Delegate.m中
-(int)fido {
NSLog(@"_fido is returing%d",fido);
return fido;
}
-(void)setfido:(int)x{
NSlog(@"-setFido:is called with%d",x);
fido=x;
}
在KvcFunAppDelegate.h中声明上述方法。
-(int)fido;
-(void)setFido:(int)x;
编译运行程序,accessor方法就要被调用了。??????accessor是什么
=======================================
绑定
我们添加一个滑动条到窗口,绑定该滑动条的值为fido. coco中有很多图形对象都使用绑定,当开发者绑定一个键(如前面的fido)到一个图形对象的属性(如它的值或字体颜色)上时。显示视图将自动让它们同步。现在,,添加一个滑动条懂啊窗口,绑定该滑动条的值为fido,来看看Kvc是怎样让它们同步的。
打开MainMenu。xib,,拖拽一个滑动条到窗口上,在Attributes Inspector 中设置滑动条为Continuous然后在Bingdings Inspector 中,将滑动条的值绑定到KvcFunAppDelegate实例的fido键上
编译运行程序,滑动条使用ValueForKey:来获取它的初始值(这触发了fido方法)。当移动滑动条的时候,调用setValue:forKey:来更新fido的值(这触发了setFido:方法)
============================================
键值观察Kvo
假如fido的值不是被滑动条而是其他对象改变之后会发生什么呢?滑动条是如何知道它有一个新的值?
当滑动条被创建后,它将告诉KVCFunAppDelegate对象,它正在观察fido的键。当fido的值被accessor方法或者kvc改变之后,KvcFunAppDelegate就发送一个消息给滑动条,通知fido已经改了。。。我们在窗口中添加一个文本标签。并将其值绑定到KVcFunAPP_Delegate的fido键
这样的话,,编译运行程序。当移动滑动条的时候,就调用setFido:方法。通知文本框fido的值改变了,,文本框对象调用valueForKey:来获取fido新的值,于是,fido方法就被调用了。
=================================================
是对象的键值可观察
前面提到,当使用Accessors方法和键-值编码方法改变键德值。观察者将自动被通知有变化产生。那么如果直接改变变量的值又会发生什么呢?
打开KvcFunAppDelegate.h 声明一个新的action方法。
-(ibAction)incrementFido:(id)sender
-(ibActiono)incrementFido:(id)sender{
fido++;
NSlog(@"fido is now%d",fido);
}
我们应该是希望单击的时候按钮会移动,文本框也将进行更新。但是遗憾的是,什么都没有发生,,再次编译,运行程序。。假如想直接更改变量,,就需要显示的通知观察者。。。所以这个时候就要重新修改incrementFido的方法了
-(ibActiono)incrementFido:(id)sender{
[self willChangeValueForkey:@"fido'];
fido++;
NSlog(@"fido is now%d",fido);
[self didChangeValueForKey:@"fido"];
}
还有两种可行的解决方法,首先是键—值编码
-(ibActiono)incrementFido:(id)sender{
Nsnumber *n =[self valueForKey:@"fido"];
NsNumber *npp=[NSNumber numberWithInt:[n intValue]+1];
[self setValue:npp forKey:@]
//fido++;
NSlog(@"fido is now%d",fido);
}
第二种方法是使用accessor方法来改变fido的值
-(ibaction)incrementFido:(id)sender{
[self setFido:[self fido]+1];
}
========================================
Property
现在花很多时间在Accessor方法上,,因此,Object—c给程序员使用点标记方法来调用accessors的选择。oc程序员关于点标记法是否是一个好的功能有着不同的观点。有些认为它是句法上的提高。既可以提升消息发送的功能,由不同于在结构体中赋值。property 用很好的方式来解决了这个问题一般都是这样声明的
Porperty(readWrite,assign)int fido;
这一行代码就相当于声明了setFido:和fido。
在.m文件中也可以可以使用@synthesize来实现accessor方法。并且删除了setFido&fido的accessor
属性可包含readwrite 和readonly两种。。默认的是readwrite.设置为readonly的属性没有setter方法。
Assign(默认)创建一个赋值语句,这个属性通常用于标量变量。而非指针类型变量(如整形和浮点型)
Strong 说明Property是强引用类型,,让对象在指针设置时就一直被指向,避免重新分配,特别针对Arc代码。如果没有使用ARC,则与retain属性等同。
weak 表明是弱引用于assign相似,除了在指向的对象呗释放的情况下,property 将被设置为nil,,只支持ARC. copy创建新值的复制,,这个属性经常用于字符创及其他mutable子类情况下的property
属性还可以包括非原子行的,,假如应用程序是多线程的,,那么setter方法为原子操作就很重要,,就是说,,setter方法在一个线程的执行与同一setter方法在另一个线程的执行不会冲突。。默认情况下,@syntheszie 操作将产生这个property的accessor操作,包括使用锁来确保同一时刻只有一个setter在执行。创建和使用锁会带来一些额外的开销。假如开发者能够确认property的accessor不需要原子操作,,可将属性设置为非原子性减少开销。
假如property名字刚好和成员变量一样的话可使用如下代码;
@synthesize fido
假如是有下划线则是@synthesize fido=_fido;
=====================
键路径
对象之间的关系通常是网络的,,例如,,一个人有个配偶,,配偶有一个踏板车,,踏板车又有一个型号,,踏板车又有一个型号
为了选中某人的配偶的踏板车的型号,可使用的建路径为:
NSString *mm=[SelectedPerson valieForKeyPath:@"spouse.scooter.modelName"];
假如有一个Person对象的Array,便可使用键路径来得到他的平均ExpectedRise
NSNumber *theAverage=[employees valueForKeyPath:@"@avg.expectedRaise'];
常用的操作符是@avg @count@max@min@sum
若希望在文本框中显示一个arraycoutroller 管理对象的平均加薪期望,可如下创建绑定
[textField bind:@"value"toObject:employeeController withKeyPath:@"[email protected]"
options:nil];
在interfaBuilde中创建绑定就容易的多,,使用unbind:可删除绑定
[textFiled unbind:@"value";]
==============================
键值观察
文本框究竟是怎样成为一个fido键的观察者呢?
[theAppDelegate addObserver:self
forkrypath:@"fido"
options:NskeyValueChangeOldKey
context:somePointer
];
这个方法的意思是option和context决定fido改变时将哪些额外的数据和消息一起发送出去触发的过程是这个样子的
-(void) observerValueForKeyPath:(NSstring *)keypath
ofObject:(id)object
change:(NsDictionary *)change
context:(void *)context
这个例子中的keyPath应该是@”fido‘,object应该是KvcFunAppDelegate
context则是在其成为观察者时提供的指针somePoint,change是保存fido旧值和新值得字典(键值对的集合);