拆解ARC下的self

最近在研究AFNetworking源码的过程中碰到了很多处地方用到了weakSelfstrongSelf。依据自己之前的理解,正常情况下使用weakSelf是为了避免发生循环引用,而使用strongSelf是为了避免方法还没有执行完成self已经被释放从而导致崩溃。不过为何在方法执行完成之前无法确保self不被释放却不是很明白,于是乎,自己花了些时间研究了一下。

self的本质###

self是类的隐藏参数,在类方法中self指向当前调用方法的类,在实例方法中指向当前调用方法的类的init方法族生成的实例。更准确来说,在类方法中self是const Class self,在实例方法中self是Person const* self(以Person类举例)。事实确实如此么?来验证一下。


#import "Person.h"

@implementation Person

- (void)eat{
}

+ (void)classEat{
}

- (void)drink:(NSString *)sth{
    [self eat];
}

@end

将Person.m用clang命令进行重写,得到的代码如下:

static void _I_Person_eat(Person * self, SEL _cmd) {
    id obj = ((Person *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Person"))}, sel_registerName("init"));
}

static void _C_Person_classEat(Class self, SEL _cmd) {
}

static void _I_Person_drink_(Person * self, SEL _cmd, NSString *sth) {
    ((void (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("eat"));
}

从重写后的代码中可以看出结论是正确的,但还是没有找到self在方法执行过程中可能被释放的原因。我又查阅了Clang的官方文档,找到了其中关于self的说明:

The self parameter variable of an Objective-C method is never actually retained by the implementation. It is undefined behavior, or at least dangerous, to cause an object to be deallocated during a message send to that object.

To make this safe, for Objective-C instance methods self is implicitly const unless the method is in the init family. Further, self is always implicitly const within a class method.

翻译过来就是在OC方法中作为参数的self不会被方法的实现持有,当给self指向的对象发送消息时确实可能会发生错误。为了确保安全,除非是在init及类init的方法中,否则在OC的实例方法和类方法中self始终是指针常量无法被retain。根据我的理解整理如下:

  1. 在ARC中,self的修饰符是__unsafe_unretained,而不是__strong。__unsafe_unretained与weak类似,均是对对象的弱引用,区别在于当__unsafe_unretained的指针指向的对象被释放后,指针仍会指向被释放对象的内存地址,变成野指针导致crash,而当__weak的指针指向的对象被释放后,指针指向的对象会被置为nil。正是由于__unsafe_unretained修饰符的作用,因此会导致在方法执行的过程若self被释放则会引起crash。

  2. OC方法不会对self自动retain(除了init方法族以外),self在方法运行过程中的生命周期需要由程序员自己手动实现来保证。通常的做法也就是在方法中添加一个局部变量strongSelf来对self指向的对象进行强引用来保证在方法执行完之前self都不会被释放。

  3. 对self采用__unsafe_unretained修饰符,主要是为了性能方面的考虑。通常调用一个方法被runtime改写成objc_msgSend()后,传入的第一个参数都是self,从上面clang重写的代码中也可以看出。若是在方法调用中对self进行retain和release,确实可以保证方法执行过程中self不会被释放,但是,会对性能产生很大影响。并且在大多数方法调用过程中,self是不会被释放的,因此,不对self进行reatain和release操作所带来的性能提升是值得的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容