定义: 把字典中的数据使用模型来保存。新建一个类,根据字典中键值对,来编写这个类中的属性,将来用这个类的对象的属性来保存字典中每个键对应的值。
为什么要用字典去转模型:
0>写代码的时候字典的键没有智能提示,但是模型的属性可以有智能提示
1>"键"是字符串,如果写错了,编译器不报错(在编译的时候不报错),运行时可能出错,出错了很难找错。
2>使用"模型"可以更方便的使用面向对象的3大特(封装、继承、多态)性进行扩展。
3>将来的这个"模型"可能会在很多地方被用到(比如有很多个控制器都会使用这个模型),那么每次用到模型的地方都需要写一次把字典中的数据赋给模型属性的代码,此时如果把这些赋值语句封装到模型内部,会大大简化了使用复杂度与代码量。
字典转模型需要修改哪里的代码:
1>创建一个模型类
2>在懒加载数据的时候,(或者网络请求数据后)把加载到的数据都放到模型对象中,然后再把模型对象放到数组中。
KVC: (键值编码)
定义: 在对象创建完成之后,动态(牵扯到运行时)的给对象的属性赋值
KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属性。而不是通过调用Setter、Getter方法访问。
在OC的API中:
@interfaceNSObject(NSKeyValueCoding) // 非正式协议
@end
用法:
1>基本取值赋值
赋值: [对象:setValue:forkey:]
fu值:[对象:valueforKey]
2> 因为类key反复嵌套,所以有个keyPath的概念,keyPath就是用.号来把一个一个key链接起来,这样就可以根据这个路径访问下去
3>KVC还有一个很重要的特点,自动装箱拆箱功能。这在ObjC中是仅有的,其他情况下均需要使用比如NSNumber来手动拆装箱的。
装箱:把值类型转换成引用类型 若是int 转换成NSNumer或者NSString
拆箱:将引用类型转换成值类型 与上面想反
4> KVC 还可以对NSArray和NSSet 进行赋值
5> 通过字典去进行赋值(不要忘了重写那个方法)
[对象setValuesForKeysWithDictionary:dict]
// 若对象没有值
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
6> 在运行时给私有属性或者可读属性进行赋值
//注意:(解档和归档的方法不是KVC,而是NSCoding这个协议)
@protocolNSCoding
- (void)encodeWithCoder:(NSCoder*)aCoder;
- (nullableinstancetype)initWithCoder:(NSCoder*)aDecoder;
@end
KVO:(键值监听)
2、KVO的是KeyValue Observe的缩写,中文是键值观察。这是一个典型的观察者模式,观察者在键值改变时会得到通知。iOS中有个Notification的机制,也可以获得通知,但这个机制需要有个Center,相比之下KVO更加简洁而直接。
KVO的使用也很简单,就是简单的3步。
注册需要观察的对象的属性addObserver:forKeyPath:options:context:
实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用
取消注册观察removeObserver:forKeyPath:context:
KVO:IOS里面的黑魔法,建议不要过多的使用,因为他的模式是一种轮询的方式,比如,一直在敲门,直到打开门为止,还有一种采用轮训的方式的是多线程中的自旋锁.
KVO 代码示例:
@interfacemyPerson:NSObject
{
NSString*_name;
int_age;
int_height;
int_weight;
}
@end
@interfacetestViewController:UIViewController
@property(nonatomic, retain) myPerson *testPerson;
- (IBAction)onBtnTest:(id)sender;
@end
- (void)testKVO
{
testPerson = [[myPerson alloc] init];
[testPerson addObserver:selfforKeyPath:@"height"options:NSKeyValueObservingOptionNewcontext:nil];
}
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
if([keyPath isEqualToString:@"height"]) {
NSLog(@"Height is changed! new=%@", [change valueForKey:NSKeyValueChangeNewKey]);
}else{
[superobserveValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (IBAction)onBtnTest:(id)sender {
inth = [[testPerson valueForKey:@"height"] intValue];
[testPerson setValue:[NSNumbernumberWithInt:h+1] forKey:@"height"];
NSLog(@"person height=%@", [testPerson valueForKey:@"height"]);
}
- (void)dealloc
{
[testPerson removeObserver:selfforKeyPath:@"height"context:nil];
[superdealloc];
}
自旋锁:
互斥锁:
多个线程共享同一个资源时,会造成线程不安全解决方式 互斥锁
主要是防止多线程抢资源造成的数据不安全
原理 :每一个对象(NSObject)内部都有一个锁(变量)当有线程要进入synchronized到代码块的时候先检查对象的锁是打开或者是关闭默认是打开,当线程会进入代码的内部,进行上锁
如果锁是是关闭的,再有线程执行代码的时候就要先等待,直到上个线程结束后就先等待,直到直到锁打开就才可以执行
@synchronized(self) {// 需要锁定的代码} 注意self要是全局对象
atomic :自旋锁 (单写多写) 效率低 (轮讯)
1.使用id作为方法返回值的问题:
1>在接收方法的返回值的时候可以使用任何类型来接收,编译都不报错,但是运行时可能出错。
2.instancetype需要注意的点
1>instancetype在类型表示上,与id意思一样,都表示任何对象类型
2>instancetype只能用作返回值类型,不能向id一样声明变量、用作参数等
3>使用instancetype,编译器会检测instancetype的真实类型,如果类型不匹配,编译时会有个警告(Incompatible pointer types returning 'Person *' from a function with result type 'BFButton *’ 不相容的指针类型“人*”从函数返回结果类型“BFButton *”)。(instancetype出现在哪个类型中就表示对应的类型)