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深入理解的更多相关文章

  1. strong & weak 的理解

    import "ViewController.h" @interface ViewController () /*weak*/ @property (nonatomic,weak) ...

  2. [翻译]Understanding Weak References(理解弱引用)

    原文 Understanding Weak References Posted by enicholas on May 4, 2006 at 5:06 PM PDT 译文 我面试的这几个人怎么这么渣啊 ...

  3. iOS深入学习之Weak关键字介绍

    iOS深入学习之Weak关键字介绍 前言 从大二的开始接触OC就用到了weak属性修饰词,但是当时只是知道如何去用这个关键字:防止循环引用.根本没有深入地去了解它. 在刚来北京的时候面试过程中也常常考 ...

  4. IOS开发基础知识--碎片48

    1:Assertion failure in dequeueReusableCellWithIdentifier:forIndexPath:  static NSString *CellIdentif ...

  5. [UWP] 对应用进行A/B测试

    [对A/B测试的看法] 开发者在Dev Center中设置几种应用变体,这几种变体有几个变量的值不一样,比如有变体A和变体B(当然还可以加上变体C,Dev Center最多支持5个变体),A和B的不同 ...

  6. C --> OC with RunTime

    前言 本来打算写一篇关于runtime的学习总结,无奈长篇大论不是我的风格,就像写申论一样痛苦,加之网上关于tuntime的文章多如牛毛,应该也够童子们学习的了,今天就随便聊聊我的理解吧. runti ...

  7. 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 ...

  8. 更新mac系统和更新到Xcode7.3版本出现的: cannot create __weak reference in file using manual reference counting

    之前的编程没有遇到过,应该是苹果官方那边又做了新规吧. 不过不要紧,只要根据这个就能解决报错问题.  Set Build Settings -> Apple LLVM 7.1 - Languag ...

  9. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

随机推荐

  1. Apollo源码阅读笔记(一)

    Apollo源码阅读笔记(一) 先来一张官方客户端设计图,方便我们了解客户端的整体思路. 我们在使用Apollo的时候,需要标记@EnableApolloConfig来告诉程序开启apollo配置,所 ...

  2. JAVA的高并发基础认知 一

    一.多线程的基本知识 1.1进程与线程的介绍 程序运行时在内存中分配自己独立的运行空间,就是进程 线程:它是位于进程中,负责当前进程中的某个具备独立运行资格的空间. 进程是负责整个程序的运行,而线程是 ...

  3. Graphviz的安装 - windows环境下

    1. 官网下载 http://www.graphviz.org/ 往下拉,选择这一个 点进去,选择msi文件下载 下载完成之后,直接双击运行即可 安装完成之后要配置环境变量 2. 配置环境变量 将gr ...

  4. C++解析 xml,用到pugixml库

    参考网站: https://www.cnblogs.com/haomiao/p/5041065.html https://blog.csdn.net/iot_change/article/detail ...

  5. Ubuntu中针对问题 E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)的解决方案

    一.问题描述: 在ubuntu中有时因为错误的操作,而导致在执行 sudo apt-get install xxxx出现如下错误: E: Could not get lock /var/lib/dpk ...

  6. Web.config配置customErrors mode为Off后依然不显示具体错误的可能原因。

    有时候我们的网站程序在本地运行没有问题,但在上传到远程服务器后则报错.这就需要我们了解具体错误,但IIS默认只显示统一的运行时错误,想要知道具体错误就需要配置Web.config中customErro ...

  7. 2018最新大厂Android面试真题

    前言 又到了金三银四的面试季,自己也不得不参与到这场战役中来,其实是从去年底就开始看,android的好机会确实不太多,但也还好,3年+的android开发经历还是有一些面试机会的,不过确实不像几年前 ...

  8. ipa的plist文件查看

    1.ipa包解压缩:右键.ipa包,使用[归档实用工具/unarchiver]打开 2.进入解压缩后的payload目录,右键ipa包-显示包内容 3.找到info.plist文件,直接拖拽出来 4. ...

  9. centos7安装rabbitmq 总结

    centos7下安装rabbitmq 折腾了三天最后做了以下总结 先查看一电脑名  :示例 #hostname name 查看一下hosts配置文件:如果如下结果,就要修改下 #cat /etc/ho ...

  10. GPU与CPU的区别

    作者:虫子君 链接:https://www.zhihu.com/question/19903344/answer/96081382 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...