OC的集合是不允许存入基本类型的,所以NSNumber类就是讲基本类型封装一下,然后存进去,这个类似于Java中的自动装箱0和自动拆箱,Java中的集合其实也不允许存入基本数据类型,但是我们仍然可以操作,是因为有自动装箱和拆箱。
为什么基本类型不能存入到集合中?
是因为在操作集合的时候会操作集合元素中的方法,但是基本数据类型是没有方法的。
KVC和KVO
OC中的KVC操作和Java中使用反射机制去访问类的private权限变量一样。这样会破坏类的封装性,类中private关键字标记的属性或者方法就不希望外界去访问,但是有的时候真的需要这样做。下面就举个例子:|
一个Person类中定义两个属性 name和dog都是private的。
//Person的.h文件 NSDog是一个没有参数没有方法的类 _name和_dog是没有set和get方法的
@interface Person:NSObject{
@private
NSString *_name;
NSDog *_dog;
NSInteger *_age;
}
@end
//--------测试代码---------
//KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法类似
Person *P = [[Person alloc] init];
[p setValue:@"zhangsan" forKey:@"name"];
Dog *dog = [[Dog alloc] init];
[p setValue:dog forKey:@"dog"];
//-----------读取--------
NSString *name = [p valueForKey:@"name"];
//如果设置基本数据类型,需要将基本数据类型转化为NSNumber,在设置值的时候,会有自动解包的过程
[p setValue:@22 forKey:@"age"];
KVO 添加监听对象
第一个参数:addObserver:self 监听者
第二个参数:forKeyPath:@"hapyValue" 监听对象的属性名
第三个参数:options 监听这个属性的状态,这里可以用 | 进行多种组合操作,属性的新值和旧值
第四个参数:Context:@"context" 传递内容给监听方法
[_children addObserver:self forKeyPath:@"hapyValue" options:NSKeyValueObservingOptionNew |NSKeyVauleObservingOptionOld Context:@"context"];
监听方法
第一个参数:(NSString *)keyPath 键值路径
第二个参数:ofObject:(id)object 监听对象
第三个参数:change:(NSDictionary *)change 变化的值
第四个参数:context:(void *)context 传递的内容
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if([keypath isEqualToString:@"hapyValue"]){
NSNumber *hapyValue = [change objectForKey:@"new"];
NSInteger *value = [hapyValue integerValue];
if(value <90){
//do somthing...
}
}
}
销毁方法:
-(void)dealloc{
[_children removeObserver:self forKeyPath:@"hapyValue"];
}
NSNotificationCenter 通知
KVO只用来监听属性值的变化,这个发送监听的操作是系统控制的,我们只能控制监听操作,类似于Android中系统发送的广播,我们只能接收。通知就不一样,他的监听发送也是我们控制的,我们可以在任何地方任何时机发送一个通知,类似于Android中开发者自己发送广播。
定义了一个定时器,在timerAction方法中发送通知
第一个参数:postNotificationname:@"XXX" 通知的名字,这个名称必须和后面接受通知的名称一致
第二个参数:object:self 可以传递的一个参数对象
@implementation Children
-(id) init{
self = [super init];
if(self !=nil){
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
self.hapyValue = 100;
}
return self;
}
-(void) timerAction:(NSTimer *) timer{
_hapyValue--;
if(_hapyValue < 80){//发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"hapyValueNotification" object:self];
}
}
@end
监听通知
第一个参数:addObserver:self 监听者对象
第二个参数:selector:@selector(notificationAction) 监听处理通知的方法
第三个参数:name:@"XXX" 通知单额名称
第四个参数:object:nil 通知发送时候传递的参数对象
@implementation Nure
-(id) init{
self = [super init];
if(self !=nil){//监听通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationAction) name:@"hapyValueNotification" object:nil];
}
return self;
}
//处理通知的方法
-(void) notificationAction:(NSNotification *)notification{
Children *children = notification.object;
}
-(void) dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"happyValueNotification" object:nil];
//一个类中可以添加多个通知,这个方法可以移除所有的通知
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
谓词 NSPredicate
谓词就像sql语句一样有自己的规则,这就不说了,比较容易理解
@property关键字定义属性会自动有set/get方法
@Property NSString *userName;
@Property(atomic,retain,readwrite) Dog *dog;
第一个位置:atomic---线程保护的,默认 nonatomic---线程不保护的
第二个位置:assign---直接赋值,默认 retain---保留对象,内部会自动调用retain方法引用次数 +1 copy---拷贝对象
第三个位置:readwrite---生成set/get方法,默认 readonly---只生成get方法
如果我们相信修改这个属性名称,可以用@synthesize关键字进行修改
拷贝
copy方法和mutableCopy方法的区别
区别只在于那些有可变对象和不可变对象之分的对象上,对于没有这种区分的对象来说,这两个方法的效果是一样的。
【不可变对象 copy】是假拷贝,等价于 【不可变对象 retain】
【不可变对象 mutableCopy】是真拷贝
深拷贝:拷贝属性对象的内容
浅拷贝:只拷贝所有属性对象的指针
iOS中如果定义一个类型是NS开头的,一般都是指针类型,比如NSString *str;结构体类型的CGRect rect;