- 版权声明:本文为博主原创文章,未经博主允许不得转载。
- 原文档关于自动引用说明:
Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. Rather than having to think about retain and release operations, ARC allows you to concentrate on the interesting code, the object graphs, and the relationships between objects in your application.
- 翻译过来就是:
Automatic Reference Counting (ARC)
是一个编译器的特性,提供了对iOS对象的自动内存管理,ARC
在编译期间自动在适当的地方添加ObjC对象的retain
和release
操作代码,而不需要我们关心。
ARC在编译期间,根据Objective-C对象的存活周期,在适当的位置添加retain和release代码。从概念上讲,ARC与手动引用计数内存管理遵循同样的内存管理规则,但是ARC也无法防止循环强引用。
ARC还引入了新的修饰符来修饰变量和声明属性。
· 声明变量的修饰符:__strong, __weak, __unsafe_unretained, __autoreleasing;
· 声明属性的修饰符:strong, weak, unsafe_unretained。
· 对象和Core Foundation-style对象直接的转换修饰符号:__bridge,__bridge_retained或CFBridgingRetain, __bridge_transfer或CFBridgingRelease。
· 对于线程的安全,有nonatomic,这样效率就更高了,但是不是线程的。如果要线程安全,可以使用atomic,这样在访问是就会有线程锁。```
#####记住内存管理法则:谁使对象的引用计数+1,不再引用时,谁就负责将该对象的引用计数-1。
- 下面我们来声明一个Person类来学习:
```swift
@interface Person : NSObject
// 注意:苹果有命名规范的,命名属性时,不能以copy开头。
// 如果下面的属性声明为copyString,会编译不通过。
@property (nonatomic, copy) NSString *copiedString;
// 默认会是什么呢?
@property (nonatomic) NSString *name;
// 默认是strong类型
@property (nonatomic) NSArray *array;
@end```
如果属性没有指定类型,默认是什么呢?其实是`strong`。如果证明呢?验证方法:分别将array属性的类型分别设置为`weak, assign,strong`,不设置,这四种情况的结果分别是:第一种打印为空,第二种直接直接崩溃,第三种和最后一种是可以正常使用。如下面的验证代码:
Person *lili = [[Person alloc] init];
lili.name = @"LiLi";
lili.copiedString = @"LiLi' father is LLL";
lili.array = @[@"谢谢", @"感谢"];
NSArray *otherArray = lili.array;
lili = nil;
NSLog(@"%@", otherArray);
再继续添加下面的代码。默认声明变量的类型为`__strong`类型,因此上面的`NSArray *otherArray = lili.array;`与`__strong NSArray *otherArray = lili.array;`是一样的。如果我们要使用弱引用,特别是在解决循环强引用时就特别重要了。我们可以使用`__weak`声明变量为弱引用,这样就不会增加引用计数值。
__strong NSArray *strongArray = otherArray;
otherArray = nil;
// 打印出来正常的结果。
NSLog(@"strongArray = %@", strongArray);
__weak NSArray * weakArray = strongArray;
strongArray = nil;
// 打印出来:null
NSLog(@"weakArray: %@", weakArray);```
xib/storybard连接的对象为什么可以使用weak?
@property (nonatomic, weak) IBOutlet UIButton *button;
像上面这行代码一样,在连接时自动生成为
weak
。因为这个button已经放到view上了,因此只要这个View不被释放,这个button的引用计数都不会为0,因此这里可以使用weak
引用。
如果我们不使用xib/storyboard,而是使用纯代码创建呢?
@property (nonatomic, weak) UIButton *button;```
>使用weak时,由于button在创建时,没有任何`强引用`,因此就有可能提前释放。Xcode编译器会告诉我们,这里不能使用weak。因此我们需要记住,只要我们在创建以后需要使用它,我们必须保证至少有一个强引用,否则引用计数为0,就会被释放掉。对于上面的代码,就是由于在创建时使用了weak引用,因此button的引用计数仍然为0,也就是会被释放,编译器在编译时会检测出来的。
这样写,在创建时通过`self.button = ...`就是出现错误,因为这是弱引用。所以我们需要声明为强引用,也就是这样:
@property (nonatomic, strong) UIButton *button;```
block声明使用copy.
在使用block时,尽量使用typedef来起一个别名,这样更容易阅读。
使block作为属性时,使用
copy
。
typedef void (^Block)(NSString *name);
@property (nonatomic, copy) Block testBlock;```
#####属性声明修饰符
- 属性声明修饰符有:`strong, weak, unsafe_unretained, readWrite`,默认`strong`, `readWrite`的。
· `strong`:`strong`和`retain`相似,只要有一个strong指针指向对象,该对象就`不会被销毁`
· `weak`:声明为`weak`的指针,`weak`指针指向的对象一旦被释放,`weak`的指针都将被赋值为`nil`;
· `unsafe_unretained`:用`unsafe_unretained`声明的指针,指针指向的对象一旦被释放,这些指针将成为野指针。
@property (nonatomic, copy) NSString *name;
// 一旦所指向的对象被释放,就会成为野指针
@property (nonatomic, unsafe_unretained) NSString *unsafeName;
lili.name = @"Lili";
lili.unsafeName = lili.name;
lili.name = nil;
// unsafeName就变成了野指针。这里不会崩溃,因为为nil.
NSLog(@"%@", lili.unsafeName);```
总结
- 关于属性的这些选项的学习,做一下总结:
· 所有的属性,都尽可能使用nonatomic,以提高效率,除非真的有必要考虑线程安全。
· NSString:通常都使用copy,以得到新的内存分配,而不只是原来的引用。
· strong:对于继承于NSObject类型的对象,若要声明为强使用,使用strong,若要使用弱引用,使用__weak来引用,用于解决循环强引用的问题。
· weak:对于xib上的控件引用,可以使用weak,也可以使用strong。
· __weak:对于变量的声明,如果要使用弱引用,可以使用__weak,如:__weak typeof(Model) weakModel = model;就可以直接使用weakModel了。
· __strong:对于变量的声明,如果要使用强引用,可以使用__strong,默认就是__strong,因此不写与写__strong声明都是一样的。
· unsafe_unretained:这个是比较少用的,几乎没有使用到。在所引用的对象被释放后,该指针就成了野指针,不好控制。
· __unsafe_unretained:也是很少使用。同上。
· __autoreleasing:如果要在循环过程中就释放,可以手动使用__autoreleasing来声明将之放到自动释放池。```