为什么这些 ARC 对象的行为不一致?
Why do these ARC objects behave inconsistently?
这是一个使用 ARC 的 OS X 的 Objective-C 程序 - 您可以使用 cc -fobjc-arc -o objc_arc_test objc_arc_test.m
或其他东西构建它。它创建了两对两个对象,一个使用 alloc/init ,另一个使用工厂函数(在 ARC 之前的代码中你会使用 autorelease
的那种东西),都在任何自动释放池之外,打印初始化和解除分配消息。
#import <Foundation/NSObject.h>
#include <stdio.h>
#if !__has_feature(objc_arc)
#error
#endif
@interface TestClass:NSObject {
int value;
}
-(TestClass *)initWithValue:(int)value;
-(void)dealloc;
+(TestClass *)testClassWithValue:(int)value;
@end
@implementation TestClass
-(TestClass *)initWithValue:(int)value_ {
if((self=[super init]))
self->value=value_;
printf("init: self=%p value=%d\n",self,self->value);
return self;
}
-(void)dealloc {
printf("dealloc: self=%p value=%d\n",self,self->value);
}
+(TestClass *)testClassWithValue:(int)value {
return [[TestClass alloc] initWithValue:value];
}
@end
static void f() {
TestClass *c5=[TestClass testClassWithValue:5];
TestClass *c6=[[TestClass alloc] initWithValue:6];
}
static void f2() {
TestClass *c7=[TestClass testClassWithValue:7];
TestClass *c8=[[TestClass alloc] initWithValue:8];
}
int main() {
f();
f2();
}
我希望获得 4 个对象的初始化消息和 2 个对象的 dealloc 消息,因为 ARC 将确保 alloc+init 对象被销毁,并且由于缺少自动释放池,将离开其他的一个人。
但我得到的是 4 个对象的初始化消息和 3 个对象的 dealloc 消息:
init: self=0x7fea20500690 value=5
init: self=0x7fea205006f0 value=6
dealloc: self=0x7fea205006f0 value=6
init: self=0x7fea205006f0 value=7
init: self=0x7fea20500700 value=8
dealloc: self=0x7fea20500700 value=8
dealloc: self=0x7fea205006f0 value=7
我不明白这种行为!我希望 value=5 和 value=7 对象的行为相同。
为什么要这样做?
(OS X 10.11.6; Xcode 8 - Apple LLVM version 8.0.0 (clang-800.0.38)
, Target: x86_64-apple-darwin15.6.0
, Thread model: posix
)
因为我相信 OS X 10.9,所以在顶层自动创建了一个自动释放池,即使你没有创建(这消除了历史性的 "object autoreleased without an autorelease pool, just leaking" 警告) .
也就是说,这与这种情况并不特别相关。 ARC 不承诺任何东西都会自动发布。当它可以证明您以后不会使用该对象时,可以免费使用显式发布。 ARC 只是有义务保证强引用的对象不被销毁,没有强引用的对象被销毁。 Autoreleasepool 是 ARC 可以自由决定使用或不使用的实现细节。作为一种优化,ARC 通常会在我们过去手动使用它的地方避免使用自动释放池。
还值得注意的是,dealloc
从未真正承诺过。该程序无需 运行ning 即可自由终止(这是一个巨大的优化,这就是为什么 ObjC 程序可以比 C++ 程序终止得更快的原因)。在这种情况下它碰巧,但如果你依赖 dealloc
到 运行 或不依赖 运行,你可能误用了它。
这是一个使用 ARC 的 OS X 的 Objective-C 程序 - 您可以使用 cc -fobjc-arc -o objc_arc_test objc_arc_test.m
或其他东西构建它。它创建了两对两个对象,一个使用 alloc/init ,另一个使用工厂函数(在 ARC 之前的代码中你会使用 autorelease
的那种东西),都在任何自动释放池之外,打印初始化和解除分配消息。
#import <Foundation/NSObject.h>
#include <stdio.h>
#if !__has_feature(objc_arc)
#error
#endif
@interface TestClass:NSObject {
int value;
}
-(TestClass *)initWithValue:(int)value;
-(void)dealloc;
+(TestClass *)testClassWithValue:(int)value;
@end
@implementation TestClass
-(TestClass *)initWithValue:(int)value_ {
if((self=[super init]))
self->value=value_;
printf("init: self=%p value=%d\n",self,self->value);
return self;
}
-(void)dealloc {
printf("dealloc: self=%p value=%d\n",self,self->value);
}
+(TestClass *)testClassWithValue:(int)value {
return [[TestClass alloc] initWithValue:value];
}
@end
static void f() {
TestClass *c5=[TestClass testClassWithValue:5];
TestClass *c6=[[TestClass alloc] initWithValue:6];
}
static void f2() {
TestClass *c7=[TestClass testClassWithValue:7];
TestClass *c8=[[TestClass alloc] initWithValue:8];
}
int main() {
f();
f2();
}
我希望获得 4 个对象的初始化消息和 2 个对象的 dealloc 消息,因为 ARC 将确保 alloc+init 对象被销毁,并且由于缺少自动释放池,将离开其他的一个人。
但我得到的是 4 个对象的初始化消息和 3 个对象的 dealloc 消息:
init: self=0x7fea20500690 value=5
init: self=0x7fea205006f0 value=6
dealloc: self=0x7fea205006f0 value=6
init: self=0x7fea205006f0 value=7
init: self=0x7fea20500700 value=8
dealloc: self=0x7fea20500700 value=8
dealloc: self=0x7fea205006f0 value=7
我不明白这种行为!我希望 value=5 和 value=7 对象的行为相同。
为什么要这样做?
(OS X 10.11.6; Xcode 8 - Apple LLVM version 8.0.0 (clang-800.0.38)
, Target: x86_64-apple-darwin15.6.0
, Thread model: posix
)
因为我相信 OS X 10.9,所以在顶层自动创建了一个自动释放池,即使你没有创建(这消除了历史性的 "object autoreleased without an autorelease pool, just leaking" 警告) .
也就是说,这与这种情况并不特别相关。 ARC 不承诺任何东西都会自动发布。当它可以证明您以后不会使用该对象时,可以免费使用显式发布。 ARC 只是有义务保证强引用的对象不被销毁,没有强引用的对象被销毁。 Autoreleasepool 是 ARC 可以自由决定使用或不使用的实现细节。作为一种优化,ARC 通常会在我们过去手动使用它的地方避免使用自动释放池。
还值得注意的是,dealloc
从未真正承诺过。该程序无需 运行ning 即可自由终止(这是一个巨大的优化,这就是为什么 ObjC 程序可以比 C++ 程序终止得更快的原因)。在这种情况下它碰巧,但如果你依赖 dealloc
到 运行 或不依赖 运行,你可能误用了它。