OC-属性简介
OC中,任何属性都有3种特性,分别是
1.多线程特性
2.读/写特性
3.内存管理特性
多线程特性
多线程特性有nonatomic和atomic两种,分别表示非原子性和原子性。默认使用atomic,提供线程安全保护。但我们一般设置为nonatomic。
读写特性
读写特性有readwrite和readonly两种,默认使用readwrite,使用readwrite编译器会生成存取方法,如果只使用readonly方法,则只会生成取方法。
内存管理特性
内存管理特性相对复杂,有strong、retain、weak、copy、unsafe_unretained、assign集中形式。
OC对象属性可使用strong、retain、weak、copy,默认值为strong
其中strong与retain等价,表示强引用,正常情况下使用这个特性;
weak表示弱引用,当两个对象是父子关系,且子对象持有对父对象的引用时,该引用需要声明为weak,否则会导致引用循环;
copy表示返回对象的副本,拥有可变子类的对象需要用该特性声明,如NSArray,NSDictionary,NSData,NSString,但它们的可变子类仍使用strong
非对象属性可使用unsafe_unretained、assign
,默认值为unsafe_unretained,两者等价
参考
被无数人写过的assign,retain,strong,weak,unsafe_unretained,还有copy
iOS中代理属性为什么要用Weak修饰?
常见问题
什么情况使用 weak 关键字?相比 assign 有什么不同?
1.在ARC中,有可能出现引用循环的,使用weak。如delegate作为属性时,需要声明为weak。
2.自身已经进行了强引用,没必要再使用强引用,不过使用强引用也没有问题,如使用storyboard创建的viewController,那么会有一个叫 _topLevelObjectsToKeepAliveFromStoryboard的私有数组强引用所有top level的对象,同时top level对象强引用所有子对象,那么vc没必要再强引用top level对象的子对象。
不同点:
1.使用范围:一般assign用于简单数据类型,在非ARC时代,它是属性的默认值,在ARC时代,一般使用unsafe_unretained,而weak则必须用于OC对象。
2.对象释放的表现:当weak指向的对象被释放时,属性值会置空,而assign则不会,这时使用该属性访问对象可能会导致程序崩溃。
怎么用 copy 关键字?(什么时候使用Copy)
1.NSString、NSArray、NSDictionary,NSData 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,NSMutableDate;他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
2.block使用copy,block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。
这个写法会出什么问题: @property (copy) NSMutableArray *array;
两个问题
1.使用copy,那么array的实际类型为NSArray,在调用NSMutableArray专有的方法,如[array removeObjectAtIndex:0];时程序会崩溃;
2.没有指明多线程特性,默认使用的是atomic,影响性能。
如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?
-
若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现
NSCopying
与NSMutableCopying
协议。 -
如下
- (void)setName:(NSString *)name {
//[_name release];
_name = [name copy];
}
@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的
1.@property = ivar + getter + setter
2.自动合成,完成属性定义后,编译器会自动编写访问这些属性所需的方法,此过程叫做“自动合成”(autosynthesis)。需要强调的是,这个过程由编译器在编译期执行。默认为@synthesize firstName = _myFirstName;
@property中有哪些属性关键字?/ @property 后面可以有哪些修饰符?
任何属性都有3种特性,分别是
1.多线程特性
2.读/写特性
3.内存管理特性
1)多线程特性
nonatomic和atomic,默认使用atomic,但我们一般设置为nonatomic。
2)读写特性
readwrite和readonly,默认使用readwrite,使用readwrite编译器会生成存取方法,如果只使用readonly方法,则只会生成取方法。
3)内存管理特性
strong、retain
weak
copy
unsafe_unretained、assign
OC对象属性可使用strong、retain、weak、copy,默认值为strong
其中strong与retain等价,强引用,正常情况下使用这个
weak表示弱引用,当出现父子关系而子又需要有指向父的指针时使用
copy表示返回对象的副本,拥有可变子类时使用,如NSArray,NSDictionary,NSData,NSString,但它们的可变子类仍使用strong
非对象属性可使用unsafe_unretained、assign
,默认值为unsafe_unretained,两者等价
block使用copy修饰
delegate使用weak修饰
被无数人写过的assign,retain,strong,weak,unsafe_unretained,还有copy
iOS中代理属性为什么要用Weak修饰?
weak属性需要在dealloc中置nil么?
不需要
1.在ARC环境无论是强指针还是弱指针都无需在 dealloc 设置为 nil , ARC 会自动帮我们处理
2.非arc中,weak属性指向的对象遭到摧毁时,属性值也会清空(nil out)。
@synthesize和@dynamic分别有什么作用?
@property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;
- @synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
- @dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到
instance.var = someVar
,由于缺 setter 方法会导致程序崩溃;或者当运行到someVar = var
时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?
- 对应基本数据类型默认关键字是
atomic,readwrite,assign
- 对于普通的 Objective-C 对象
atomic,readwrite,strong
用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?
使用strong,如果给该属性赋值时,赋值的类型是可变类型,则外部的修改会影响到该属性的值,使用copy相当于建立一个备份,不会影响。
@property (nonatomic ,readwrite, strong) NSArray *array;
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
NSArray *array = @[ @1, @2, @3, @4 ];
self.array = mutableArray;
[mutableArray removeAllObjects];;
NSLog(@"%@",self.array);
打印结果为空。
@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo
的实例变量,那么还会自动合成新变量么?
1)合成规则如下:
- 如果指定了成员变量的名称,但该成员变量没有声明,会生成一个指定的名称的成员变量,如果已经声明,则该属性对应操作该成员变量
- 如果不指定成员变量的名称,则会生成一个与属性同名的成员变量。例如,
@synthesize foo;
还会生成一个名称为foo的成员变量 - 不写@synthesize时,编译器默认生成 @synthesize foo = _foo;
2)此情况等同于以下情况
@property (copy,nonatomic) NSString foo;
@synthesize foo = _foo;
根据合成规则第一条,不会再生成新变量。