weak 和 assign

382 阅读2分钟

1、 weak 的使用

weak 关键字的使用场景:

  1. 在ARC中为了避免循环引用时,会使用 weak 来打破,比如代理属性delegate 需要使用 weak 修饰。

  2. 在使用 XIB 的 IBOutlet 控件属性时,系统默认会使用 weak,但是也可以 strong,那为什么不用 strong 呢? 因为:

因为既然有外链那么视图在xib或者storyboard中 肯定存在,视图已经对它有一个强引用了。另外使用 storyboard(xib不行)创建的 vc,会有一个叫 _topLevelObjectsToKeepAliveFromStoryboard 的私有数组强引用所有 top level 的对象,所以这时即便outlet声明成weak也没关系。

参考:Should IBOutlets be strong or weak under ARC?

  1. __weak 的使用场景为:

现在看一段代码:

@interface TestViewController ()
@property(nonatomic, copy) void (^block)(void);
@end
@implementation TestViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    self.block = ^{
        [self funtionA];
    };
    self.block();
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];
}

- (void)funtionA {
    NSLog(@"FNNTION -- funtionA");
}

- (void)dealloc {
    NSLog(@"FUNTION -- dealloc");
}

有这样的一段代码存在,我们在控制器 pop 的时候,dealloc 并不会调用,因为此处会有一处循环引用,self 和 block 互相强持有,self 强引用了 block ,block 又在 block 体内强引用了 self(因为block会把block体内的对象拷贝一份到堆上)。

想要打破这种循环引用应该怎么办呢? 此时就会用到 __weak

修改代码为:

__weak typeof(self) weakSelf = self; //typeof(instance):可以根据括号里的参数动识别变量类型并返回该类型。
self.block = ^{
    [weakSelf funtionA];
};
self.block();

这样的话就会打破循环引用强持有,控制器就会正常释放,delloc正常执行。

2、 assign 的使用

assign 常用来修饰基本数据类型的数据,当然也可以修饰对象。

3、 weak 和 assign 区别

weak 关键字的作用为弱引用,所引用对象的计数器不会加 1,并在引用对象被释放的时候 自动被设置为 nil,所以weak 不会产生野指针的问题。

assign 如果修饰对象,会产生野指针问题;如果修饰基本数据类型则是安全的。如果assign修饰了对象,当此对象释放后,指针不会自动被置nil,此时向对象发消息会崩溃。

4、 delegate 用 weak 还是 assign 修饰?

先说答案: 当然是用 weak

由上面第三点 两只的区别看来,如果使用 assign 修饰的话,在delegate对象被释放时并不会自动置为nil,会产生野指针,如果此时对 delegate 对象发送消息的话,就会产生崩溃。

weak 修饰就避免了这种问题。