如何实现ARC中weak功能?
我们都知道ARC中weak与assign或者说unsafe_unretained最大的不同就是设置weak属性后,系统会在对象被释放后自动将指向对象的指针置为nil,而assign则会产生一个悬空指针,那么系统是如何实现这一机制呢?我们能否自己模拟系统对weak的实现呢?
通过查看runtime源码中objc-accessors.h和objc-weak.h部分,我们大概可以了解系统针对weak的实现方式与strong或者copy的实现方式是不同的。
对于注册为weak的对象,系统会以weak指向的对象内存地址作为key,将之放入到一个hash表之中,当此对象的引用计数为0时会调用dealloc,之后遍历hash表中此key所对应的对象,将之置为nil,关于这部分详细内容可以自行查看源代码,在此不进行扩展。我们这里重点介绍下如何自行模拟系统这一机制。
分析
首先我们回想一下weak机制的几个步骤,其中真正与assign不相同的部分在于当对象调用dealloc之后对对象指针置空操作。那么我们很容易联想到Objective-C中关联对象的使用,关联对象也是在对象调用dealloc之后被移除,这样我们是否可以通过对对象添加一个关联对象来模拟weak的实现呢?
探究
下面我们通过代码来说明下如何自行实现一个类似weak机制的对象管理机制,本文中所用到的代码存放在https://github.com/samwei12/WeakDemo :
unsafe_unretained和weak具体使用中的差异
- 首先,创建一个
ClassA类, 创建一个
ClassB类,并在里面添加一个测试方法print,用于等下向ClassB实例对象发送消息,确认对象是否仍在使用- (void)print {
NSLog(@"Object is %@", self);
}
给
ClassA添加一个ClassB对象属性,并设置为unsafe_unretained@property (nonatomic, unsafe_unretained) ClassB *objectB;
在main函数中添加如下代码:
@autoreleasepool {
ClassA *instanceA = [ClassA new];
ClassB *instanceB = [ClassB new];
instanceA.objectB = instanceB;
[instanceA.objectB print];
// release instanceB
instanceB = nil;
[instanceA.objectB print];
}
// prevent process be killed immediately
sleep(3);
return 0;
运行一下代码,不出意外的话,程序会挂掉,因为
instanceA.objectB所指向的内存已经在instanceB = nil;时候被释放掉,instanceA.objectB仅指向一个悬空指针:2016-03-09 15:25:10.427 WeakDemo[98402:1613532] Object is 0x7fa080d0f100
2016-03-09 15:25:10.432 WeakDemo[98402:1613532] Object is 0x7fa080d0f100
Process finished with exit code 139
当然,也有可能不会挂,这取决于执行
print函数时,instanceB所在的内存是否完全释放掉。如果将
ClassA中的属性改为@property (nonatomic, weak) ClassB *objectB;则不会出现crash,这就是weak的作用了,objectB对象如果被释放掉,则该指针变为nil,而向nil发送消息是不会出现问题的。
如何给unsafe_unretained添加weak功能
下面我们就使用unsafe_unretained来一步一步模拟weak修饰符:
创建一个
DeallocBlock类,代码如下:typedef void (^voidBlock)();
@interface DeallocBlock : NSObject
@property(nonatomic, copy) voidBlock block;
- (instancetype)initWithBlock:(voidBlock)block1;
@end
@implementation DeallocBlock
- (instancetype)initWithBlock:(voidBlock)block1 {
self = [super init];
if (self) {
_block = [block1 copy];
}
return self;
}
- (void)dealloc {
if (_block) {
NSLog(@"DeallocBlock dealloc!");
_block();
}
}
@end
覆盖它的
dealloc函数,这样就实现了该对象被释放时执行外部传入的block功能。添加一个
NSObject的category,如下:#import <Foundation/Foundation.h>
#import "DeallocBlock.h"
#import <objc/runtime.h>
@interface NSObject (deallocBlock)
- (void)runBlockOnDealloc:(voidBlock)block;
@end
@implementation NSObject (deallocBlock)
- (void)runBlockOnDealloc:(voidBlock)block {
if (block) {
DeallocBlock *deallocBlock = [[DeallocBlock alloc] initWithBlock:block];
objc_setAssociatedObject(self, _cmd, deallocBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
@end
这里主要实现的功能是,给所有的
NSObject对象添加一个传入block的方法,这个方法的作用就是在其中根据传入的block生成一个DeallocBlock实例,并使用关联对象将这个实例关联到自身。之后当这个对象被释放时候,会自动移除所有的关联对象,也就会触发DeallocBlock实例的dealloc方法,执行我们传入的block。接下来,我们重载
ClassA的setObjectB方法:- (void)setObjectB:(ClassB *)objectB {
_objectB = objectB;
// 仅对objectB != nil case做处理
if (_objectB) {
[_objectB runBlockOnDealloc:^{
NSLog(@"_objectB dealloc");
_objectB = nil;
}];
}
}
这段代码主要作用就是给
_objectB添加一个deallocBlock,这样,如果_objectB所指向的内存已经被释放掉,则会调用我们传递进去的block来将此悬空指针置为空再次运行程序:
2016-03-09 15:53:36.881 WeakDemo[99270:1639867] Object is 0x7fad79c0f310
2016-03-09 15:53:36.882 WeakDemo[99270:1639867] DeallocBlock dealloc!
2016-03-09 15:53:36.882 WeakDemo[99270:1639867] _objectB dealloc
Process finished with exit code 0
由此可知,在
main函数中执行instanceB = nil;之后,开始执行deallocBlock,之后由于instanceA.objectB已经为nil,print方法不执行操作。
总结
至此,我们已经实现了自己模拟系统weak机制的运行,给一个本会产生悬空指针的unsafe_unretained修饰符加上了weak的功能。大家可以自行尝试https://github.com/samwei12/WeakDemo,如果有任何问题,欢迎指正。
参考文档
- https://www.opensource.apple.com/source/objc4/
- Fun With the Objective-C Runtime: Run Code at Deallocation of Any Object
如何实现ARC中weak功能?的更多相关文章
- block使用小结、在arc中使用block、如何防止循环引用
引言 使用block已经有一段时间了,感觉自己了解的还行,但是几天前看到CocoaChina上一个关于block的小测试主题: [小测试]你真的知道blocks在Objective-C中是怎么工作的吗 ...
- iOS开发学习-类似微信聊天消息中的电话号码点击保存到通讯录中的功能
类似微信聊天消息中的电话号码点击保存到通讯录中的功能,ABAddress的实现在iOS9中是不能正常使用的,点击完成后,手机会非常的卡,iOS9之后需要使用Contact新提供的方法来实现该功能.快捷 ...
- [转]iOS ARC机制 weak strong
写在开头 虽然距离WWDC2011和iOS 5已经快一年时间,但是很多开发者并没有利用新方法来提高自己的水平,这点在ARC的使用上非常明显(特别是国内,基本很少见到同行转向ARC).我曾经询问过一些同 ...
- @autoreleasepool在MRC和ARC中的区别
对于@autoreleasepool {} (1)在ARC中会销毁所有在里面创建的对象,即使你用外面的Strong指针指向他 (2)在MRC中如果有外部的强指针指向,不会销毁对象,retainCoun ...
- ARC中KVO开发注意
1 在ARC 中 KVO开发 添加监听和去掉监听必需 一一匹配,不要有过的去掉监听否则会有可能导致对象无法释放. 例如,在一个viewcontroller中添加webview 并监听webview的c ...
- Qt调用dll中的功能函数
声明: 事先我已经自己动手写了一个简单的dll文件(myDLL.dll),C版接口的.并且用我前两篇有关DLL文章里面的方法,从dll中导出了导入库(.lib)文件,dll中有两个函数,原型如下: ...
- OpenGL中的功能与OSG对应功能 (摘)
将OpenGL中的功能与OSG对应功能进行列举: OpenGL function OpenSceneGraph implementation glClear( GLbitfield mask ) os ...
- oracle数据库不支持mysql中limit功能
oracle数据库不支持mysql中limit功能,但可以通过rownum来限制返回的结果集的行数,rownum并不是用户添加的字段,而是oracle系统自动添加的. (1)使查询结果最多返回前10行 ...
- ppt画笔标记在哪里|ppt中画笔工具功能怎么用?
一.ppt中画笔工具功能在哪里? 这个画笔工具其实就相当于我们的一个标记工具,要实现标记功能首先将需要演示的PPT按住F5进入到放映状态,然后在右击ppt上的空白处就会弹出衣蛾对话框,在对话框中选择“ ...
随机推荐
- spring 注解注入bean
通过注解方式注入bean,需要在配置类下注入bean 第一步,配置扫描文件夹 首先要在spring.xml中配置需要扫描的配置类 <context:componenet-scan base-pa ...
- python办公自动化系列之金蝶K3自动登录(二)
接上一篇博文python办公自动化系列之金蝶K3自动登录(一),我们接着聊聊利用python脚本实现金蝶K3 Wise客户端自动登录这一需求. 如上图所示,自动选择[组织机构]后,我们还需要驱动[当前 ...
- 添加了tabBar之后就不能使用wx.navigateTo跳转页面
我在app.json中添加了增加底部选项卡的代码如下: { "pages": [ "pages/index/index", "pages/lo ...
- Java中eq、ne、ge、gt、le、lt的含义
Java中eq.ne.ge.gt.le.lt 关系运算符包括EQ.NE.GE.GT.LE.LT几个,关系运算符返回的是真"True"或假"False". eq( ...
- Solution -「CF 510E」Fox And Dinner
\(\mathcal{Description}\) Link. 给定正整数集合 \(\{a_n\}\),求一种把这些数放置在任意多个圆环上的方案,使得每个环的大小大于 \(2\) 且环上相邻两 ...
- suse 12 升级 OpenSSH-7.2p2 到 OpenSSH-8.4p1
文章目录 1.查看当前当前环境信息 1.1.查看openssh当前版本 1.2.查看当前linux发行版 2.部署telnet-server 2.1.下载telnet-server 2.2.配置tel ...
- MYSQL优化的一些性能与技巧
1. 为查询缓存优化你的查询 大多数的MySQL服务器都开启了查询缓存.这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的.当有很多相同的查询被执行了多次的时候,这些查询结果会被放到一 ...
- 常用模块(Day25-Day28)
模块分为三种: 1.内置模块:python安装时自带的. 2.扩展模块:别人写的,需要安装之后可以直接使用,如django,tornado等. 3.自定义模块:自己写的模块. 序列化模块 序列指字符串 ...
- Docker 镜像 层结构理解
镜像到底是什么.镜像的层结构又是什么 通过docker history命令进行分析,镜像是一种其他镜像+文件+命令的组合. 这些镜像的加载.文件导入创建.命令是存在顺序关系的,所以也引出了层的概念. ...
- Python中类的定制
1 class Chinese: 2 eye = 'black' 3 4 def eat(self): 5 print('吃饭,选择用筷子.') 6 7 class Guangdong(Chinese ...