局部变量objective-c中的内存管理
在一次采访中,我被要求实现NSArray的exchangeObjectAtIndex:withObjectAtIndex:method。 我编写了以下代码:局部变量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
- (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术语),因此它们永远不会被删除。但现实生活会咬你。(我曾经遇到过同样的基本问题,只是在一些异步代码中遇到过,这是一个很难解决的问题。)