自從開始使用ARC(Automatic Reference Counting)後,我覺得這算是Objective-C的一個重大進步,但是,但是,並不代表寫程式時不需要思考如何管理物件與記憶體了,還是要跟一堆關鍵字(strong、weak、__bridge_transfer、等等)打交道,還是要遵循一堆使用記憶體的相關守則與慣例,以前要想著release與retain,現在則要想著物件彼此間的關係圖。
底下記錄一個絆倒我的ARC陷阱,跟UIColor回傳CGColor有關。
在某個方法裡,我建立了UIColor物件,並以它的CGColor方法回傳CGColorRef,然後使用。
在某方法裡:
{
CGColorRef cgcolor = [UIColor colorWithRed: 0.2
green: 0.3
blue: 0.4
alpha: 1.0].CGColor;
[[self.view layer] setBackgroundColor: cgcolor];
}糟了,發生記憶體錯誤當掉了,怎麼會這樣呢?
使用ARC以前:上面程式碼裡的UIColor物件會被autorelease,我們知道,在方法回傳結束前,這個物件會是存在的,所以cgcolor會指向存在的物件。
使用ARC以後:UIColor物件並沒有被任何變數指向,所以,ARC很聰明地將它釋放掉了,哈哈。
解法很多,我比較想採用的是這一個:
{
UIColor color = [UIColor colorWithRed: 0.2
green: 0.3
blue: 0.4
alpha: 1.0];
[[self.view layer] setBackgroundColor: color.CGColor];
}這麼一來,color是個strong變數,可以確保該物件不會被釋放,直到用完為止。
其他解法還有:以CGColorRetain與CGColorRelease抓住cgcolor。
另外,底下的寫法看似合理,但卻是個有問題的寫法:
{
UIColor color = [UIColor colorWithRed: 0.2
green: 0.3
blue: 0.4
alpha: 1.0];
CGColorRef cgcolor = color.CGColor;
[[self.view layer] setBackgroundColor: cgcolor];
}color物件在呼叫CGColor方法後就無處使用,所以ARC很可能會在setBackgroundColor之前就是放掉color物件,以致於cgcolor指向不存在的記憶體空間。
參考文章:
- Big Nerd Ranch Weblog的ARC Gotcha – Unexpectedly Short Lifetimes。
- Bob McCune的A funny thing happened on the way to the ARC。
No comments:
Post a Comment