有关在 NSMutableArray 的副本上使用快速枚举删除对象的详细信息



我学到了艰难的方法,当你循环浏览NSMutableArray中的对象时,你不能从中删除对象。

循环遍历[< array_object > copy]而不是< array_object >修复它。

但是,我有一些未解决的问题,我想从Objective-C大师那里获得意见。

  1. 在第一个 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
    }
    
  2. 在第二个 for 循环中
  3. 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
    }
    
  4. 但是,当我循环遍历[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)
    }
    

复制数组会执行"浅拷贝"。它创建一个新的数组对象,然后存储指向第一个数组中的对象的指针。它不会创建新对象。

将数组视为地址簿。它列出了您朋友家的地址。如果我复制您的地址簿,那么我就有地址列表的副本。地址簿不包含房屋。

如果我从地址簿副本中删除某个条目,它不会从地址簿中删除相同的条目。它也不会摧毁任何房屋。

在循环 2 代码中,您循环遍历副本,然后告诉原始数组删除某些对象。它们将从原始数组中删除,但不从副本中删除。 (这很好,因为正如您所说,在迭代数组时改变数组会导致崩溃。

请注意,数组可以包含

指向同一对象的多个指针,就像地址可以多次包含相同的地址一样。(如果一个朋友在她结婚时改变了她的名字,你可以用他已婚的名字写下她,并在她的婚前姓氏下留下条目。两个地址都指向同一所房子。

请注意,您正在使用的 removeObject 方法会删除对象的所有条目。这就像你在说"删除我地址簿中榆树街 123 号的每个条目"。如果您只想删除重复集的一个条目,则需要改用 removeObjectAtIndex,并且需要更改代码才能使其正常工作。

  1. 复制操作复制容器,而不是其内容。您有一个新的指向相同对象的指针列表。

  2. &nextObject是变量的地址,而不是对象的地址。对象的地址是变量的值:NSLog(@"%p", nextObject);

  3. removeObject:使用 isEqual: 将其参数与集合的内容进行比较,通常不按地址进行比较,而是通过类定义的某种语义评估进行比较。

即使撇开在快速枚举循环中禁止更改的禁令,也无法从副本中删除对象,因为copy会创建不可变的副本。您需要mutableCopy才能更改新实例。

但是所有%p的印刷品都给出了相同的价值。为什么?

因为 &nextObjectnextObject 变量(代码示例中使用的循环变量(的地址;它的类型是指向指针的指针。 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

最新更新