2012年8月9日 星期四

ARC - Automatic Referece Couting 實務經驗

以下是根據 ARC Best Practices 加上我的解釋

討論的對像是針對 @property 這個應用,不同的對象應該用那一種修飾
  • 數值型別 -assign
@property (assign) int numbers; @property (assign) CGPoint center;
  • id 或者說物件型別需要被 retain 的物件或者說在 object graph (註1) 中向下參考的物件 - strong
in Car.h@property (strong) Engine * kernel;
  •  應用 Protocol 的物件或是在 object graph 中向上參考的物件 - weak
in Engine.h@property (weak) Car * owner;  // 向上參考的物件
          @property (weak) id<SomeDelegate> delegate ; // delegate 的應用
  • Block 物件 -  copy
 typedef  void (^BlockType) (int a) ;
@property (copy) BlockType someBlock;
  •  IBOutlet 大部分是 weak 只有最上層的 IBOutlet ( View Controller 的 view )是 strong
Bridging - C 型別 (Core Fundation ) 以下簡稱 CF 和 Objective-C ( Foundation ) 以下簡稱 F 型別轉換時,有關記憶體管理應該注意的地方

  • __bridge - 沒有改變 retain count (注意是有兩個下底線),可以適用在 CF 轉 F 或是 F 轉 CF
  • __bridge_transfer - 用在 CF 轉 F 的時候,會將 CF 的 retain count 減 1
  • __bridge_retained - 用在 F 轉 CF 的時候,會將 F 的 retain count 加 1
我們來看幾個例子
ARC 寫法 - __bridge_transfer
id obj = (__bridge_transfer ) cf; // 預設是 __strong id obj ;
換成 non-ARC 的寫法的時候是
id obj = (id) cf;
[obj retain];  // strong 的關系
[(id) cf release]; //transfer 的關系

ARC 寫法 - __bridge_retained
id obj = [[NSObject alloc] init];
void *cf = (__bridge_retained void *) obj;
換成 non-ARC 的寫法的時候是 
id obj = [[NSObject alloc] init];
void * cf = obj;
[(id) cf retain];
此寫法通常最後會加上一個  CFRelease(cf) 來保持 retain count 平衡
另外有兩個方便的 function 可以用

CFTypeRef CFBridgingRetain(id X) {
     return (__bridge_retained CFTypeRef)X;
}

id CFBridgingRelease(CFTypeRef X) { 
    return (__bridge_transfer id)X;
}
id obj = (__bridge_transfer ) cf;
可以改寫成
id obj =CFBridgingRelease(cf);

void *cf = (__bridge_retained void *) obj;
可以改寫成
void *cf = CFBridgingRetain (obj);

// 待續...




註1:object graph 在 wiki 的解釋中說明是表達物件之間關系的圖表。物件的關係我們可以這樣想像,比如說有兩個 Class Car 和 Engine。物件化的時候 car 這個物件需要 engine 這個物件,因為 car 在實際應用中沒有 engine 就不算是 car,反過來說 engine 沒有 car 這個物件還是可以擁有完整的意思。所以在 car 指向 engine 的 property 用 strong 來修飾,而 engine 指向 car 的property 就用 weak 來修飾,以免造成 retain cycle。可以看以下圖示

沒有留言:

張貼留言