MRC 环境下

  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:指针指向曾经存在的对象,但该对象现在不存在了,那么该指针即为悬垂指针

  __bridge 不持有对象。

  在代码中加入了 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, , 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.framework 的 api 生成并持有的对象可以用 CoreFoundation.framework 的 api 释放。当然,反过来也是可以的。

  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;

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

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

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

id 与 void * 转换的更多相关文章

  1. ARC 类型转换:显式转换 id 和 void *

    http://blog.csdn.net/chinahaerbin/article/details/9471419 /* * ARC有效时三种类型转换: */ 1.__bridge           ...

  2. VC中句柄、指针、ID之间的转换

    win32直接操作的是句柄HANDLE,每个句柄就对应windows窗口,而vc对HANDLE进行类封装,间接操作的都是HANDLE,现在句柄只是类的一个成员变量. 从句柄到指针 CWnd* pWnd ...

  3. 【转载】混编ObjectiveC++

    原文:混编ObjectiveC++ 最近有点炒冷饭的嫌疑,不过确实以前没有Git Or Blog的习惯,所以很多工作上的技术分享就存留在了电脑的文档里,现在还是想重新整理一下,再分享出来. 混编C++ ...

  4. 新浪微博id的62进制转换

    某条微博链接 某条微博的链接如下,同样省略了后面的无关参数 http://weibo.com/2803301701/CeaOU15IT CeaOU15IT为这条微博的mid,与之相对应的还有一个id, ...

  5. org.Hs.eg.db包简介(转换NCBI、ensemble等数据库中基因ID,symbol等之间的转换)

    1)安装载入 ------------------------------------------- if("org.Hs.eg.db" %in% rownames(install ...

  6. json转换成对象

    在json转换成对象时,json的key会与java 类的字段一一对应.如果没有映射上的java字段会在该数据类型上填充默认值,如int 0,String null 等. 没有映射的json key在 ...

  7. Json转换利器Gson之实例一-简单对象转化和带泛型的List转化 (转)

    Gson 是 Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库.可以将一个 JSON 字符串转成一个 Java 对象,或者反过来. jar和源码下载地址: h ...

  8. BlocksKit初见:一个支持将delegate转换成block的Cocoa库

    简介 项目主页: https://github.com/zwaldowski/BlocksKit BlocksKit 是一个开源的框架,对 Cocoa 进行了扩展,将许多需要通过 delegate 调 ...

  9. SpringMvc 相关,bean map转换,百度天气,base64.js,jsBase64.java;

    1. Map<String, Object>与JavaBean[POJO, Model]转换; //model public class model{ private int id; pr ...

随机推荐

  1. 代码报错记录-MAVEN-2

    报错: 编译错误,程序包org.junit找不到 原因: 这个是父项目,报错是在子项目中,子项目使用了父项目的junit包,由于scope是test,导致子项目在编译时找不到junit, 修改: 将父 ...

  2. cobbler全自动批量安装部署linux

    Cobbler的设计方式: Cobbler的配置结构基于一组注册的对象.每个对象表示一个与另一个实体相关联的实体(该对象指向另一个对象,或者另一个对象指向该对象).当一个对象指向另一个对象时,它就继承 ...

  3. HttpSession的关键属性和方法

    1.当一个用户向服务器发送第一个请求时,服务器为其建立一个session,并为此session创建一个标识号:2.这个用户随后的所有请求都应包括这个标识号.服务器会校对这个标识号以判断请求属于哪个se ...

  4. Word 2003-在一个方框里打勾或打叉

    最近有个同事问我,如何在Word中输出一个方框中打勾的符号?查了一下帮助,其实很简单,特记录如下,供碰到的朋友参考: 一.在方框中打勾的方法: 先输入一个大写字母R,然后将R选中,将字体改为“Wind ...

  5. kubeadmin 部署(centos 7)

    安装指定版本docker:# yum list docker-ce --showduplicates | sort -ryum install docker-ce-18.06.1.ce-3.el7vi ...

  6. go 第一个项目

    官方下载go: https://golang.org/dl/ 安装完成后:cmd命令下:go go env:查看当前的环境配置:

  7. ES5之defineProperty

    一 概述 Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象. 对象里目前存在的属性描述符有两种主要形式:数据描述符和存 ...

  8. 使用生活实例理解Asp.net运行时

    学习编程语言,掌握面向对象的编程思想尤为重要,一旦理解了面向对象的这种概念,那么好些地方拿到生活中去理解,就容易的多了.书本上的枯燥干涩的语言,对于好多人来说,即难懂,更难长时间牢牢记得.但是编程语言 ...

  9. [udemy]WebDevelopment_HTML5

    Build Your First Website  装一个subline text HTML default rule tags with opening and closing <!DOCTY ...

  10. php不重新编译,安装未安装过的扩展,如curl扩展

    假设我们的之前的php安装于/data/php下. 1.找到之前安装的PHP源码包,把它重新解压出来,进入到要安装的扩展目录. > cd /data/php-5.6.11/ext/curl (* ...