在使用@property定义property时可以在@property与类型之间用括号添加一些额外的指示符,常用的指示符有assign、atomic、copy、retain、strong、week、等。下面对它们的用途和常常对应的属性讲解一下。
assign:该指示符号对属性只是简单的赋值,不更改引用计数。常用于NSInteger等OC基础类型,以及short、int、double、结构体等C数据类型,因为这些类型不存在被内存回收的问题。
atomic、nonatomic:指定setter和getter是否是原子操作,即是否线程安全。如果是atomic,那么存取方法都是线程安全的,即某一线程访问存或者取方法,其他线程不可以进入该存、取方法。nonatomic则不具备线程安全的功能。需要指出的是atomic是默认值,可以保证数据的完整性,但是相应的降低了性能,所以在单线程环境中建议使用nonatomic来提升性能。
copy:如果使用copy指示符,当调用setter方法对成员变量赋值时,会将被赋值的对象复制的一个副本,再将该副本给成员变量,相应的原先的被赋值的对象的引用计数加1。当成员变量的类型是可变类型,或其子类是可变类型,被赋值的对象在赋值后有可能再被修改,如果不需要这种修改,则可以考虑copy指示符。
getter、setter:用于为getter方法、setter方法指定自定义方法名。比如getter=myName,setter=setName:,我们可以看到setter方法后面有一个(:),这是因为我们需要在后面添加参数。
readonly、readwrite:readonly指示系统只合成getter方法,不合成setter方法;readwrite是默认值,指示系统需要合成setter方法和getter方法。
retain:当把某个对象赋值给该属性时,该属性原来所引用的对象的引用计数减1,被赋值对象的引用计数加1。在未启用ARC机制的的情况下,retain可以保证一个对象的引用计数大于1时,该对象不会被回收。启用ARC后一般较少使用retain
strong、weak:strong指示符该属性对被赋值对象持有强引用,而weak指示符指定该属性对被赋值对象持有弱引用。强引用的意思是:只要该强引用指向被赋值的对象,那么该对象就不会自动回收。弱引用的意思是:即使该弱引用指向被赋值的对象,该对象也可能被回收。如果不希望对象被回收,可以使用strong指示符。如果需要保证程序性能,避免内存溢出,可以使用weak,内存一旦被回收,指针会被赋值为nil。
unsafe_unretained:与weak不同,被unsafe_unretained指针所引用的对象被回收后,unsafe_unretained指针不会被赋为nil,可能会导致程序出错。
1、atomic是默认行为,assign是默认行为,readwrite是默认行为
2、推荐做法是NSString用copy
3、delegate用assign(且一定要用assign)
4、非objc数据类型,比如int,float等基本数据类型用assign(默认就是assign)
5、其它objc类型,比如NSArray,NSDate用retain。
OC中提供了4个访问控制符:@private @package @protected @public。
@private(当前类访问权限):成员只能在当前类内部可以访问,在类实现部分定义的成员变量相当于默认使用了这种访问权限。
@package(同映像访问权限):成员可以在当前类或和当前类实现的同一映像中使用。同一映像就是编译后生成的同一框架或同一个执行文件。
@protected(子类访问权限):成员可以在当前类和当前类的子类中访问。在类接口部分定义的成员变量默认是这种访问权限。
@public(公共访问权限):成员可以在任意地方访问。
@private | @package | @protected | @public | |
同一个类中 | ||||
同一个映像中 | ||||
子类中 | ||||
全局范围 |
下面使用@private来实现Person类,用来封装Person的2个属性,并将方法暴露出来:
[objc] view plain copy
#import <Foundation/Foundation.h>
@interface Person : NSObject{
//使用@private限制成员变量
@private
NSString* _name;
int _age;
}
//声明_name的set方法
-(void)setName:(NSString*)name;
//声明_name的get方法
-(NSString*)name;
//声明_age的set方法
-(void)setAge:(int)age;
//声明_age的get方法
-(int)age;
@end
#import "Person.h"
@implementation Person
//声明_name的set方法
-(void)setName:(NSString*)name{
_name = name;
}
//声明_name的get方法
-(NSString*)name{
return _name;
}
//声明_age的set方法
-(void)setAge:(int)age{
_age = age;
}
//声明_age的get方法
-(int)age{
return _age;
}
@end
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const charchar * argv[]) {
@autoreleasepool {
Person* person = [[Person alloc]init];
//报错,age已经被封装起来,对外不可见
//person->_age = 10;
[person setAge:10];
NSLog(@"age:%d",[person age]);
}
return 0;
}