其实对于基础知识的掌握还是很重要的,很多次都被属性声明绕的有点晕。索性做个总结,网上找了其他大牛的总结作为参考。下面进入正题:
1.通过self.name和_name获取局部变量的区别
@interface Person : NSObject
@property (nonatomic, copy) NSString* name;
@property (nonatomic, assign) NSUInteger age;
@end
@implementation Person
@synthesize name = _name;
@synthesize age = _age;
@end
上述代码,在xcode6以后 @synthesize部分可以省略。下面说一下_name和self.name的区别。
在Person对象实例化的时候,假设有一个person对象,此时编译器会自动生成_name这个变量,用来存储name这个属性。通过_name可以直接访问变量的name属性。
而self.name本质是调用实例对象属性的setter方法和getter方法。从而访问name属性。
2.setter方法和getter方法。
属性方法遵守一个简单的命名约定。getter的名字与属性名相同(如:属性名为date则getter的名字也为date),setter的名字则是属性名字加上set前缀并采用驼峰命名规则(如:属性名为date则setter的名字为setDate)。布尔类型的属性还可以定义一个以is开头的getter方法,如:
@property (readonly, getter=isBlue) BOOL blue;
可以这样理解,对对象中的属性进行读和写。就是对应的getter方法和setter方法。如果确定了对象的一项属性,那么使用property关键字声明之后,系统会自动生成对应的setter方法和getter方法。当然你也可以通过重写这两个方法来实现更多的功能。
@interface Person : NSObject
{
NSString *_name;
NSUInteger _age;
}
- (void)setName:(NSString*)name;
- (NSString*)name;
- (void)setAge:(NSUInteger)age;
- (NSUInteger)age;
@end
@implementation Person
- (void)setName:(NSString*)name {
//dosomething
_name = [name copy];
}
- (NSString*)name {
return _name;
}
- (void)setAge:(NSUInteger)age {
//dosomething
_age = age;
}
- (NSUInteger)age {
return _age;
}
@end
3.合成存取方法:@property
如若为每一个变量都写setter和getter无疑是很繁琐和没有必要的。此时合成存取方法就出现了。使用@property声明变量之后,会自动生成这两个方法,如果有必要,再进行重写,不然就按照默认的规范名称来访问属性。
可以这样理解,对象是一个变量,对象的变量里面也有name和age这样的变量,他们都需实现存取方法,那就将他们设置为属性。(合成了存取方法)。用@property进行声明,系统就默认生成对应的存取方法了。
注意:在声明一个属性(property)的时候尽量使用Foundation框架的数据类型,如整形使用NSInteger或NSUInteger表示,时间间隔的浮点类型使用NSTimeInterval表示,这样代码数据类型更统一。
4.懒加载
所谓懒加载,其实就是重写属性的getter方法,在属性被访问,或者被使用到的时候,再进行加载,节省系统资源
应用场景:
@interface XMGTopicViewController ()
@property (nonatomic, strong) NSMutableArray *users;
@end
@implementation XMGTopicViewController
- (NSMutableArray *)users //1部分
{
if (!_users) { //2部分
_users = [NSMutableArray array]; //3部分
}
return _users; //4.部分
}
// 加载网络数据
self.users = [LXBUsers objectArrayWithKeyValuesArray:responseObject[@"user"]];
第一部分:self.users是一个getter
第二部分:不能写成 !self.users 这也是一个getter,getter中有getter会造成死循环
第三部分:可以使用self.users,这是一个setter
此处如果按照_users方法编写不会调用setter方法,如果自定义setter方法需要完成一些事情建议使用self.users的方式来设置
第四部分:不能使用self.users,这也是一个getter,getter中有getter会造成死循环
可以参照本文开头第一点理解懒加载写法。
接下来是重点部分:
5.对于@property的指示符
栗子:
@property(nonatomic, readonly, strong) NSMutableArray *users;
① nonatomic atomic:
指定合成存取方法是否为原子操作,可以理解为是否线程安全,但在iOS上即时使用atomic也不一定是线程安全的,要保证线程安全需要使用锁机制;
可以发现几乎所有代码的属性设置都会使用nonatomic,这样能够提高访问性能,在iOS中使用锁机制的开销较大,会损耗性能。
总之,就是只使用nonatomic。
② readwrite,readonly
如果忽略这个属性,那么系统默认是readwrite。生成setter和getter两个方法,如果指定了readonly,那么就只生成getter方法,没有setter方法。此属性也相对简单。
③ 重点来了
assign,strong,weak,copy,unsafe_unretained,retain
先简单粗暴的上结论:
对于标量类型NSInteger,NSUInteger,CGFloat,NSTimeInterval,使用assign类型。
对于有对应可变类型子类的对象比如:NSString/NSMutableString,NSArray/NSMutableArray,NSDictionary/NSMutableDictionary等,使用copy来修饰。copy也用来修饰block。
对于可变类型,一般使用强引用strong来修饰,如NSMutableString,NSMutableArray,NSMutableDictionary
还有其他必须强持有的对象,也使用strong来修饰。
weak表示对所赋的值对象持有弱引用表示一种“非拥有关系”(nonowning relationship),对新值不会增加引用计数,也不会减少旧值的引用计数。所赋的值在引用计数为0被销毁后,weak修饰的属性会被自动置为nil能够有效防止野指针错误。
weak常用在修饰delegate等防止循环引用的场景。
retain在MRC模式下,与strong相同。
一些注意点:assign也可以用于修饰NSString,但是由于不计算引用计数,如果属性被置为nil,并不会像weak一样自动销毁,所以如果nil以后再去self.name访问,就会发生野指针错误,程序崩溃。
网友评论