在目标 c 中,假设我有一个对象Obj
存储在 NSMutableArray 中,并且指向它的数组指针是Obj
整个程序中唯一的强指针。现在假设我调用一个方法Obj
并在另一个线程中运行这个方法。在这种方法中,如果Obj
将自身的指针设置为等于,nil
它会本质上删除自己吗?(因为不会再有强指针了)我怀疑答案是否定的,但为什么呢?如果这确实有效,是不是不好的编码习惯(我认为它不是好的编码,但它实际上是坏的吗?)
4 回答
如果您的代码设计得当,一个对象极不可能导致其自己的释放/释放。所以是的,你描述的情况表明编码习惯不好,实际上可能导致程序崩溃。这是一个例子:
@interface Widget : NSObject
@property (retain) NSMutableArray *array;
@end
@implementation Widget
@synthesize array;
- (id)init
{
self = [super init];
if(self) {
array = [[NSMutableArray alloc] init];
[array addObject:self];
}
return self;
}
- (void)dealloc
{
NSLog(@"Deallocating!");
[array release];
[super dealloc];
}
- (void)removeSelf
{
NSLog(@"%d", [array count]);
[array removeObject:self];
NSLog(@"%d", [array count]);
}
@end
然后这段代码在另一个类中:
Widget *myWidget = [[Widget alloc] init];
[myWidget release]; // WHOOPS!
[myWidget removeSelf];
第二次调用 NSLog inremoveSelf
将导致 EXC_BAD_ACCESS,因为此时array
已被释放并且无法调用方法。
这里至少有几个错误。最终导致崩溃的一个事实是,创建和使用myWidget
对象的任何类在使用它完成之前释放它(调用 removeSelf)。如果没有这个错误,代码将运行良好。但是,MyWidget 不应该有一个实例变量首先创建对自身的强引用,因为这会创建一个保留循环。myWidget
如果有人在没有先调用的情况下尝试释放removeSelf
,则不会释放任何内容,并且您可能会发生内存泄漏。
如果你的后向指针很弱(应该是因为一个类永远不应该尝试拥有它的所有者,你最终会得到一个保留循环)并且你从数组中删除了强指针,那么对象将从堆中删除. 没有强指针 = 从内存中删除。
您可以随时对此进行测试。
如果你需要一个类来解决它被删除的情况,最好的做法是首先保留/自动释放它,然后让这种情况发生。在这种情况下,类不会在其方法的中间被删除,而只会在之后被删除。
我认为我们可以说这可能是不好的编码习惯,这取决于你是如何做到的。您可以通过多种方式安全地或可能安全地进行操作。
所以让我们假设我们有一个全局:
NSMutableArray *GlobalStore;
一种方法是删除自己作为您的最终行动:
- (void) someMethod
{
...
[GlobalStore removeObject:self];
}
由于这是最后的行动,因此应该没有未来的用途,self
并且一切都应该很好,可能......
其他选项包括以 0 的时间延迟安排删除 - 这意味着它将在下一次运行循环周围触发(当然,只有当你有一个运行循环时才有效,而在线程中你可能没有)。这应该始终是安全的。
您还可以让一个对象保留对自身的引用,这会产生一个循环,从而使其保持活动状态。当它准备好死时,它可以取消自己的引用,如果没有其他引用并且这是一个最终操作(或另一个对象的计划操作),那么该对象就死了。