修饰符copy
和 strong
的使用场景
1、copy
修饰符
copy
修饰不可变对象
① 如果赋值对象为不可变对象,则与strong
修饰符使用上没有区别,不会发生内存拷贝,只是发生了指针的强引用(指针重新指向);
② 如果赋值对象为可变对象,会发生内存的拷贝。例如,可变数组A
赋值给copy
修饰的NSArray
对象B
,当A
的值发生变化,B
不会发生变化。
copy
修饰可变对象
copy
修饰可变对象时会进行浅拷贝,拷贝出来的内存区域是不可变的。使用不可变对象进行赋值不会有问题,如果使用可变对象赋值,并改变可变对象的值,则会出现崩溃。
小结:
copy修饰符主要用于修饰不可变对象,防止因为可变对象赋值时因为赋值对象的值变化而发生变化。
2、strong
修饰符
① strong
修饰不可变对象时,赋值对象共用同一内存,赋值对象的引用计数+1。赋值对象的值发生变化strong
修饰对象的值也会发生变化。
② strong
修饰可变对象时,如果对象值发生变化不会引起崩溃,因为共用的是同一内存区域。
小结:
strong修饰符主要用于修饰可变对象,防止因为可变对象的值发生变化而引起崩溃。
延伸:self.
语法 和 _
语法
@property (nonatomic, strong) NSString *string;
实际项目中调用string属性主要有两种方式,self.string
或者_string
。在说self.string
和_string
之前首先需要了解一下@property
以及 @synthesize
两者之间的关系。
@property
和@synthesize
@synthesize
是写在@implementation
中,@synthesize
声明的属性 = 变量。意思是,将属性的setter,getter
方法,作用于这个变量。
iOS 6 之后 LLVM 编译器引入property autosynthesis,即属性自动合成。换句话说,就是编译器会为每个 @property
添加 @synthesize
,如以下形式:
@synthesize propertyName = _propertyName;
虽然现在我们不必再用@synthesize
声明一个实例变量。(注意:是不必要,不是不可以),但是一些特殊情况还是会用到@synthesize
① @synthesize
可以指定与属性对应的实例变量,例如:
@synthesize age = myAge;
这样的话调用self.age
的时候,其实是操作的实例变量myAge
,而不是_age
了。
② 使用@synthesize
为属性添加任意别名,此时使用自动生成的实例变量名将报错,只能使用指定的别名。例如:
@synthesize propertyName = _propertyNameNew;
这样的话,使用_语法调用self.propertyName
,只能使用_propertyNameNew
,而不能使用_propertyName
。
③ 还有一种情形需要使用 @synthesize
,就是当在 protocol
中声明并实现属性时。协议中声明的属性不会自动生成setter
和getter
,[UIApplicationDelegate window]
就是个典型的例子。
④ 同时重写属性的setter
和getter
方法之后,需要使用 @synthesize
手动生成成员变量。因为同时重写setter
和getter
会导致系统不再自动生成_xx
成员变量。
ps:重写setter和getter的注意事项
重写getter
时,最后返回return _xx;
而不是return self.xx;
, 这是因为点语法实际上是对setter
和getter
方法的调用,如果在getter
方法中调用return self.xx
的话,就会循环调用。
重写setter
时,最好在setter
方法中添加一行_xx = xx;
,以便外部调用_xx
。
关于 @synthesize
的其他知识点:
① 禁止@synthesize
:如果某属性已经在某处实现了自己的 setter/getter
,可以使用 @dynamic
来阻止 @synthesize
自动生成新的 setter/getter
覆盖。
② 自动合成没有任何内存的含义,因为它根本没有连接到ARC。
言归正传,下面继续聊self.
语法和_
语法的问题。
① self.xx
实际是对xx
的setter/getter
方法的调用:
self.xx
在=
的左边调用的是setter
方法
self.xx
在=
右边调用的是getter
方法
② _xx
是直接对变量操作,不会调用setter/getter
方法
小结:
1、self.xx
和 _xx
的区别主要是在是否调用setter/getter
方法。
2、在不需要调用setter/getter
方法时使用_xx
会提高一些性能,但是需要主要的是,必须在确保xx
已经创建之后再用_xx
,否则_xx
是nil
。