• id 与 void * 转换


    MRC 环境下(Targets -> Setting -> Objective-C Automatic Reference Counting = NO)

      id 变量赋值给 void * 变量运行时不会有问题。

    id obj1 = [NSObject new];
    void * p = obj1;

      void * 变量赋值给 id 变量并调用其实例方法,运行时也不会有问题。

    id obj2 = p;
    [obj2 release];

     ARC境下

      直接赋值报错

      

      系统给出解决方案:

      

    __bridge 

    {
      id
    obj1 = [NSObject new];   void * p = (__bridge void *)obj1;   id obj2 = (__bridge id
    )p;
    }
     

      id 变量赋值给 void * 变量时的__bridge 与 __unsafe_unretained 修饰符相近,甚至会更低。如果管理时不注意 id 对象的持有者,就会因悬垂指针而导致程序崩溃。

      PS:指针指向曾经存在的对象,但该对象现在不存在了,那么该指针即为悬垂指针

      在代码中加入了 dict = nil 运行时会 crash。如下:

    {
      NSDictionary * dict = @{ @"k": @"v" };   void * p = (__bridge void *)(dict);   dict = nil;   NSLog(@"%@", p);         
    }

      __bridge 还有另外两种转换:__bridge_retained__bridge_transfer。

    __bridge_retained 

      __bridge_retained 转换会导致被赋值的变量也持有所赋值的对象,等同于 MRC 环境下使用的 retain 方法。MRC 环境下使用无效果。

      MRC 环境下写法: 

    {
      NSDictionary * dict = @{ @"k": @"v" };   void * p = [dict retain];    // dict.retainCount = 2
    }

      ARC 环境下写法:

    {
      NSDictionary * dict = @{ @"k": @"v" };
      void * p = (__bridge_retained void *)(dict);   // dict.retainCount = 2
    }

     

    __bridge_transfer

      __bridge_transfer 转换与 __bridge_retained 行为相反,原有的变量在通过 __bridge_transfer 赋值给目标变量后引用计数减一,等同于 MRC 环境下使用的 release 方法。MRC 环境下使用无效果。

      MRC 环境下写法:

    {
      const
    void * keys[] = {};   const void * values[] = {};   CFDictionaryRef cf = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, NULL, NULL); // retainCount = 1   NSDictionary * p = (__bridge NSDictionary *)(cf);  // retainCount = 2   CFRelease(cfDict);                     // retainCount = 1   NSLog(@"%d", CFGetRetainCount(cfDict));

    }

      ARC 环境下写法:

    {
      const void * keys[] = {};
      const void * values[] = {};
        
      CFDictionaryRef cf = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, NULL, NULL);
      NSLog(@"%d", CFGetRetainCount(cf));                // retainCount = 1
      NSDictionary * dict = (__bridge_transfer NSDictionary *)cf; // retainCount + 1 - 1
      NSLog(@"%d", CFGetRetainCount(cf));                // retainCount = 1
      NSLog(@"%@", cf);                          }

      原本 CFBridgingRelease() 会导致 cf 对象的引用计数 - 1,但因为 dict 指针是强引用,所以最终成了先引用计数 + 1,然后引用计数 - 1,对象的引用计数还是 1

      注意:引用计数是对象的属性,不是指针。

    Objective-C 对象与 CoreFoundation 对象

      这些转换多数用于 Objective-C 对象与 Core Foundation 对象之间。

      Core Foundation 对象主要使用在用 C 语言编写的 CoreFoundation.framework 中,并使用引用计数的对象。两者对引用计数的操作方法:

    Objective-C Core Foundation Effect
    retain CFRetain() retainCount + 1
    release CFRelease() retainCount - 1
    retainCount CFGetRetainCount()  

      Core Foundation 对象与 Objective-C 对象不同之处只在于是由 CoreFoundation.framework 还是 Foundation.framework 所生成的。无论是由哪种框架生成的对象,都能在不同的框架中使用。Foundation.frameworkapi 生成并持有的对象可以用 CoreFoundation.frameworkapi 释放。当然,反过来也是可以的。

      MRC 环境下只用简单的 C 语言的转换也能实现互换。另外这种转换不需要使用额外的 CPU 资源,因此也被称为"免费桥"(Toll-FreeBridge)。如下函数:

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

        id CFBridgingRelease(CFTypeRef X) {   return (__bridge_transfer id)X;   }

    {
      NSDictionary * dict = (@{ @"k": @"v" });   CFDictionaryRef cf = CFBridgingRetain(dict);   CFShow(cf);   NSLog(@"%d", dict.retainCount);  // 2 dict.retainCount = CFGetRetainCount(cf)
      CFRelease(cf);
      NSLog(@"%d", dict.retainCount);  // 1
    }

      由此可知,Objective-C 对象能够作为 Core Foundation 对象来使用。也可以通过 CFRelease 来使引用计数减一。当然,也可以使用 __bridge_retained 转换来替代 CFBridgingRetain()。大家可选用自己更熟悉的方法。

    CFDictionaryRef cf = (__bridge_retained CFDictionaryRef)dict;

      __bridge 转换不持有对象。

      这次反过来,将使用 Core Foundationapi 生成并持有对象,将该对象作为 Objective-C 对象来处理。

    {
      CFMutableArrayRef cfObject = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
      NSLog(@"retain count = %d", CFGetRetainCount(cfObject));    // 1
      NSArray * arr = CFBridgingRelease(cfObject);           // retainCount + 1 - 1 
      NSLog(@"retain count = %d", CFGetRetainCount(cfObject));    // 1 
      NSLog(@"%@", arr);
    }

    参考文章:http://book.2cto.com/201305/23864.html 

  • 相关阅读:
    OPC UA认识汇总
    linux内核铁三角-进程(任务)调度
    nginx配置文件
    git和coding的使用
    php处理mysql的结果集
    php中self和$this还有parent的区别
    Mysql练习题
    SEO优化
    css3 旋转 八仙桌
    laravel笔记
  • 原文地址:https://www.cnblogs.com/dins/p/6710118.html
Copyright © 2020-2023  润新知