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. javasript中var、let和const区别

    let和const都是es5,es6新版本的js语言规范出来的定义,在这以前定义一个变量只能用var.let和const都是为了弥补var的一些缺陷而新设计出来的. 简单来说是: let是修复了var ...

  2. js array 数组添加与删除数据

    //新建数组 var ids =new Array(); //向数组中添加数据 ids.push(1); //删除下标为i的数组元素 ids.remove(i); //自定义删除函数: Array.p ...

  3. webpack单独打包一个less文件

    需要将btn.less文件用webpack打包后,放到项目中.在网上百度了各种,遇到了很多问题,现在我将整个步骤整理如下: 1.建一个空的文件夹,命名为init_webpack,在该文件夹下运行: 这 ...

  4. windows 2012 r2企业版没有界面

    windows 2012 R2系统进去以后只有CMD命令窗口,没有图形化界面,除了cmd其余的全部是黑的.在网上搜了很多,都是大同小异的解决方法,但根本解决不了.今天再这里分享的这个方法很简单,不用重 ...

  5. 《Inside C#》笔记(三) 数据类型

    数据类型系统是一门编程语言的核心..NET系列的语言使用统一的数据类型系统CTS(Common Type System).所有的数据类型都继承自System.Object. 一 值类型和引用类型 a) ...

  6. [20180413]热备模式相关问题2.txt

    [20180413]热备模式相关问题2.txt --//上午测试热备模式相关问题,就是如果打开热备模式,如果中间的归档丢失,oracle在alter database end   backup ;时并 ...

  7. 百度纯CSS生成菜单

    首页我们打看dreamweaver或其它编辑器,创建一个名为nav的导航菜单 <div class="nav"> <ul> <li><a ...

  8. C#检测本机是否联网

    public class Net { [DllImport("wininet")] private extern static bool InternetGetConnectedS ...

  9. python遍历本地文件系统 按文件大小排序

    在这个例子中,主要会用到python内置的和OS模块的几个函数: os.walk() : 该方法用来遍历指定的文件目录,返回一个三元tuple(dirpath, dirnames, filenames ...

  10. SQL取最大值编码(自动编码)

    SQL取最大值编码(自动编码) 用途 : 使用SQL语法做出自动编码效果,例如将单号自动+1后,产生该笔单号 Table说明 SQL语法 SELECT 'A'+REPLICATE('0',7-len( ...