iPhone尺寸

/ 屏幕尺寸 物理pt 像素pxiPhone4 320 480 2倍iPhone4s
320 480 2倍iPhone5
320
568 2倍iPhone6
375 667 2倍iPhone6plus
414
736 3倍iPhone6s 375

  • 667 2倍iPhone6splus
    414 736 3倍 /
    /*Icon.png – 57×57 iPhone (ios5/6) Icon@2x.png – 114×114 iPhone Retina (ios5/6)

Icon-72.png – 72×72 iPad (ios5/6) Icon-72@2x.png - 144×144 iPad Retina (ios5/6)
Icon-60@2x.png - 120x120 iphone & ipod touch (ios7/8)
Icon-60@3x.png - 180x180 iphone6 plus (ios8)

Icon-76.png - 76x76 ipad2 & ipad mini (ios7/8)
Icon-76@2x.png - 152x152 ipad retina (ios7/8)*/

model归档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#import <Foundation/Foundation.h>

#warning 归档第一步:让model签订NSCoding协议
@interface Student : NSObject<NSCoding>

@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)NSInteger age;
@property(nonatomic,copy)NSString *gender;
@end


#import "Student.h"

@implementation Student

#warning 归档第二步:对model属性进行编码
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.gender forKey:@"gender"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
#warning 归档第三步:对model进行解码
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
self.name =
[aDecoder decodeObjectForKey:@"name"];
self.gender =
[aDecoder decodeObjectForKey:@"gender"];
self.age =
[aDecoder decodeIntegerForKey:@"age"];
}
return self;
}


@end


/***************写入model*************************/
//缓存自定义model模型数据
//需要使用iOS中归档/反归档,专门来存储model数据到本地

#warning 归档第四步:对model进行归档操作
Student *stu = [[Student alloc]init];
stu.name = @"大水杯";
stu.gender = @"男";
stu.age = 18;
NSString *archiverPath = [documentPath stringByAppendingPathComponent:@"student"];

//归档类
BOOL result3 =
[NSKeyedArchiver archiveRootObject:stu toFile:archiverPath];

if (result3) {
NSLog(@"归档成功");
}else
{
NSLog(@"归档失败");
}

//反归档取出model数据
Student *stu1 = [NSKeyedUnarchiver unarchiveObjectWithFile:archiverPath];
NSLog(@"name = %@ %@ %ld",stu1.name,stu1.gender,stu1.age);
/***************写入model*************************/

UISearchController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  self.allMovieArray = [NSMutableArray array];
self.searchArray = [NSMutableArray array];

/************UITableView*************/
self.myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain];
[self.view addSubview:self.myTableView];
[_myTableView release];
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
/************UITableView*************/


/************UISearchController*************/
//创建UISearchController
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.myTableView.tableHeaderView = self.searchController.searchBar;

//成为代理
self.searchController.searchResultsUpdater = self;
/************UISearchController*************/


/************interface*************/
//设置开始搜索时背景显示与否 页面背景阴影效果,一般不要设置.
self.searchController.dimsBackgroundDuringPresentation = NO;

//设置点击搜索框时候隐藏导航栏
self.searchController.hidesNavigationBarDuringPresentation = NO;
/************interface*************/


/************searchBar*************/
self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);
// [searchBar sizeToFit]:设置searchBar位置自适应
[self.searchController.searchBar sizeToFit];
/************searchBar*************/



/*****************searchMethod*********s*********/
//UISearchController的移除
//在viewWillDisappear中要将UISearchController移除, 否则切换到下一个View中, 搜索框仍然会有短暂的存在.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.searchController.active) {
self.searchController.active = NO;
[self.searchController.searchBar removeFromSuperview];
}
}
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
NSString *searchString = [self.searchController.searchBar text];
NSLog(@"===%@",searchString);

