iOS基础修炼iOS技术文章

OC:copy/strong/weak..使用总结☀️

2016-06-24  本文已影响642人  LeaderBiao
  • 版权声明:本文为博主原创文章,未经博主允许不得转载。

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.

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来声明将之放到自动释放池。```
上一篇 下一篇

猜你喜欢

热点阅读