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. 【github&&git】2、github入门到上传本地项目

    [在原文章的基础上,修改了描述的不够详细的地方,对内容进行了扩充,整合了网上的一些资料] [内容主要来自http://www.cnblogs.com/specter45/p/github.html#g ...

  2. Vim settings file on Windows

    Question: I can't believe I am typing a question for a simple thing like this but here we are. I can ...

  3. video 铺满父元素(object-fit: fill;)

    遇到这个属性,是在给video 嵌入一个div时,导致video播放器上下有灰色.在控制台查看video默认样式的时候看到了这个属性. 播放器上下的灰色,不是我们想要的样式,如果能完全覆盖就更好了. ...

  4. 《Inside C#》笔记(完) 程序集

    程序集内部包含了各种相关的模块.资源文件.配置文件等,将这些在功能上相关的文件整合到单个文件中,以便于部署和维护.使用C#编译器编译程序时,生成的便是程序集. 一.清单数据 a)如果编译的是独立应用程 ...

  5. Mac 的mysql5.7没有配置文件,如何解决only_full_group_by 问题

    数据库版本是5.7.19,在写语句的时候,只要涉及ORDER BY,就会报错, ERROR 1055 (42000): Expression #7 of SELECT list is not in G ...

  6. (网页)JS编程中,有时需要在一个方法返回两个个或两个以上的数据

    转自脚本之家: 1 使用数组的方式,如下: <html> <head> <title>JS函数返回多个值</title> </head> & ...

  7. JsonParseException:非法的unquoted字符((CTRL-CHAR,代码9)):必须被转义

     其它异常,Could not read document: Illegal unquoted character ((CTRL-CHAR, code 10)): has to be escaped  ...

  8. [20180123]测试SQLNET.EXPIRE_TIME参数.txt

    [20180123]测试SQLNET.EXPIRE_TIME参数.txt --//曾经写过一篇linux内核网络参数测试tcp_keepalive,链接http://blog.itpub.net/26 ...

  9. python第二十三天-----作业中

    #!usr/bin/env python #-*-coding:utf-8-*- # Author calmyan import os ,sys,time from core import trans ...

  10. 【PAT】B1051 复数乘法(15 分)

    要会使用math函数, 还要注意到用四舍五入的方法判断是否应该输出0.00 #include <math.h> #include<stdio.h> int main() { d ...