NSPredicate *preicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[c] %@", searchString];
if (self.searchArray!= nil) {
[self.searchArray removeAllObjects];
}
//过滤数据
/*
对象数组过滤

ios提供了一个filteredArrayUsingPredicate 方法,通过给定条件来进行过滤,过滤后形成一个新的数组。 而NSMutableArray提供了一个filterUsingPredicate方法,在原数组中保留符合条件的数组元素。
*/
self.searchArray= [NSMutableArray arrayWithArray:[self.allMovieArray filteredArrayUsingPredicate:preicate]];
NSLog(@"searchArray===%@",self.searchArray);

//刷新表格
[self.myTableView reloadData];
}
/*****************searchMethod*********s*********/



/*****************tableviewmethod*********s*********/
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//如果searchController是活动状态,说明是当前正在搜索
if (self.searchController.active) {

return self.searchArray.count;
}
else {
return self.allMovieArray.count;
}

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if (self.searchController.active) {
cell.textLabel.text = [self.searchArray objectAtIndex:indexPath.row];
}
else {
cell.textLabel.text = [self.allMovieArray objectAtIndex:indexPath.row];
}


return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

DetailViewController *detailVC = [[DetailViewController alloc] init];
//如果searchController是活动状态,说明是当前正在搜索
if (self.searchController.active) {

NSLog(@"选中搜索列表");
detailVC.movieName = [self.searchArray objectAtIndex:indexPath.row];
}
else {

NSLog(@"选中所有列表");
detailVC.movieName = [self.allMovieArray objectAtIndex:indexPath.row];
}
[self.navigationController pushViewController:detailVC animated:YES];
[detailVC release];

}


-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 60;

}
/*****************tableviewmethod*********s*********/

oc 播放gif动画

1
2
3
4
5
6
7
8
9
10
// 设定位置和大小
CGRect frame = CGRectMake(50,50,0,0);
frame.size = [UIImage imageNamed:@"load.gif"].size;
// 读取gif图片数据
NSData *gif = [NSData dataWithContentsOfFile: [[NSBundle mainBundle] pathForResource:@"load" ofType:@"gif"]];
// view生成
UIWebView *webView = [[UIWebView alloc] initWithFrame:frame];
webView.userInteractionEnabled = NO;//用户不可交互
[webView loadData:gif MIMEType:@"image/gif" textEncodingName:nil baseURL:nil];
[self.view addSubview:webView];

runtime 运行时机制 完全解读

我们前面已经讲过一篇runtime 原理,现在这篇文章主要介绍的是runtime是什么以及怎么用!希望对读者有所帮助!
首先,第一个问题,
1》runtime实现的机制是什么,怎么用,一般用于干嘛?
这个问题我就不跟大家绕弯子了,直接告诉大家,
runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。
在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者
比如说,下面一个创建对象的方法中,
举例:
OC :
[[MJPerson alloc] init]
runtime :
objc_msgSend(objc_msgSend(“MJPerson” , “alloc”), “init”)
第二个问题
runtime 用来干什么呢??用在那些地方呢?怎么用呢?
runtime是属于OC的底层, 可以进行一些非常底层的操作(用OC是无法现实的, 不好实现)

  • 在程序运行过程中, 动态创建一个类(比如KVO的底层实现)

  • 在程序运行过程中, 动态地为某个类添加属性\方法, 修改属性值\方法

  • 遍历一个类的所有成员变量(属性)\所有方法
    例如:我们需要对一个类的属性进行归档解档的时候属性特别的多,这时候,我们就会写很多对应的代码,但是如果使用了runtime就可以动态设置!
    例如,PYPerson.h的文件如下所示
    #import

@interface PYPerson : NSObject
@property (nonatomic, assign) int age;
@property (nonatomic, assign) int height;
@property (nonatomic, copy) NSString name;
@property (nonatomic, assign) int age2;
@property (nonatomic, assign) int height2;
@property (nonatomic, assign) int age3;
@property (nonatomic, assign) int height3;
@property (nonatomic, assign) int age4;
@property (nonatomic, assign) int height4;
@end
而PYPerson.m实现文件的内容如下
*

