2012/08/23

使用ARC時的一個小陷阱:UIColor回傳的CGColor

自從開始使用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指向不存在的記憶體空間。



參考文章:

No comments:

Post a Comment