2018年5月10日
前言
首先声明本文涉及到的内容并非本人原创,只是笔者在工作中遇到相关问题,通过查阅前人的成果,自己做的一些总结,初衷是加深印象,也方便自己以后查阅,如果能对读者有所帮助,那是鄙人的荣幸。
从NSString说起
#define Log(_var) ({ NSString *name = @#_var; NSLog(@"%@: %@ -> %p : %@", name, [_var class], _var, _var);})
__weak NSString *weak_string = nil;
- (void)viewDidLoad {
[super viewDidLoad];
// 场景:1
NSString *string1 = @"常量";
weak_string = string1;
/*
// 场景:2
NSString *string2 = [[NSString alloc] initWithFormat:@"实例方法"];
weak_string = string2;
*/
/*
// 场景:3
NSString *string3 = [NSString stringWithFormat:@"类方法"];
weak_string = string3;
*/
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"%s", __func__);
Log(weak_string);
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(@"%s", __func__);
Log(weak_string);
}
输出
-[ViewController viewWillAppear:]
weak_string: __NSCFConstantString -> 0x10cb408e0 : 常量
-[ViewController viewDidAppear:]
weak_string: __NSCFConstantString -> 0x10cb408e0 : 常量
-[ViewController viewWillAppear:]
weak_string: (null) -> 0x0 : (null)
-[ViewController viewDidAppear:]
weak_string: (null) -> 0x0 : (null)
-[ViewController viewWillAppear:]
weak_string: __NSCFString -> 0x60c00002ece0 : 类方法
-[ViewController viewDidAppear:]
weak_string: (null) -> 0x0 : (null)
场景:1
第一种情况没的说,string1的class是__NSCFConstantString,编译期创建,放在常量区,程序销毁的时候才被释放。
场景:2
第二种情况也很好理解,通过alloc在堆上分配内存的局部变量,作用域结束被自动回收,所以在viewWillAppear
和viewDidAppear
的时候string2已不复存在。
场景:3
下面着重说一下通过类方法stringWithFormat
创建的对象。
为了更直观,我们拿场景2做对比,通过设置观察点发现alloc创建的对象在viewDidLoad
作用域结束的时候就被回收了,而此时AutoreleasePool并没有被pop。
再观察一下类方法创建的对象,viewWillAppear
方法结束的时候执行了 AutoreleasePoolPage::pop(void*)
方法。
由此我们可以得出结论,通过类方法创建的对象生命周期延长了,直到自动释放池被pop的时候才被销毁。同时也再次证明sunnyxx大神的论断viewDidLoad
和viewWillAppear
是在同一个runloop调用的。
另外
无论使用alloc还是类方法创建的对象,当内容是数字、英文字母、字符等,只要字符串的长度小于等于9就会转成NSTaggedPointerString类型。长度大于9或者有中文在就会变成NSCFString类型。NSTaggedPointerString类型也不会释放,其实对于NSTaggedPointerString类型来说,它的内容就在本身的指针里,不存在释放的问题。
Autorelease原理
sunnyxx大神的《黑幕背后的Autorelease》写的很清楚了,这里不再赘述,有兴趣的可以去拜读一下,写的相当棒。
网友评论