如下代码中,string 何时被释放:
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string = [[NSString alloc] initWithFormat:@"Test AutoreleasePool"];
}
有很多地方说,在 runloop 进入休眠的时候释放,通过如下实验,可得出其实是在 viewDidLoad 大括号结束后就释放了。
测试方法:创建一个 weak 类型的对象指针,指向我们创建的 string 指向的地址,因为加载 VC 是先加载 viewDidLoad 再加载 viewWillAppear:,所以我们可以在 viewWillAppear: 中查看,这个对象释放被释放。得出的结论是,在viewWillAppear: 中访问时已经是 nil 了。
另一种测试方式,就是在 runloop 进入休眠时,打印一下这个 weak 对象的内容以及地址,发现在发出即将进入休眠通知时,已经释放了。
具体代码如下:
static ViewController *object;
@interface ViewController ()
@property (nonatomic, weak)NSString *myString;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
object = self;
CFRunLoopObserverContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context);
NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop];
CFRunLoopRef cfRunLoop = [myRunLoop getCFRunLoop];
CFRunLoopAddObserver(cfRunLoop, observer, kCFRunLoopDefaultMode);
NSString *string = [[NSString alloc] initWithFormat:@"Test AutoreleasePool"];
NSLog(@"string Text: %@", string);
NSLog(@"string Text p: %p", string);
self.myString = string;
NSLog(@"testLabel Text: %@", self.myString);
NSLog(@"string Text p: %p", self.myString);
[NSMachPort port];
}
void myRunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
switch(activity)
{
case kCFRunLoopEntry:
NSLog(@"run loop entry");
break;
case kCFRunLoopBeforeTimers:
NSLog(@"run loop before timers");
break;
case kCFRunLoopBeforeSources:
NSLog(@"run loop before sources");
break;
case kCFRunLoopBeforeWaiting:
NSLog(@"run loop before waiting -----------------------");
NSLog(@"testLabel Text: %@", object.myString);
NSLog(@"string Text p: %p", object.myString);
NSLog(@"run loop before waiting -----------------------");
break;
case kCFRunLoopAfterWaiting:
NSLog(@"run loop after waiting -----------------------");
NSLog(@"testLabel Text: %@", object.myString);
NSLog(@"string Text p: %p", object.myString);
NSLog(@"run loop after waiting -----------------------");
break;
case kCFRunLoopExit:
NSLog(@"run loop exit");
break;
default:
break;
}
}
- (void)viewWillAppear:(BOOL)animated {
NSLog(@"viewWillAppear myString Text: %@", self.myString);
NSLog(@"viewWillAppear myString Text: %p", self.myString);
}
具体运行结果如下:
2018-01-30 14:10:04.221671+0800 string Text: Test AutoreleasePool
2018-01-30 14:10:04.221805+0800 string Text p: 0x608000240930
2018-01-30 14:10:04.221929+0800 testLabel Text: Test AutoreleasePool
2018-01-30 14:10:04.222028+0800 string Text p: 0x608000240930
2018-01-30 14:10:04.222179+0800 viewWillAppear myString Text: (null)
2018-01-30 14:10:04.222271+0800 viewWillAppear myString Text: 0x0
2018-01-30 14:10:04.254927+0800 run loop before timers
2018-01-30 14:10:04.255037+0800 run loop before sources
2018-01-30 14:10:04.255182+0800 run loop before timers
2018-01-30 14:10:04.255279+0800 run loop before sources
2018-01-30 14:10:04.255396+0800 run loop before timers
2018-01-30 14:10:04.255475+0800 run loop before sources
2018-01-30 14:10:04.256013+0800 run loop before timers
2018-01-30 14:10:04.256115+0800 run loop before sources
2018-01-30 14:10:04.256213+0800 run loop before timers
2018-01-30 14:10:04.256313+0800 run loop before sources
2018-01-30 14:10:04.275536+0800 run loop before timers
2018-01-30 14:10:04.275646+0800 run loop before sources
2018-01-30 14:10:04.275754+0800 run loop before timers
2018-01-30 14:10:04.275847+0800 run loop before sources
2018-01-30 14:10:04.275943+0800 run loop before waiting -----------------------
2018-01-30 14:10:04.276025+0800 testLabel Text: (null)
2018-01-30 14:10:04.276107+0800 string Text p: 0x0
2018-01-30 14:10:04.276194+0800 run loop before waiting -----------------------
2018-01-30 14:10:04.290160+0800 run loop after waiting -----------------------
2018-01-30 14:10:04.290312+0800 testLabel Text: (null)
2018-01-30 14:10:04.290407+0800 string Text p: 0x0
2018-01-30 14:10:04.290495+0800 run loop after waiting -----------------------