#import "PYPerson.h"

#import
@implementation PYPerson

  • (void)encodeWithCoder:(NSCoder )encoder
    {
    unsigned int count = 0;
    Ivar ivars = class_copyIvarList([PYPerson class], &count);
    for (int i = 0; i<count; i++) {
    // 取出i位置对应的成员变量
    Ivar ivar = ivars[i];

    // 查看成员变量
    const char *name = ivar_getName(ivar);

    // 归档
    NSString *key = [NSString stringWithUTF8String:name];
    id value = [self valueForKey:key];
    [encoder encodeObject:value forKey:key];

}
free(ivars);
}

  • (id)initWithCoder:(NSCoder )decoder
    {
    if (self = [super init]) {
    unsigned int count = 0;
    Ivar
    ivars = class_copyIvarList([PYPerson class], &count);

    for (int i = 0; i<count; i++) {

    *// 取出i位置对应的成员变量*
    Ivar ivar = ivars[i];
    
    *// 查看成员变量*
    const char *name = ivar_getName(ivar);
    
    *// 归档*
    NSString *key = [NSString stringWithUTF8String:name];
    id value = [decoder decodeObjectForKey:key];
    
    *// 设置到成员变量身上*
    [self setValue:value forKey:key];
    

    }

    free(ivars);

}
return self;
}

@end
这样我们可以看到归档和解档的案例其实是runtime写下的
学习,runtime机制首先要了解下面几个问题
1相关的头文件和函数
1> 头文件

  • 利用头文件,我们可以查看到runtime中的各个方法!

2> 相关应用

  • NSCoding(归档和解档, 利用runtime遍历模型对象的所有属性)
  • 字典 –> 模型 (利用runtime遍历模型对象的所有属性, 根据属性名从字典中取出对应的值, 设置到模型的属性上)
  • KVO(利用runtime动态产生一个类)
  • 用于封装框架(想怎么改就怎么改)
    这就是我们runtime机制的只要运用方向

3> 相关函数

  • objc_msgSend : 给对象发送消息
  • class_copyMethodList : 遍历某个类所有的方法
  • class_copyIvarList : 遍历某个类所有的成员变量
  • class_…..
    这是我们学习runtime必须知道的函数!

4.必备常识
1> Ivar : 成员变量
2> Method : 成员方法
从上面例子中我们看到我们定义的成员变量,如果要是动态创建方法,可以使用Method,
也许,看到这里,你是否对runtime有了更深入的了解呢?在这里,希望我们大家相互交流!有什么错误之处,还请指正

RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 )。编译完成之后直接顺序执行,无任何二义性。OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。
那OC是怎么实现动态调用的呢?下面我们来看看OC通过发送消息来达到动态调用的秘密。假如在OC中写了这样的一个代码:
1[obj makeText];其中obj是一个对象,makeText是一个函数名称。对于这样一个简单的调用。在编译时RunTime会将上述代码转化成
1objc_msgSend(obj,@selector(makeText));首先我们来看看obj这个对象,iOS中的obj都继承于NSObject。
123@interface NSObject <nsobject> {` Class isa OBJC_ISA_AVAILABILITY;}在NSObjcet中存在一个Class的isa指针。然后我们看看Class: 1234567891011121314typedef struct objc_class Class;struct objc_class { Class isa;// 指向metaclass` `Class super_class ; // 指向其父类 const char name ; // 类名 long version ;// 类的版本信息,初始化默认为0,可以通过runtime函数class_setVersion和class_getVersion进行修改、读取long info; // 一些标识信息,如CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含对象方法和成员变量;CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法; long instance_size ;// 该类的实例变量大小(包括从父类继承下来的实例变量);struct objc_ivar_list ivars; // 用于存储每个成员变量的地址 struct objc_method_list **methodLists ;// 与 info 的一些标志位有关,如CLS_CLASS (0x1L),则存储对象方法,如CLS_META (0x2L),则存储类方法;struct objc_cache cache; // 指向最近使用的方法的指针,用于提升效率; struct objc_protocol_list *protocols;// 存储该类遵守的协议}`

我们可以看到,对于一个Class类中,存在很多东西,下面我来一一解释一下:
Class isa:指向metaclass,也就是静态的Class。一般一个Obj对象中的isa会指向普通的Class,这个Class中存储普通成员变量和对 象方法(“-”开头的方法),普通Class中的isa指针指向静态Class,静态Class中存储static类型成员变量和类方法(“+”开头的方 法)。
Class super_class:指向父类,如果这个类是根类,则为NULL。
下面一张图片很好的描述了类和对象的继承关系:
iuqQFnm.png
注意:所有metaclass中isa指针都指向跟metaclass。而跟metaclass则指向自身。Root metaclass是通过继承Root class产生的。与root class结构体成员一致,也就是前面提到的结构。不同的是Root metaclass的isa指针指向自身。
Class类中其他的成员这里就先不做过多解释了,下面我们来看看:
@selector (makeText):这是一个SEL方法选择器。SEL其主要作用是快速的通过方法名字(makeText)查找到对应方法的函数指针,然后调用其函 数。SEL其本身是一个Int类型的一个地址,地址中存放着方法的名字。对于一个类中。每一个方法对应着一个SEL。所以iOS类中不能存在2个名称相同 的方法,即使参数类型不同,因为SEL是根据方法名字生成的,相同的方法名称只能对应一个SEL。
下面我们就来看看具体消息发送之后是怎么来动态查找对应的方法的。

首先,编译器将代码[obj makeText];转化为objc_msgSend(obj, @selector (makeText));,在objc_msgSend函数中。首先通过obj的isa指针找到obj对应的class。在Class中先去cache中 通过SEL查找对应函数method(猜测cache中method列表是以SEL为key通过hash表来存储的,这样能提高函数查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,则取superClass中查找。若能找到,则将method加
入到cache中,以方便下次查找,并通过method中的函数指针跳转到对应的函数中去执行。

scrollView加约束

#尊重原创 转自:http://www.jianshu.com/p/1cfeb1eab6c6
#

#先办到能设置contentSize

  • 得添加一个额外的视图,占位
  • scrollView中只添加个UIView
  • 其它的控件全部放在这个UIView上
  • 设置UIView的高度,即为scrollView的contendSize
  • 得设置水平居中
  • 约束完毕

##上下滚动

  • 1.添加一个UIView类型的子控件(这将是UIScrollView唯一的一个子控件)
  • 2.上下左右0
  • 3.高度(contentSize的高度,可滚动的高度)
  • 4.水平居中

##左右滚动

  • 1.添加一个UIView类型的子控件(这将是UIScrollView唯一的一个子控件)
  • 2.上下左右0
  • 3.宽度(contentSize的宽度,可滚动的宽度)
  • 4.竖直居中

##上下左右都能滚动

  • 1.添加一个UIView类型的子控件(这将是UIScrollView唯一的一个子控件)
  • 2.上下左右0
  • 3.宽度,高度(contentSize的宽度,可滚动的宽度,contentSize的高度,可滚动的高度)

storyboard传值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.


//得到点击的cell,sender是指触发跳转的那个控件,这里指的是点击的cell
UITableViewCell *cell = (UITableViewCell *)sender;

//通过当前被点击的cell得到点击位置
NSIndexPath *selectedIndexPath = [self.tableView indexPathForCell:cell];

Roster *roster = self.rosterArray[selectedIndexPath.row];

//得到要跳转的viewcontroller
ChatTableViewController *chatTableViewController = (ChatTableViewController *)[segue destinationViewController];

chatTableViewController.chatToRoster = roster;

}

tableview 下拉图片放大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

#import "RootViewController.h"

@interface RootViewController ()

@end

@implementation RootViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.

self.view.backgroundColor = [UIColor lightGrayColor];

[self setAutomaticallyAdjustsScrollViewInsets:NO];

self.myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewStylePlain];
[self.view addSubview:self.myTableView];
[_myTableView release];

