您的代码 sn-p 包含一些关于 iOS/OS X 内存管理的有趣内容。
__weak NSString* str = [NSString stringWithFormat:@"abcsdf"];
str = nil;
没有ARC的代码与以下相同。
NSString* str = [[[NSString alloc] initWithFormat:@"abcsdf"] autorelease];
str = nil;
因为stringWithFormat: 类方法不以“alloc”、“new”、“copy”或“mutableCopy”开头。这是命名规则。因此 NSString 对象由 Autorelease Pool 保留。自动释放池可能在主 Runloop 中。因此 NSString 对象没有立即释放。它会导致内存增长。 @autoreleasepool 解决了。
@autoreleasepool {
__weak NSString* str = [NSString stringWithFormat:@"abcsdf"];
str = nil;
}
NSString 对象在@autoreleasepool 代码块的末尾被释放。
顺便说一句,[NSString stringWithFormat:@"abcsdf"] 可能不会每次都分配任何内存。原因是它是静态字符串。让我们使用这个类来做进一步的解释。
#import <Foundation/Foundation.h>
@interface Test : NSObject
+ (instancetype)test;
@end
@implementation Test
- (void)dealloc {
NSLog(@"Test dealloc");
}
+ (instancetype)test
{
return [[Test alloc] init];
}
@end
这是__weak的测试代码。
@autoreleasepool {
NSLog(@"BEGIN: a = [Test test]\n");
__weak Test *a = [Test test];
NSLog(@"END: a = [Test test]\n");
a = nil;
NSLog(@"DONE: a = nil\n");
}
代码的结果。
BEGIN: a = [Test test]
END: a = [Test test]
DONE: a = nil
Test dealloc
你说deallocate 'str' by making 'str' becomes nil, thus losing the owner。这是不正确的。 a 弱变量没有对象的所有权。自动释放池确实拥有对象的所有权。这就是为什么对象在@autoreleasepool 代码块的末尾被释放的原因。看看这个案例的其他测试代码。
NSLog(@"BEGIN: a = [[Test alloc] init]\n");
__weak Test *a = [[Test alloc] init];
NSLog(@"END: a = [[Test alloc] init]\n");
a = nil;
NSLog(@"DONE: a = nil\n");
您可以从代码中看到编译警告。
warning: assigning retained object to weak variable; object will be
released after assignment [-Warc-unsafe-retained-assign]
__weak Test *a = [[Test alloc] init];
^ ~~~~~~~~~~~~~~~~~~~
[[Test alloc] init] 不会将对象注册到自动释放池。好吧,不再需要@autoreleasepool。而a 是__weak 变量,所以对象不会被任何东西保留。因此结果是
BEGIN: a = [[Test alloc] init]
Test dealloc
END: a = [[Test alloc] init]
DONE: a = nil
没有所有权就没有生命。该对象在分配后立即被释放。我认为您想编写没有__weak 的代码,如下所示。
NSLog(@"BEGIN: a = [[Test alloc] init]\n");
Test *a = [[Test alloc] init];
NSLog(@"END: a = [[Test alloc] init]\n");
a = nil;
NSLog(@"DONE: a = nil\n");
结果符合预期。该对象是通过将nil 分配给强变量a 来释放的。然后没有人拥有该对象的所有权,该对象被释放了。
BEGIN: a = [[Test alloc] init]
END: a = [[Test alloc] init]
Test dealloc
DONE: a = nil