Objective-C weak深入理解
1、weak是弱引用,所引用的对象计数不会加1。
2、weak变量在其引用的对象被销毁之后,会被置为nil。
3、weak通常用于block, delegate, NSTimer,以解决循环引用带来的内存泄漏问题。
NSObject *obj = [[NSObject alloc] init]; // obj是被引用对象的指针
id __weak obj1 = obj; // obj1是weak变量,也是被引用对象的指针
weak的底层实现,简化的源码及解析如下:
id objc_storeWeak(id *location, id newObj) // objc_storeWeak(&obj1, obj)
{
id oldObj;
SideTable *oldTable;
SideTable *newTable; oldObj = *location; // weak变量,也是被引用对象的指针
// 根据被引用对象的指针的哈希值得到对应的SideTable
oldTable = SideTable::tableForPointer(oldObj);
newTable = SideTable::tableForPointer(newObj); if (oldObj) {
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); // 删掉旧引用,因为location要指向newObj,其实应该先判断oldObj != newObj的
}
if (newObj) {
newObj = weak_register_no_lock(&newTable->weak_table, newObj,location); // 添加新引用
}
*location = newObj; return newObj;
}
void weak_unregister_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id)
{
objc_object *referent = (objc_object *)referent_id;
objc_object **referrer = (objc_object **)referrer_id; weak_entry_t *entry;
if ((entry = weak_entry_for_referent(weak_table, referent))) {
remove_referrer(entry, referrer); // 删掉旧的weak变量的指针
bool empty = true;
for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
if (entry->inline_referrers[i]) {
empty = false;
break;
}
}
if (empty) {
weak_entry_remove(weak_table, entry); // 如果旧的被引用对象的指针对应的weak变量的指针数组空了,则删掉这个被引用对象的指针
}
}
}
id weak_register_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id)
{
// 被引用对象的指针
objc_object *referent = (objc_object *)referent_id;
// weak变量的指针
objc_object **referrer = (objc_object **)referrer_id; weak_entry_t *entry;
if ((entry = weak_entry_for_referent(weak_table, referent))) {
append_referrer(entry, referrer); // 有就往指针数组加一个
} else {
weak_entry_t new_entry;
new_entry.referent = referent;
new_entry.inline_referrers[0] = referrer;
for (size_t i = 1; i < WEAK_INLINE_COUNT; i++) {
new_entry.inline_referrers[i] = nil;
}
weak_grow_maybe(weak_table);
weak_entry_insert(weak_table, &new_entry); // 没有就创建一个指针数组,然后加一个
} return referent_id;
}
class SideTable {
private:
static uint8_t table_buf[SIDE_TABLE_STRIPE * SIDE_TABLE_SIZE]; // 所有SideTable对象共用,数组元素是SideTable *。看成全局数组,而不属于某个SideTable对象,更好理解。
public:
weak_table_t weak_table; // SideTable对象和weak表一一对应
static SideTable *tableForPointer(const void *p)
{
uintptr_t a = (uintptr_t)p;
int index = ((a >> 4) ^ (a >> 9)) & (SIDE_TABLE_STRIPE - 1);
return (SideTable *)&table_buf[index * SIDE_TABLE_SIZE];
}
};
// weak表
struct weak_table_t {
weak_entry_t *weak_entries;
};
// weak表项
struct weak_entry_t {
DisguisedPtr<objc_object> referent; // 被引用对象的指针
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT]; // weak变量的指针数组
};
来个直观的整体结构图如下:

