以前刚开始学OC的时候,写一个delegate 的时候都是用assign来声明,我进的第一家公司之前的代码也都是assign,但是后来看别人的代码,发现用的都是weak了,所以有时候就特别想知道他们俩的区别在哪。
首先明确一点,assign既可以声明基本数据类型,也可以声明对象,但是weak只能用来声明对象。
其次,weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似,
然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。
而 assign的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。
在使用delegate的时候,我们都知道使用assign/weak,要问为什么,往往就是一句防止循环引用,具体要我说清楚是什么循环引用,我之前也都是说不上来。现在算是明白是什么一回事了。
一个很简单的例子,两个VC,在VCA里,声明一个delegate
@property (nonatomic, assign) id<VCADelegate> delegate;
然后再VCB里,代理这个协议
VCA *vc = [VCA new]
vc.delegate = self;
…….
在VCB里面,对这个VCA是强拥有关系的,这时候VCA里面的属性delegate,这时候就是VCB,所以如果属性用关键字strong的话,就会相互强拥有,就造成了循环引用,用assign/weak就可以打破这个循环。
那么为什么现在又要用weak来声明了,而不是assign呢?
这是因为,用assign的话,即使delegate指向的对象被销毁了,但是delegate还是会指向那个内存地址,就会出现野指针这种情况,用weak的话,weak就会自动置空,delegate = nil了。
关于weak的置空,这里就要讲到weak的实现机制了,简单讲一下就是,系统内部会有一个哈希表,key值就是用weak声明的对象的内存地址,根据这个哈希表,来判断是否对这个对象置空,具体的可以自行谷歌。。。
到此算是弄明白了delegate用assign和weak修饰的区别😊。
关于block,在使用block的时候,也经常会在外面写这样一句代码
__weak typeof(self) weakSelf = self;
你要问我为什么,那我也只会说一句防止循环引用......😆
我们在创建一个对象的时候
Objc *obj = [Objc new];
但其实这里隐藏了一个关键字,
Objc __strong *obj = [Objc new];
所以,self会对这个对象有一个强引用的关系,我们在创建block的时候,self对block有一个强引用,block内部,如果直接使用self的话,那么block又会捕获这个self,对self有一个强引用的关系,这样就造成了循环引用。这样就很尴尬,所以我们可以在外部用__weak修饰一下,这样你block拿到的只是一个弱引用的self。
但是如果只是这样写的话,可能还会出现一个问题,用__weak修饰,block拿到的是弱引用的self,这样如果外部的self被销毁掉,比如pop出去的话,block内部的self也会被释放掉,此刻block内部的工作还没有做完啊,就贼尴尬。
所以在block内部,还可以用__strong修饰weakSelf。对weakSelf形成强引用关系,这样不管你外部有没有释放,和我这个block内部都没有关系啦,等我block执行完之后,也会自动释放掉strongSelf,开心😊~~
这样算是简单的弄清楚这一系列关系了。如果大家想要更深入了解,可以看看Objective-C高级编程这本书,讲得很深,要反复的看~