zoukankan      html  css  js  c++  java
  • 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 

  • 相关阅读:
    xls与csv文件的区别
    青音,经典爱情语录
    win7用户账户自动登录方法汇总
    How to using Procedure found Lead Blocker
    FTS(3) BSD 库函数手册 遍历文件夹(二)
    FTS(3) BSD 库函数手册 遍历文件夹(一)
    DisplayMetrics类 获取手机显示屏的基本信息 包括尺寸、密度、字体缩放等信息
    About App Distribution 关于应用发布
    FTS(3) 遍历文件夹实例
    OpenCV 2.1.0 with Visual Studio 2008
  • 原文地址:https://www.cnblogs.com/dins/p/6710118.html
Copyright © 2011-2022 走看看