//设置tableview的contentView距离上边界200
//相对于0点,已经向下偏移了-200
self.myTableView.contentInset = UIEdgeInsetsMake(200.0+64, 0, 0, 0);
self.myTableView.delegate = self;
self.myTableView.dataSource = self;


//相对于0点,图片坐标应该是(0,-200)
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -200.0, self.view.frame.size.width, 200)];
self.imageView.image = [UIImage imageNamed:@"hua.jpg"];
//设置imageView高度改变时宽度也跟着改变
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
[self.myTableView addSubview:self.imageView];
[_imageView release];

}


//指定多少行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}

//创建一个cell
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];

}

cell.textLabel.text = [NSString stringWithFormat:@"%ld",indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;

return cell;

}
//设置行高
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 80;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//点击后自动取消选中置灰效果
[tableView deselectRowAtIndexPath:indexPath animated:YES];

}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//刚开始y的偏移量初始值就是-264
NSLog(@"y1 === %f",scrollView.contentOffset.y);
CGFloat y = scrollView.contentOffset.y + 64;//加上导航栏高度,第一次是-200
NSLog(@"y2 === %f",y);

if (y < -200) {
CGRect frame = self.imageView.frame;
frame.origin.y = y;//imageView的frame是不断往上偏移
frame.size.height = -y;//tablview向下偏移了多少,高度就增加多少
self.imageView.frame = frame;
}

}


- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}


@end

view 的 clipsToBounds属性

取值:BOOL(YES/NO)作用:决定了子视图的显示范围当取值为YES时,超出父视图范围的子视图被剪裁不显示;当取值为NO时,超出父视图范围的子视图不被剪裁,显示。默认值为NO。
如下图所示:view2是view1的子视图
取值为NO时:
取值为YES时:

iOS之CF和OC之间类型转换

转自:http://blog.csdn.net/annkey123/article/details/8271806

自 Xcode4.2 开始导入ARC机制后,为了支持对象间的转型,Apple又增加了许多转型用的关键字。这一讲我们就来了解其用法,以及产生的理由。

###引子
我们先来看一下ARC无效的时候,我们写id类型转void*类型的写法:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id obj </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSObject</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> alloc</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">]</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> init</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> obj</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li></ol>

反过来,当把void*对象变回id类型时,只是简单地如下来写,

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id obj </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> p</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">obj release</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li></ol>

但是上面的代码在ARC有效时,就有了下面的错误:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    error</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">:</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">implicit</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> conversion of an </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">Objective</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">-</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">C pointer</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">        to </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">’</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*’</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">is</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> disallowed </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">with</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> ARC</span></span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">        </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> obj</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">                  </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">^</span></span></li><li class="L4" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L5" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    error</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">:</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">implicit</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> conversion of a non</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">-</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">Objective</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">-</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">C pointer</span></span></li><li class="L6" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">        type </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">’</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*’</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> to </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">’</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">’</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">is</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> disallowed </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">with</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> ARC</span></span></li><li class="L7" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">        id o </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> p</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L8" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">                </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">^</span></span></li></ol>

###bridge
为了解决这一问题,我们使用
bridge 关键字来实现id类型与void*类型的相互转换。看下面的例子。

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id obj </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSObject</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> alloc</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">]</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> init</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">obj</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L4" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id o </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge id</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li></ol>

将Objective-C的对象类型用 bridge 转换为 void* 类型和使用 unsafe_unretained 关键字修饰的变量是一样的。被代入对象的所有者需要明确对象生命周期的管理,不要出现异常访问的问题。
除过 bridge 以外,还有两个 bridge 相关的类型转换关键字:

  • __bridge_retained
  • __bridge_transfer

接下来,我们将看看这两个关键字的区别。

