关于delegate为什么设置为assign而不是retain

来源:互联网 发布:mysql删除有外键的数据 编辑:程序博客网 时间:2024/05/18 01:50
当你开始写iOS程式不久,应该开始面对到很多的delegate, 
不管是用别人的library或是自己写library,可能都逃不了delegate。 
为了怕有些人不知道什么是delegate,在这边简单的介绍一下, 
delegate中文叫做委托,通常会用在class内部把一些事件处理"委托"给别人去完成。 
举个例子,XML Parser可能他知道怎么parse xml,但是parse到的东西要怎么处理xml parser可能不知道。 
所以NSXMLParser就提供了一个NSXMLParserDelegate给client去实作, 
当parse到某个element的时候,就callback delegate所定义的message, 
让他client自己去决定怎么去处理这个element。 
好吧,我承认我解释的很模糊,不过我这篇本来就不是要你搞懂什么是delegate, 
而是针对使用或是设计delegate的时候,可能会要注意的事情。 

在我们的class中设计delegate的时候,我们通常会有几个注意事项。 
假设我的class叫做MyClass,那我们可能会有定义一个MyClassDelegate这个protocol当作我的delegate protocol。 
而MyClass中我们可能是这样写。 
@protocol MyClassDelegate <NSObject> 
- (void) myClassOnSomeEvent:(MyClass*)myClass; 
@end 

@interface MyClass 

    id<MyClassDelegate> _delegate; 

@property (nonatomic, assign) delegate; 
@end 
上面的code我们注意到delegate此property是定义为@property (assign)。 
为什么我们不用retain而要用assign呢? 
原因就是在于iOS的reference counting的环境中,我们必须解决circular count的问题。 
让我们来写写我们平常都怎么用delegate的,下面的code我想大家应该不陌生 
- (void)someAction 

   myClass = [MyClass new]; 
   myClass.delegate = self; 
   .... 

这边很快的就出现circular reference了 
假设上面的code是写在一个myViewController的物件当中, 
之后一旦myViewController的reference count变成1的时候, 
myViewController跟myClass这两个兄弟两只剩下互相retain,那就变成了孤岛,也​​就因此造成了memory leak!!! 
 

也因为这样,iOS官方文件才会要建议我们所以的delegate都要用assign property。 
也就是所谓"weak reference"的property,他的特色就是虽然会持有对方的reference,但是不会增加retain count。 
如此下来,当myViewController的retain count变成0,则会dealloc。 
同时在dealloc中,也一并把myClass release,则myClass也跟着被release。 
- (void)dealloc 

   [myClass release]; 
   [super dealloc]; 


 

事情就结束了吗? 还没有唷... 
这边还有一个大家常常忘记的重点,那就是上面的dealloc这样写会有潜在危险。 
应该要改成这样 
- (void)dealloc 

   myClass.delegate = nil; 
   [myClass release]; 
   [super dealloc]; 

你可能会很纳闷,myClass不是马上就会被release了吗? 干嘛要先把他的delegate设成nil? 
那是因为我们假设myClass会马上会被dealloc,但是现实状况这个是不一定的, 
有可能里面内部有建个NSURLConnection,或是正在做某件事情而让其他物件也retain myClass。 
如果myClass没有马上dealloc,那他的myClass.delegate不就正指向一个不合法的位置了吗? (此种pointer称作dangling pointer) 

 

解决方法是在MyViewController的dealloc中,在release myClass之前, 
要先把原本指向自己的delegate改设成nil,这样才可以避免crash发生。 
在我之前写的project,很大一部份的crash都是这样造成的,因为这个问题通常不是每次都发生, 
但是发生的时候确很难在重新复制,所以不可不慎啊。 

 

但是很兴奋的是到了iOS5中的Automatic Reference Counting 这个问题可以有所改善。 
在ARC中提出了一个新的weak reference的概念来取代原本的assign, 
weak reference指到的物件若是已经因retain count归零而dealloc了,则此weak reference也自动设成nil。 
而原本​​旧的这种assign的作法,在ARC中叫做__unsafe_unretained,这只是为了相容iOS4以下的版本。 

回顾重点: 
如果你是写library给别人用的,记得把你的delegate设成assign property,这样才不会造成circular reference 
当你是要始用别人的library,记得在你自己dealloc的时候,把delegate设成nil,以避免crash的事情发生。 
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 入户门对着窗户怎么办 院子门对着窗户怎么办 电梯入户同梯人怎么办 房门对着电梯门怎么办 房门对着电梯口怎么办 大门对着电梯门怎么办 房门和电梯对着怎么办 搬家与生肖相冲怎么办 颈椎生理曲度变直怎么办 整个背部长痘痘怎么办 卧室门对着厨房怎么办 卧室门正对厕所怎么办 进门正对厕所门怎么办 门口对着厕所门怎么办 厨房门比大门高怎么办 鼻子上山根横纹怎么办 墙与床的缝隙怎么办 床边与墙有间隙怎么办 抽了烟头晕恶心怎么办 9个月宝宝口臭怎么办 狗舔了人的伤口怎么办 狗舔了结痂伤口怎么办 狗狗指甲变黑了怎么办 狗狗不肯剪指甲怎么办 厕所门对厨房门怎么办 房间门对着镜子怎么办 门直对着楼梯口怎么办 厨房门对着客厅怎么办 卧室正对着马路怎么办 主卧厕所对着床怎么办 卧室门对着床头怎么办 主卧厕所门对床怎么办 老人晕车怎么办最有效方法 货车油刹不好用怎么办 7岁儿童喉咙有痰怎么办 3岁宝宝喉咙有痰怎么办 冰箱正对厨房门怎么办 买了连廊高层怎么办 想买电玩瑞文怎么办 财位旁边有窗户怎么办 入室门对卧室门怎么办