一、@property
1. @synthesize 与 @dynamic
在声明@property 属性后,会有两种实现选择@synthesize 和 @dynamic
2. 两者区别
- @synthesize ,表示在编译阶段 编译器会自动生成 setter/getter方法的实现;
- @dynamic,表示通知编译器不自动生成,由用户手动添加属性的 setter/getter方法;
3. @property重写setter方法
如果使用@property生成的属性,重写setter方法会报错。
原因: 重写setter方法,那@property就不会再自动生成setter和getter方法,也不会生成带下划线的成员变量,自然无法访问报找不到该对象。
解决: 使用 @synthesize
@synthesize object = _object;
二、属性关键字
1. 默认属性关键字
默认包含: atomic、 readwrite、assign(基本数据类型)、strong(对象);
2. 关键字分类
- 读写权限: readonly、readwrite ;
- 原子性: atomic、noatomic ;
- 内存管理: assign, weak, unsafe_unretained, copy, strong,retain;
注意点:
retain用在MRC,当retain作为@property属性关键字时:
@property(nonatomic, retain)
相当于系统自动帮我们处理了属性的setter方法,如下
-(void)setObject:(id)Obj
{
if(obj != obj) { // 防止重复赋值,指针指向被释放的对象造成崩溃
[_obj release]; // 防止前一个对象没被释放,造成的内存泄漏
[obj retain]; // 多对象引用,保证A存在B存在,A释放B随后释放
_obj = obj;
}
}
同时注意,在MRC下retain作为关键字,dealloc中都需要把属性进行释放。才能防止内存泄漏。
-(void)dealloc
{
[_obj release]; // ...
[super dealloc];
}
三、常见比较
1. 原子性 atomic 与 nonatomic区别?
- atomic 是系统默认的属性,给getter/setter方法会进行加锁,在一定程度保证线程安全;
- nonatomic 没有加锁,不能保证线程安全, 但是访问更快;
- 设置属性一般会使用 nonatomic , 虽然atomic能保证线程安全但是保护范围仅仅是getter/setter方法,而且耗费资源、访问更慢。
2. assign 和 weak 的区别?
- assign 可以修饰基本数据类型, weak用来修饰对象;
- assign 修饰的对象被释放后,对象对应的指针没有置为 nil 从而造成野指针;
weak 修饰的对象被释放后,对象指针置为 nil 。
3. copy 和 strong 的区别?
- copy分为浅拷贝和深拷贝;
浅拷贝不会开辟新的地址产生新的对象,两个指针指向同一块地址,因此引用计数会+1;
深拷贝会开辟新的地址产生新的对象,两个指针各自指向不同的地址,因此引用计数不会+1; - copy 和 strong的区别
strong 强引用对象,操作仍是浅拷贝; copy修饰的对象,分深浅拷贝两种;引用计数也有不同;
4. 为什么代理使用 weak 修饰?
答:防止循环引用
- 如以UITableView为例, tableView作为控制器vc的属性, vc 强引用tableView;
tableView需要设置vc为代理,self.delegate = vc; 如果代理也是强引用则会造成循环引用。 因此代理使用weak;
5. 为什么 block 使用copy修饰?
答: Block作为OC对象, 包含 全局Block、 堆Block、栈Block 三种;
在Block没有访问外部变量时,一般是放在全局区;当需要访问外部变量时,分MRC和ARC两种;
- 在MRC下,Block是放在栈中的,会随着作用域的结束被系统收回,当外部变量调用空的对象就会造成崩溃;
因此使用copy,复制一份在堆内存中,始终强引用防止被销毁; - 在ARC下,系统自动的对block进行了copy,因此ARC下的Block放在堆中;
6. 为什么 NSString 使用copy修饰?
答:
7. 使用copy修饰可变数组 (NSMutableArray) 会造成的问题?
答:copy修饰可变数组NSMutableArray,深拷贝,最终会变成不可变数组NSArray。
那么原来可变数组具备的添加、删除对象的方法,都不可用。 此时生成的不可变数组再使用上述方法就会崩溃。
8. 为什么xib或storyBoard拖线的控件使用weak,而代码创建的使用strong?
- IBOutlet使用weak的原因
(1) 拖线产生的对象会添加到控制器的view的subViews里,
控制器vc 对其view肯定是强引用,view持有控件但是控制器不需要直接持有。如果控件也设置strong,存在父控件被销毁子控件仍然存在从而内存泄漏; 并且为了保证父子控件相同的生命周期,也应该使用weak; - 代码使用strong 的原因
代码定义的控件如button,在使用是 self.button 即控制器直接持有button, 强引用因此使用strong 。
9. __weak 与__block
weak 是修饰属性, 而 __weak 和 __block 用于修饰变量。
- 使用场景不同
__weak 用于断开 block 容易产生的循环引用;
__ block 则是由于内部想要修改外部的值,由原来的值传递转换成指针传递。