目录
前言
iOS 的 ARC 模式各位应该都很熟了, 虽然在这个 Swift 都已经出到 3 的年代再来提 ARC 真是有点落伍了,
不过 ARC 下和 C++ 混编时各种问题倒是很少人提到,
正好这次将 ZFFramework 迁移到 ARC, 顺便留个文记录一下
PS: 作为从 C艹 撸过来的猴子, 对 ARC 其实并没有抱多少好感, 毕竟不像 Java 的 GC 那么方便,
又会有各种语法限制, 不过这次试了下感觉 ARC 还是很好用很有意义的
基础
个人倾向于简单一句话理解为 "有指针指向, 则保持对象的 retain 状态"
教科书式的教程什么的最没劲了, 这里就简单列一些不那么容易看到的情况
非 property 指针
static MyObject *_instance = nil;
@implementation MyHolder
- (id)init
{
self = [super init];
_instance = [MyObject new];
return self;
}
- (void)cleanup
{
_instance = nil;
}
- (void)dealloc
{
_instance = nil;
}
@end
在 ARC 下, 非 property 指针可以视为和 property 的行为完全一致, new/alloc 之后直接赋值, 要销毁时设为 nil 即可
readonly property
// in *.h file
@interface MyObject : NSObject
@property (nonatomic, strong, readonly) id myValue;
@end
// in *.m file
@interface MyObject()
@property (nonatomic, strong, readwrite) id myValue;
@end
这个 ARC/MRC 下都可以用这种设计, ARC 下更是什么都不用管,
不管是 self.myValue
还是 self->_myValue
都可以直接赋值,
还是很好用的
显式 retain
偶尔一些代码逻辑还是希望能够明确的表示 "我想要 retain 这个对象",
然而 ARC 不让你干, 这时候可以用个简单粗暴的方式, 就是在对象里弄个 strong property 来存自己,
需要显式释放时置空就好
performSelector
这个问题应该也容易碰到, 到处搜索一下也有各种解决方案, 因为比较重要这边也列一下
原因: 非显示声明的 selector, ARC 无法判断返回值是否需要自动 release
问题例子:
- (id)func1
{
return [MyObject new];
}
- (id)func2
{
return [MyObject sharedInstance];
}
// 此处 ARC 无法知道返回值是否需要释放, 因此会报警告
SEL action = (someCond ? @selector(func1) : @selector(func2));
[target performSelector:action];
// 此处编译器可以自行推导出来, 因此没有问题
[target performSelector:@selector(func1)];
[target performSelector:@selector(func2)];
网上各种解决方案大多是让你们用各种路子绕过编译器警告, 实际上是不靠谱的方案,
因为相当于让 ARC 不要处理返回值, 因此上述例子的 func1 就会造成内存泄露了
个人建议的方法是, 非必须情况下就不要用 selector 返回值了, 确实要返回, 可以用参数来输出, 比如
@interface Holder : NSObject
@property (nonatomic, strong) MyObject *result;
@end
- (void)func:(Holder *)result
{
result.result = xxx;
}
与 C++ 混编
基本上就是以下三个关键词转来转去:
__bridge
: 简单的指针转换, 不涉及引用计数变化__bridge_retained
: OC对象指针转 C指针, 所有权交给 C指针__bridge_transfer
: C指针转 OC对象指针, 所有权交给 OC对象指针
(大多数文章也就讲到此了, 给的例子也是让人摸不着头脑, 所以这里我尽量用简单并容易理解的例子再列一遍)
典型流程
-
OC对象放到 C代码中保存
// wrapper static void *cFunc(void) { MyObject *ocObj = [MyObject new]; return (__bridge_retained void *)ocObj; } // 保存 void *cPointer = cFunc();
-
通过 C指针访问 OC对象
MyObject *ocObj = (__bridge MyObject *)cPointer; [ocObj xxx]; // 作为参数时也要这么搞 [other func:(__bridge MyObject *)cPointer];
-
手动释放
MyObject *ocObj = (__bridge_transfer MyObject *)cPointer; ocObj = nil;
其实讲太多反而晕, 最简洁的理解为
__bridge_retained
相当于 MRC 的retain
__bridge_transfer
相当于 MRC 的release
__bridge
相当于static_cast
- 总的来说, 与 C 交互时, 相当于回到了 MRC (而且是没有 autorelease 的 MRC)
-
对比一下你会发现, 这个和 JNI 挺像的
- JNI 里面的 global ref 对应 ARC 的
__bridge_xxx
- JNI 里面的 local ref 对应 ARC 帮你自动插入的
retain
/release
, 或者更像是autorelease
- JNI 里面的 global ref 对应 ARC 的
转载请注明来自: http://zsaber.com/blog/p/147
既然都来了, 有啥想法顺便留个言呗? (无奈小广告太多, 需审核, 见谅)