参考链接:
https://opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mm.auto.html
https://opensource.apple.com/source/objc4/objc4-646/runtime/objc-weak.h
Objective-C weak深入理解的更多相关文章
- strong & weak 的理解
import "ViewController.h" @interface ViewController () /*weak*/ @property (nonatomic,weak) ...
- [翻译]Understanding Weak References(理解弱引用)
原文 Understanding Weak References Posted by enicholas on May 4, 2006 at 5:06 PM PDT 译文 我面试的这几个人怎么这么渣啊 ...
- iOS深入学习之Weak关键字介绍
iOS深入学习之Weak关键字介绍 前言 从大二的开始接触OC就用到了weak属性修饰词,但是当时只是知道如何去用这个关键字:防止循环引用.根本没有深入地去了解它. 在刚来北京的时候面试过程中也常常考 ...
- IOS开发基础知识--碎片48
1:Assertion failure in dequeueReusableCellWithIdentifier:forIndexPath: static NSString *CellIdentif ...
- [UWP] 对应用进行A/B测试
[对A/B测试的看法] 开发者在Dev Center中设置几种应用变体,这几种变体有几个变量的值不一样,比如有变体A和变体B(当然还可以加上变体C,Dev Center最多支持5个变体),A和B的不同 ...
- C --> OC with RunTime
前言 本来打算写一篇关于runtime的学习总结,无奈长篇大论不是我的风格,就像写申论一样痛苦,加之网上关于tuntime的文章多如牛毛,应该也够童子们学习的了,今天就随便聊聊我的理解吧. runti ...
- Xcode 7.3 cannot create __weak reference in file using manual reference counting
原帖地址 http://stackoverflow.com/questions/36147625/xcode-7-3-cannot-create-weak-reference-in-file-us ...
- 更新mac系统和更新到Xcode7.3版本出现的: cannot create __weak reference in file using manual reference counting
之前的编程没有遇到过,应该是苹果官方那边又做了新规吧. 不过不要紧,只要根据这个就能解决报错问题. Set Build Settings -> Apple LLVM 7.1 - Languag ...
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
随机推荐
- 【常用配置】Spring框架web.xml通用配置
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java. ...
- Easyui-textbox得到焦点方法
得到焦点是我们在编写前台时经常使用到的,为了提高用户的体验度,话不多说直接上代码. jsp页面: <div class="box_xian"> <span cla ...
- Linux常用基本命令:三剑客命令之-awk模式用法(2)
1,正则模式,在/etc/passwd中 过滤出使用/bin/bash的用户 ghostwu@dev:~/linux/awk$ awk -v FS=":" 'BEGIN{print ...
- inheritCombination.js
// 组合继承 // 其基本思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承 function Person(name){ this.name = name; th ...
- Python基础二字符串和变量
了解一下Python中的字符串和变量,和Java,c还是有点区别的,别的不多说,上今天学习的代码 Python中没有自增自减这一项,在转义字符那一块,\n,\r\n都是表示回车,但是对于不同的操作系统 ...
- Java执行sh等
1.通过java代码,调用bat.shell等脚本或者命令 1)使用Runtime的exec()方法,会返回一个用于管理操作系统进程的Process对象 Process process =null; ...
- 运行gulp项目报错:AssertionError: Task function must be specified。
一.问题描述: gulp项目在本地windows 10机器上跑没有任何问题,但是放在centos 7虚拟机上跑报错:AssertionError: Task function must be spec ...
- 《AngularJS入门与进阶》图书简介
一.图书封面 二.图书CIP信息 图书在版编目(CIP)数据 AngularJS入门与进阶 / 江荣波著. – 北京 : 清华大学出版社, 2017 ISBN 978-7-302-46074-9 Ⅰ. ...
- 利用Spring的AbstractRoutingDataSource解决多数据源的问题
多数据源问题很常见,例如读写分离数据库配置. 原来的项目出现了新需求,局方要求新增某服务器用以提供某代码,涉及到多数据源的问题. 解决方法如下: 1.首先配置多个datasource <bean ...
- python第三十六天-----类中的特殊成员方法
__doc__ 查看尖的描述信息 __module__表示当前操作的对象所在的模块 __class__表示当前操作的对象所属的类 __init__构造方法 通过类创建对象自动执行 __del__析构方 ...