__bridge_retained/__bridge_transfer/__bridge使用詳解

當ARC有效時,屬性聲明的關鍵詞除strong,weak,unsafe_unretained外,也可以爲retain,assign,copy。
屬性聲明和所有權修飾符對應關係
屬性聲明    所有權修飾符
assign     __unsafe_unretained
copy       __strong
retain     __strong
strong     __strong
unsafe_unretained __unsafe_unretained
weak       __weak

屬性聲明和所有權修飾符的關係。

第一、__bridge_retained的使用

__bridge_retained轉換可使要轉換的變量也持有所賦值的對象
 void *p=0;
        {
        id obj=[[NSObject alloc] init];
        p=(__bridge_retained void*)obj;
        }
        NSLog(@"class=%@",[(__bridge id)p class]);
 輸出結果:
class=NSObject
分析:

變量作用域結束後,雖然obj失效,__bridge_retained轉換使變量p看上去處於持有該對象的狀態,因此該對象不會被釋放


第二、__bridge_transfer
當想把本來擁有對象所有權的變量,在類型轉換後,讓其釋放原先所有權的時候,需要使用 __bridge_transfer 關鍵字。
如在非ARC環境下:
id obj = (id)p;
[obj retain];
[(id)p release];
在ARC環境下,使用__bridge_transfer,如下所示:
id obj = (__bridge_transfer id)p;

__bridge_retained是編譯器爲我們做了retain操作,__bridge_transfer是編譯器爲我們做了release


第三、在 Core Foundation框架中的使用
CoreFoundation對象是用C語言實現CoreFoundation Framework的對象,也有引用計數的概念,使用的關鍵詞是CGRetain/CFRelease,
因爲和Foundation結構相同,在非ARC下可以用C語言的類型轉換,如下所示:
NSString *str=@"RichardYang";
 CFStringRef strRef=(CFStringRef)str;
在ARC環境下,因爲編譯器會管理Foundation對象的內存,但CoreFoundation對象卻不會處理,此時,使用關鍵詞__bridge/__bridge_retained進行處理。
1、使用__bridge_retained
 @autoreleasepool {
        CFMutableArrayRef cfObject=nil;
        {
            id obj=[[NSMutableArray alloc] init];
            cfObject=(__bridge_retained CFMutableArrayRef)obj;
            //CFShow(cfObject);
            printf("the retain count =%ld\n",CFGetRetainCount(cfObject));
        }
        printf("the retain count is %ld\n",CFGetRetainCount(cfObject));
        CFRelease(cfObject);//如果不執行CFRelease則內存泄露
    }
    輸出結果爲:
    the retain count =2
    the retain count is 1
2.使用__bridge
只做類型轉換,但是不修改對象(內存)管理權;
    @autoreleasepool {
        CFMutableArrayRef cfObject=nil;
        {
            id obj=[[NSMutableArray alloc] init];
            cfObject=(__bridge CFMutableArrayRef)obj;
            //CFShow(cfObject);
            printf("the retain count =%ld\n",CFGetRetainCount(cfObject));
        }
        //printf("the retain count is %ld\n",CFGetRetainCount(cfObject));
        CFRelease(cfObject);
    }
    CFRelease(cfObject);會拋異常,__bridge實現了轉換,並沒有保持對象。
3、使用__bridge_transfer
    @autoreleasepool {
        CFMutableArrayRef cfObject=CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
        printf("the retaincount is %ld\n",CFGetRetainCount(cfObject));
        
        /*
        * __bridge_transfer,對cfObject執行release操作,然後將對象賦給了obj,但是cfObject仍然指向存在的對象,可以正常使用
         */
        id obj=(__bridge_transfer id)cfObject;
        printf("after __bridge_transfer retaincount is %ld\n",CFGetRetainCount(cfObject));
        NSLog(@"class=%@",obj);
    }
    /*
     *obj跳出作用域,強引用失效,釋放對象,沒有內存泄露
     */    
      return 0;





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章