id 与 void * 转换
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 * 转换的更多相关文章
- ARC 类型转换:显式转换 id 和 void *
http://blog.csdn.net/chinahaerbin/article/details/9471419 /* * ARC有效时三种类型转换: */ 1.__bridge ...
- VC中句柄、指针、ID之间的转换
win32直接操作的是句柄HANDLE,每个句柄就对应windows窗口,而vc对HANDLE进行类封装,间接操作的都是HANDLE,现在句柄只是类的一个成员变量. 从句柄到指针 CWnd* pWnd ...
- 【转载】混编ObjectiveC++
原文:混编ObjectiveC++ 最近有点炒冷饭的嫌疑,不过确实以前没有Git Or Blog的习惯,所以很多工作上的技术分享就存留在了电脑的文档里,现在还是想重新整理一下,再分享出来. 混编C++ ...
- 新浪微博id的62进制转换
某条微博链接 某条微博的链接如下,同样省略了后面的无关参数 http://weibo.com/2803301701/CeaOU15IT CeaOU15IT为这条微博的mid,与之相对应的还有一个id, ...
- org.Hs.eg.db包简介(转换NCBI、ensemble等数据库中基因ID,symbol等之间的转换)
1)安装载入 ------------------------------------------- if("org.Hs.eg.db" %in% rownames(install ...
- json转换成对象
在json转换成对象时,json的key会与java 类的字段一一对应.如果没有映射上的java字段会在该数据类型上填充默认值,如int 0,String null 等. 没有映射的json key在 ...
- Json转换利器Gson之实例一-简单对象转化和带泛型的List转化 (转)
Gson 是 Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库.可以将一个 JSON 字符串转成一个 Java 对象,或者反过来. jar和源码下载地址: h ...
- BlocksKit初见:一个支持将delegate转换成block的Cocoa库
简介 项目主页: https://github.com/zwaldowski/BlocksKit BlocksKit 是一个开源的框架,对 Cocoa 进行了扩展,将许多需要通过 delegate 调 ...
- SpringMvc 相关,bean map转换,百度天气,base64.js,jsBase64.java;
1. Map<String, Object>与JavaBean[POJO, Model]转换; //model public class model{ private int id; pr ...
随机推荐
- Swift - JPush极光推送的使用3(根据Alias别名,给某个指定用户发推送)(转)
一.别名(alias)介绍 (1)我们可以给每一个安装了应用程序的用户,取不同别名来标识(比如可以使用用户账号的 userid 来作为别名). (2)以后给某个特定用户推送消息时,就可以用此别名来指定 ...
- 解决Linux命令行为什么变成-bash-3.2$
在Linux服务器上创建了一个新用户probe,是这样创建的: [root@localhost home]# groupadd -g 501 probe [root@localhost home]# ...
- 趣味编程:CPS风格代码(C#,F#版)
CPS风格代码(C#版) using System; namespace fp { class CPS { static int add(int x, int y) => x + y; stat ...
- 吴裕雄 数据挖掘与分析案例实战(13)——GBDT模型的应用
# 导入第三方包import pandas as pdimport matplotlib.pyplot as plt # 读入数据default = pd.read_excel(r'F:\\pytho ...
- javascritp伪协议
[javascritp伪协议] 将javascript代码添加到客户端的方法是把它放置在伪协议说明符javascript:后的URL中.这个特殊的协议类型声明了URL的主体是任意的javascript ...
- Access to the path 'C:\inetpub\wwwroot\mysite\images\savehere' is denied.
访问路径被拒绝 我解决了这个设置: IIS>应用程序池> [您的站点]>高级设置...>标识>内置帐户> LocalSystem
- php拓展安装
Yaf安装配置:http://www.laruence.com/manual/yaf.install.html#yaf.installation.linux 下载Yaf的最新版本, 解压缩以后, 进入 ...
- suse安装gcc,升级到4.8.5
前面这些是挂载iso,如果iso可以使用,就不需要下面几步. cd /etc/zypp/repos.d mkdir iso chmod -R 777 iso mount -o loop /media/ ...
- python之生产者消费者模型
#Auther Bob #--*--conding:utf-8 --*-- #生产者消费者模型,这里的例子是这样的,有一个厨师在做包子,有一个顾客在吃包子,有一个服务员在储存包子,这个服务员我们就可以 ...
- [leetcode]367. Valid Perfect Square验证完全平方数
Given a positive integer num, write a function which returns True if num is a perfect square else Fa ...