在目标c中,假设我有一个存储在NSMutableArray中的对象Obj
,并且数组指向它的指针是整个程序中唯一指向Obj
的强指针。现在假设我在Obj
上调用了一个方法,并在另一个线程中运行此方法。在这种方法中,如果Obj
将自身的指针设置为等于nil
,它本质上会自行删除吗? (因为没有更强的指针了)我怀疑答案是否定的,但为什么呢?如果这确实有效,那么它是不好的编码实践(我认为它不是很好的编码,但它实际上是不好的?)
答案 0 :(得分:5)
如果您的代码设计正确,则对象极不可能导致自己的释放/释放。所以,是的,你描述的情况表明编码实践不好,实际上可能导致程序崩溃。这是一个例子:
@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];
removeSelf
中对NSLog的第二次调用将导致EXC_BAD_ACCESS,因为此时array
已被解除分配,并且无法调用方法。
这里至少有几个错误。最终导致崩溃的一个事实是,无论什么类创建和使用myWidget
对象,在它完成使用之前释放它(调用removeSelf)。没有这个错误,代码运行正常。但是,MyWidget不应该有一个实例变量,它首先会创建一个强引用,因为这会创建一个保留周期。如果有人试图在没有先调用myWidget
的情况下释放removeSelf
,则不会释放任何内容,并且您可能会发生内存泄漏。
答案 1 :(得分:0)
如果你的后向指针很弱(它应该是一个类,因为一个类永远不会尝试拥有它的所有者,你将最终得到一个保留周期)并从数组中删除强指针,该对象将被删除从堆。没有强烈的指针=从内存中移除。
您可以随时测试。
答案 2 :(得分:0)
如果你需要一个类来解决它被删除的情况,最好的做法是先保留/自动释放它然后让情况发生。在这种情况下,类不会在其方法的中间删除,而是仅在之后删除。
答案 3 :(得分:0)
我认为我们可以说可能是糟糕的编码习惯,具体取决于你的工作方式。有些方法可以安排,或者可能安全地进行。
所以我们假设我们有一个全局:
NSMutableArray *GlobalStore;
一种方法是将自己移除为最终行动:
- (void) someMethod
{
...
[GlobalStore removeObject:self];
}
由于这是最后的行动,因此self
将来不应该使用,而且一切都应该很好,可能......
其他选项包括使用0的时间延迟来安排删除 - 这意味着它将在下一次运行循环周围启动(当然,如果你有一个运行循环,那么它在一个线程中你可能没有)。这应该始终是安全的。
你也可以让一个对象保持对自身的引用,这会产生一个循环,因此会保持它的存活。当它准备好死时,如果没有其他引用并且这是最后一个动作(或者是另一个对象的预定动作),它就可以自己引用它,那么该对象就已经死了。