在XIB里面关于@property,@synthesize,release,dealloc的怪现象
在一个XIB中,有一个IBOutlet的UILabel叫 label_ XIB的线已经连好了
IBOutlet UILabel *label_;
如果我定义
@property(nonatomic,assign)UILabel *label_;
@synthesize label_;
那么在dealloc里面加
[label_ release];
会造成程序的crash 给出的错误代码是
[CALayer release]: message sent to deallocated instance 0x8f14800(这个数字可以是随便的地址啦)
但是,如果我定义
@property(nonatomic,readonly)UILabel *label_;
@synthesize label_;
在dealloc里面加
[label_ release];
程序就不会crash
进一步,如果我定义
@property(nonatomic,assign)UILabel *label;
@synthesize label = label_;
在dealloc里面加
[label_ release];
程序依然不会crash
自然,即使是把上面的assign换成readonly自然也不会crash
接下来我们继续研究,如果是retain呢
如果我定义这个
@property(nonatomic,retain)UILabel *label_;
@synthesize label_;
那么在dealloc里面
[label_ release];
那么不会crash!
可以想到,如果继续定义
@property(nonatomic,retain)UILabel *label;
@synthesize label = label_;
就更加不会crash了,事实也证明了这一点
看来这玩意儿还是有规律可循的,写了这么多,大概规律也知道了
CocoaTouch 的SDK在将对应的XIB反序列话的时候,会将反序列出类的实例的指针值赋值给你的这个UIView对应的IBOutlet的指针,如果你的这个view 定义了自己存取器方法,而且将存取器的名字替代了IBOutlet的名字(或者说名字取成相同的)(这点很重要,如果不满足这一点的话,则不会出现crash的情况),那么这个赋值操作会调用这个自定义方法,即你的存取器方法定义的引用类型就决定了最终UIView对这个反序列后实例的引用类型, 如果你像上面第一种情况那样子定义assign的话,那么你的UIView对这个UILabel的引用就是assign,所以自然的,你在dealloc 里面就不能调用release。这样想,retain就好理解了,我在想,如果是readonly的话,之所以不会出问题,是因为在这个时候,既然不能用 你自定义的存取器方法对那个类的实例指针进行赋值,那么SDK里面自己的方法还是会按照默认情况下的来,即还是retain,所以在dealloc里面调 用release是不会有什么问题的。
所以简单的原则就是:
如果是IBOutlet的变量,那么定义存取器的时候,假设要做成assign,那么存取器方法的名字一定不要和IBOutlet的名字相同,如果相同了,就不能在dealloc里面release!
第一篇原创的技术文章,写完算是有点感觉了~