局部变量objective-c中的内存管理

局部变量objective-c中的内存管理,objective-c,memory,memory-management,Objective C,Memory,Memory Management,在一次采访中,我被要求实现NSArray的exchangeObjectAtIndex:withObjectAtIndex:method。 我编写了以下代码: - (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 { id tmp = [self objectAtIndex:index1]; [self replaceObjectAtIndex:index1 withObj

在一次采访中,我被要求实现NSArray的exchangeObjectAtIndex:withObjectAtIndex:method。 我编写了以下代码:

- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 {
  id tmp = [self objectAtIndex:index1];
  [self replaceObjectAtIndex:index1 withObject:[self objectAtIndex:index2]];
  [self replaceObjectAtIndex:index2 withObject:tmp];
}
采访者说,在第一行有一个内存管理问题,我要抓住坏访问exc。 他建议这样写:

- (void)exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 {
    id tmp = [[[self objectAtIndex:index1] retain] autorelease];
    [self replaceObjectAtIndex:index1  withObject:[self objectAtIndex:index2]];
    [self replaceObjectAtIndex:index2 withObject:tmp];
}

我知道他的代码是对的,但因为tmp是局部变量,它将被赋值,所以没有释放,一切都会好起来。有错误吗?

请记住,
idtmp
不过是指向数组中对象的指针。它没有说明它所指向的对象的内存管理

…它将被分配,所以没有发布


这是症结所在。当您将
index1
处的对象替换为
index2
处的对象时,无法保证不会解除分配
index1
处的对象。实际上,此时数组将调用对象上的
release
,以平衡最初添加到数组中时对对象调用的
retain
。因此,当
index1
处的对象被替换时,
index2
处的对象将被替换,
index1
处对象的引用计数将变为零,对象将被解除分配,并且
tmp
变量将变为悬空指针。
。。。retain]autorelease]
dance将对象保留足够长的时间以进行交换,而不必担心在方法结束之前将其释放(可能会一直保留到下一次运行循环的顶部)。

如果使用手动内存管理,则会出现错误。苹果公司已将该问题记录在案

具体来说,
objectAtIndex:
不会保留它返回给您的对象。因此,
NSArray
可能是对对象的唯一“拥有”引用。在手动保留计数(MRC)下分配给
tmp
不会保留对象,因此
tmp
不拥有对象,自动释放池也不拥有对象

这意味着,当方法的第2行发送
[self-ReplaceObjectIndex:index1 withObject:[self-ObjectIndex:index2]]
时,数组可能会释放对该对象的最后一个引用,即取消分配它。此时,
tmp
指的是解除分配的对象;这被称为“悬挂参考”

然后在第3行中,尝试将悬挂引用放入数组中。数组将向引用发送
retain
,该引用无效,您将崩溃或遇到堆损坏


在ARC下,分配给
tmp
不会保留对象,因此在这种情况下没有错误。

谢谢,这是非常清楚的解释。但现在我有另一个误解:我创建了一个空项目并编写了代码,它应该会失败,但它工作得很好。为什么?我有一个ARC禁用,似乎没有任何其他链接到该数组。核心基础框架缓存<代码> NStuts实例,用于从<代码> -1 < /代码>到<代码> 12 > /代码>包含的整数。一旦分配,这些实例就永远不会被释放。在中搜索
MinCachedInt
以了解详细信息。静态分析器或僵尸可能会检测到您的错误。我还没试过。@RustamGaneyev-不一定会失败。这取决于释放的存储是否被重用,以及相关对象是否保留在其他地方。例如,如果您制作了一个用文本字符串或文本NSNumbers填充数组的测试用例,那么它们很有可能被“扣押”(使用Java术语),因此它们永远不会被删除。但现实生活会咬你。(我曾经遇到过同样的基本问题,只是在一些异步代码中遇到过,这是一个很难解决的问题。)