####bridge_retained
先来看使用
bridge_retained 关键字的例子程序:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id obj </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSObject</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> alloc</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">]</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> init</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge_retained </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">obj</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li></ol>

从名字上我们应该能理解其意义:类型被转换时,其对象的所有权也将被变换后变量所持有。如果不是ARC代码,类似下面的实现:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id obj </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSObject</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> alloc</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">]</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> init</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> obj</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p retain</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li></ol>

可以用一个实际的例子验证,对象所有权是否被持有。

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="lit" style="border-width: 0px; margin: 0px; padding: 0px;">0</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">{</span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    id obj </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSObject</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> alloc</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">]</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> init</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li><li class="L4" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    p </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge_retained </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">void</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">obj</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L5" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">}</span></li><li class="L6" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L7" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSLog</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(@</span><span class="str" style="border-width: 0px; margin: 0px; padding: 0px;">"class=%@"</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">,</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge id</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">class</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">]);</span></span></li></ol>

出了大括号的范围后,p 仍然指向一个有效的实体。说明他拥有该对象的所有权,该对象没有因为出其定义范围而被销毁。

####bridge_transfer
相反,当想把本来拥有对象所有权的变量,在类型转换后,让其释放原先所有权的时候,需要使用
bridge_transfer 关键字。文字有点绕口,我们还是来看一段代码吧。
如果ARC无效的时候,我们可能需要写下面的代码。

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="com" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">// p 变量原先持有对象的所有权</span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id obj </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">obj retain</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p release</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">];</span></span></li></ol>

那么ARC有效后,我们可以用下面的代码来替换:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="com" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">// p 变量原先持有对象的所有权</span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id obj </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge_transfer id</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">p</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li></ol>

可以看出来,bridge_retained 是编译器替我们做了 retain 操作,而 bridge_transfer 是替我们做了 release1。

###Toll-Free bridged
在iOS世界,主要有两种对象:Objective-C 对象和 Core Foundation 对象0。Core Foundation 对象主要是有C语言实现的 Core Foundation Framework 的对象,其中也有对象引用计数的概念,只是不是 Cocoa Framework::Foundation Framework 的 retain/release,而是自身的 CFRetain/CFRelease 接口。
这两种对象间可以互相转换和操作,不使用ARC的时候,单纯的用C原因的类型转换,不需要消耗CPU的资源,所以叫做 Toll-Free bridged。比如 NSArray和CFArrayRef, NSString和CFStringRef,他们虽然属于不同的 Framework,但是具有相同的对象结构,所以可以用标准C的类型转换。
比如不使用ARC时,我们用下面的代码:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> stringWithFormat</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">:...];</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> cfString </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li></ol>

同样,Core Foundation类型向Objective-C类型转换时,也是简单地用标准C的类型转换即可。
但是在ARC有效的情况下,将出现类似下面的编译错误:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">Cast</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> of </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">Objective</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">-</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">C pointer type </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">‘</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*’</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> to C pointer type </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">‘</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">’</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">aka </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">‘</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">const</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">struct</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> __CFString </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*’)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> requires a bridged cast</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">Use</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> __bridge to convert directly </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">no</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> change </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">in</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> ownership</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span></span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">Use</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> __bridge_retained to make an ARC </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">object</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> available </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">as</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> a </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">+</span><span class="lit" style="border-width: 0px; margin: 0px; padding: 0px;">1</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">‘</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">’</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">aka </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">‘</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">const</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">struct</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> __CFString </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*’)</span></span></li></ol>

错误中已经提示了我们需要怎样做:用 bridge 或者 bridge_retained 来转型,其差别就是变更对象的所有权。
正因为Objective-C是ARC管理的对象,而Core Foundation不是ARC管理的对象,所以才要特意这样转换,这与id类型向void*转换是一个概念。也就是说,当这两种类型(有ARC管理,没有ARC管理)在转换时,需要告诉编译器怎样处理对象的所有权。
上面的例子,使用 bridge/bridge_retained 后的代码如下:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> stringWithFormat</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">:...];</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> cfString </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li></ol>

