我偶然发现一个有趣的情况,当物体可以自我释放,并且想知道在这种情况下什么是安全的。
想象一下,我们有一个Foo类:
@implementation Foo
+ (Foo *) foo {
return [[[Foo alloc] init] autorelease];
}
- (void)resign {
[FooHolder holder].foo = nil;
// here's where the things happen
}
@end
另一个类是FooHolder(具有一个属性的单例):
@interface FooHolder : NSObject {
Foo *foo;
}
@property (retain) Foo *foo;
+ (FooHolder *)holder;
@end
在代码的某处我们执行此操作(先调用stepOne
然后调用stepTwo
;在stepOne
完成后自动释放池耗尽:
- (void)stepOne {
Foo *foo = [Foo foo];
[FooHolder holder].foo = foo;
}
- (void)stepTwo {
[[FooHolder holder].foo resign]
}
如果我尝试在self
方法中访问resign
,在分配后,使用NSZombieEnabled,我收到一条警告,self
已被解除分配。这给了我短暂的WTF时刻,但好吧,我可以在这部分没有访问self
的情况下生活。令我困扰的是,如果对象已经被释放,谁可以保证堆栈没有被损坏,我们正在使用我们的本地和实例变量正常进行?一般来说,在方法中允许self
被释放是不好的做法吗?
答案 0 :(得分:5)
一般来说,在方法中允许自我释放是不好的做法吗?
是的,因为从自我解除分配的角度来看,你的所有伊娃都可以被解除分配。
我不会假装了解您的设计或理由,但为什么不重新安排辞职方法:
- (void)resign {
// here's where the things should happen
[FooHolder holder].foo = nil;
}
您应该在有可能使用它们之后释放所拥有的对象,就像您在[super dealloc];
的 end 调用-(void)dealloc
一样
答案 1 :(得分:3)
我认为你的设计有缺陷。在实例方法-resign
中,您实际上释放了由单例持有的foo的特定实例。为什么foo的任意实例会这样做?在实例方法中引用有效的全局变量会使耦合过于紧张。
无论调用-resign
是什么,都应告诉[FooHolder holder]
它已经辞职foo
或将辞职foo。或者,对FooHolder
中的foo
进行弱引用,并让foo
向其发送-willResign:(Foo*)
之类的消息。这有效地使其成为foo
的代表}。在-willResign:
中,FooHolder
可以检查它是否是正确的foo
,然后在将其设置为nil之前保留并自动释放它。