问题概要

  • _block是否是一个OC对象?
  • __bridge相关。
_block是否是一个OC对象?
  • 结论

    • 一般来说,block可以看做一个OC对象,但是在编译器底层,block又可以被细分为block对象,独立于OC对象的存在。
  • 分析

    • 根据苹果官方文档,明确的指明block是一个OC对象。有兴趣的在文档里面搜索Working with Blocks
    • 根据文档Clang 4.0 documentation里面描述的,这里引入一个概念——可保留对象指针(retainable object pointer),这是苹果官方文档Working with Blocks这章里面没有出现过的字眼,这里面是这样描述的:可保留对象指针分为三类: block块指针,OC对象指针,由__attribute__((NSObject))标志的指针。
    • block一般可以认为是一个OC对象,但是在编译器底层有细分为block对象,独立于OC对象的存在,但是无论怎么描述,可保留对象(一般认为的OC对象)指针都可以受ARC管理。
__bridge相关。(参考文档Clang 4.0 documentation)
  • __bridge

    • 在文档中关于__bridge的描述是这样的,可以实现非可保留对象指针以及可保留对象指针之间的转换,转换的两个对象必须一个是可保留对象,另外一个是非可保留对象,不做对象所有权转移,为了方便理解,可保留对象可以认为是一般情况下的OC对象(包括block等),非可保留对象可以认为是Core Foundation里面的对象等。
  • __bridge_retain

    • 文档中对__bridge_retained的描述是这样的,__bridge_retained把可保留对象指针类型转换为非可保留对象指针类型(不可以倒过来),转换前后对象所有权转移(从被转换者转移到转换者)。
    (void)bridgeRetain{
    CFStringRef fontName = (__bridge CFStringRef)@"PingFangSC-Thin";
    CGFloat fontSize = ;
    CTFontRef fontRef = CTFontCreateWithName(fontName, fontSize, NULL);
    {
    id obj = [[NSObject alloc] init];
    fontRef = (__bridge CTFontRef)obj;
    }
    CFRelease(fontRef);
    }
    • 使用__bridge的情况
    关于block以及__bridge的一些笔记-LMLPHP

     
    • 一个已经释放掉的对象重复释放,本质上是坏内存访问,无论调这个类的什么方法都会出现坏内存crash,并不特指释放方法,obj的对象所有权没有转移,还是由自身去管理内存,ARC下,可保留对象的内存管理在自动调用release来释放内存。
    • 使用bridge_retain之后可以运行通过,对象所有权转移到fontRef,所以必须要调用CFRelease函数来管理内存,不然会发生内存泄露。

  • __bridge_transform

    • __bridge_transform:把非可保留对象指针类型转换为可保留对象指针类型,对象所有权转移,ARC下,自动调用realeas操作。
    //示例函数
    (void)bridgeTransform{
    CFStringRef fontName = (__bridge CFStringRef)@"PingFangSC-Thin";
    CGFloat fontSize = ;
    CTFontRef fontRef = CTFontCreateWithName(fontName, fontSize, NULL);
    UIFont font = (__bridge_transfer UIFont)fontRef;
    }
    • 使用__bridge会出现内存泄露,fontRef的对象所有权没有转移,内存还是要手动释放。

      关于block以及__bridge的一些笔记-LMLPHP

      ​

    • 使用__bridge_transform的情况,对象所有权转移,内存转移到font来管理,ARC下,可保留对象会自动调用release操作。
      关于block以及__bridge的一些笔记-LMLPHP

     
  • 目前的项目中的使用很多关于__bridge的用法

    • 有以下用法的,感觉先将UIImage转CGImage,在转id再赋给contents,感觉中间的操作是可以去掉的,但是去掉中间的操作发现contents展示是空的。
    //这样
    animationView.contents = (__bridge id)MQZ_LOAD_QZONE_IMAGE_NO_CACHE("mqz_live_bg.jpg").CGImage;
     
    • 在《ios核心动画高级技巧》这本书中是这样描述的,造成这个现象是由Mac OS的历史原因造成的。它之所以被定义为id类型,是因为在Mac OS系统上,这个属性对CGImage和NSImage类型的值都起作用。如果你试图在iOS平台上将UIImage的值赋给它,只能得到一个空白的图层。

参看资料
05-11 15:12