只是单纯地执行了类型转换,没有进行所有权的转移,也就是说,当string对象被释放的时候,cfString也不能被使用了。

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> stringWithFormat</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">:...];</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> cfString </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge_retained </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">...</span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFRelease</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">cfString</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">);</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="com" style="border-width: 0px; margin: 0px; padding: 0px;">// 由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release</span></span></li></ol>

使用 __bridge_retained 可以通过转换目标处(cfString)的 retain 处理,来使所有权转移。即使 string 变量被释放,cfString 还是可以使用具体的对象。只是有一点,由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release。
实际上,Core Foundation 内部,为了实现Core Foundation对象类型与Objective-C对象类型的相互转换,提供了下面的函数。

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFTypeRef</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">  </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFBridgingRetain</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id  X</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">  </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">{</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">return</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">  </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge_retained  </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFTypeRef</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">X</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">}</span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L4" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">id  </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFBridgingRelease</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFTypeRef</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">  X</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">  </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">{</span></span></li><li class="L5" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">    </span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">return</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">  </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge_transfer  id</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">X</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L6" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">}</span></li></ol>

所以,可以用 CFBridgingRetain 替代 __bridge_retained 关键字:

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">[</span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> stringWithFormat</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">:...];</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> cfString </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFBridgingRetain</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">);</span></span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">...</span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFRelease</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">cfString</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">);</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="com" style="border-width: 0px; margin: 0px; padding: 0px;">// 由于Core Foundation不在ARC管理范围内,所以需要主动release。</span></span></li></ol>

bridge_transfer所有权被转移的同时,被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候,会经常用到 bridge_transfer 关键字。

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> cfString </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringCreate</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">...();</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">__bridge_transfer </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*)</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">cfString</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">;</span></span></li><li class="L2" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);"> </span></li><li class="L3" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span class="com" style="border-width: 0px; margin: 0px; padding: 0px; background-color: rgb(255, 255, 255);">// CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权,所以不需要调用 release</span></li></ol>

同样,我们可以使用 CFBridgingRelease() 来代替 __bridge_transfer 关键字。

prettyprint linenums:1
1
<ol class="linenums" style="border-width: 0px; margin: 0px; padding: 0px 0px 0px 26px;"><li value="1" class="L0" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringRef</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> cfString </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFStringCreate</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">...();</span></span></li><li class="L1" style="border-width: 0px; margin: 0px 0px 0px 20px; padding: 0px; list-style-type: decimal;"><span style="background-color: rgb(255, 255, 255);"><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">NSString</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">*</span><span class="kwd" style="border-width: 0px; margin: 0px; padding: 0px;">string</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">=</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;"> </span><span class="typ" style="border-width: 0px; margin: 0px; padding: 0px;">CFBridgingRelease</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">(</span><span class="pln" style="border-width: 0px; margin: 0px; padding: 0px;">cfString</span><span class="pun" style="border-width: 0px; margin: 0px; padding: 0px;">);</span></span></li></ol>

###总结
由上面的学习我们了解到 ARC 中类型转换的用法,那么我们实际使用中按照怎样的原则或者方法来区分使用呢,下面我总结了几点关键要素。

  • 明确被转换类型是否是 ARC 管理的对象- Core Foundation 对象类型不在 ARC 管理范畴内
  • Cocoa Framework::Foundation 对象类型(即一般使用到的Objectie-C对象类型)在 ARC 的管理范畴内
  • 如果不在 ARC 管理范畴内的对象,那么要清楚 release 的责任应该是谁
  • 各种对象的生命周期是怎样的

1. 声明 id obj 的时候,其实是缺省的申明了一个 strong 修饰的变量,所以编译器自动地加入了
retain 的处理,所以说
bridge_transfer 关键字只为我们做了 release 处理。

|