当你循环浏览其中的对象时,我学到了很难从NSMutableArray
删除对象。
循环使用[< array_object > copy]
代替< array_object >
修复它。
但是,我想从Objective-C专家那里得到一些未解答的问题。
在第一个for循环中,我希望每个nextObject
指向不同的内存(即我认为msgDetail
数组将有一个指针列表,每个指针都指向特定数组索引包含的NSDictionary
的地址。但是所有%p nextObject
打印都给出了相同的值。那是为什么?
for(NSDictionary *nextObject in msgDetailArray)
{
NSLog(@"Address = %p, value = %@",&nextObject,nextObject) ;
//Doing [msgDetailArray removeObject:nextObject] here based on some condition fails
}
在第二个for循环中,nextObject
NSDictionary
的地址与第一个for循环中的地址不同。
for(id nextObject in [msgDetailArray copy])
{
NSLog(@"In copy Address = %p, value = %@",&nextObject,nextObject) ;
//Doing [msgDetailArray removeObject:nextObject] here based on some condition succeeds and it also removes it from the original array even though I am looping through a copy
}
但是,当我循环浏览[msgDetailArray copy]
,然后执行removeObject:
时,会将其从原始msgDetailArray
中删除。 removeObject:
如何做到这一点?它是否实际使用字典的内容并删除与内容匹配的对象?我认为所做的只是检查是否有一个对象位于同一个内存位置并将其删除(基于2,我假设包含[msgDetailArray copy]
中字典的内存地址与中的地址不同原msgDetailArray
)。如果它实际上是在使用内容,我必须非常小心,以防有重复的条目。
for(id nextObject in msgDetailArray)
{
NSLog(@"Address = %p, value = %@",&nextObject,nextObject) ;
//test what is left in msgDetailArray. I see that doing removeObject on [msgDetailArray copy] does remove it from the original too. How is removeObject working (is it actually contents of dictionary)
}
答案 0 :(得分:2)
复制数组会产生一个&#34;浅拷贝&#34;。它创建一个新的数组对象,然后存储指向第一个数组中对象的指针。它不会创建新对象。
将数组想象为地址簿。它列出了你朋友的地址&#39;房屋。如果我复制了你的地址簿,那么我就有一份地址列表的副本。地址簿不包含房屋。
如果我从地址簿副本中删除条目,则不会从地址簿中删除相同的条目。它也不会破坏任何房屋。
在循环2代码中,循环遍历副本,然后告诉原始数组删除某些对象。它们将从原始数组中删除,但不会从副本中删除。 (这很好,因为正如你所说,在迭代它时改变一个数组会导致崩溃。)
请注意,数组可以包含多个指向同一对象的指针,就像地址可以多次包含相同的地址一样。 (如果朋友在结婚时更改了她的名字,你可以根据他的已婚姓名将她写入你的地址,并将该条目留在她的婚前姓名下。两个地址都指向同一所房子。)
请注意,您使用的removeObject
方法会删除对象的所有条目。它就像你在说&#34;擦除我的地址簿中123 Elm street&#34;的每个条目。如果您只想删除重复集的一个条目,则需要使用removeObjectAtIndex,并且需要更改代码才能使其正常工作。
答案 1 :(得分:2)
复制操作会复制容器,而不是其内容。您有一个指向同一对象的新指针列表。
&nextObject
是变量的地址,而不是对象。对象的地址是变量的值:NSLog(@"%p", nextObject);
removeObject:
使用isEqual:
将其参数与集合的内容进行比较,通常不按地址进行比较,而是通过类定义的某种语义评估进行比较。
即使不考虑禁止在快速枚举循环内部进行变更,也无法从副本中删除对象,因为copy
会生成不可变副本。您需要mutableCopy
才能更改新实例。
答案 2 :(得分:2)
但是所有
%p
的打印都给出了相同的值。那是为什么?
因为&nextObject
是nextObject
变量的地址,所以代码示例中使用了一个循环变量;它的类型是指向指针的指针。 nextObject
本身也是一个指针,所以如果你想打印对象的地址,你需要做的只是将其转换为void*
:
NSLog(@"Address = %p, value = %@", (void*)nextObject, nextObject);
在第二个for循环中,
nextObject
NSDictionaries
的地址与第一个for循环中打印的地址不同
因为它是不同变量的地址。
当我循环浏览
[msgDetailArray copy]
,然后执行removeObject
时,会将其从原始msgDetailArray
中删除。
循环的副本位于不可见的临时对象中。它是由原始数组支持的不可变副本。
调用[msgDetailArray removeObject:nextObject]
对原始数组进行操作。如果您不希望出现此效果,请将副本存储在变量中,然后从中删除项目:
NSMutableArray *mutableCopy = [msgDetailArray mutableCopy];
...
[mutableCopy removeObject:nextObject];
这不会触及原始阵列。但是,您可能无法在删除项目的同时迭代mutableCopy
。