我正在使用类似于以下代码的基于块的枚举:
[[[rows objectForKey:self.company.coaTypeCode] objectForKey:statementType]
enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id coaItem, NSUInteger idx, BOOL *stop) {
// block code here
}]
我想在枚举过程中删除一些对象,具体取决于它们的对象值。
我怎么能这样做?我知道在枚举期间操纵可变数组或字典(NSMutableArray或NSMutableDictionary)通常是不可能的。
实现这一目标的最佳方式是什么?
谢谢!
答案 0 :(得分:39)
由于在枚举期间无法从数组或字典中删除对象,因此您必须累积要删除的项目,然后在枚举后将其全部删除。
如果您正在处理数组,则可以累积索引。:
NSMutableIndexSet *indexesToDelete = [NSMutableIndexSet indexSet];
NSUInteger currentIndex = 0;
for (id obj in yourArray) {
//do stuff with obj
if (shouldBeDeleted(obj)) {
[indexesToDelete addIndex:currentIndex];
}
currentIndex++;
}
[yourArray removeObjectsAtIndexes:indexesToDelete];
由于NSDictionary中键的顺序未定义,因此对于NSMutableDictionary,您将不得不累积键:
NSMutableArray *keysToDelete = [NSMutableArray array];
for (id obj in [yourDictionary keyEnumerator]) {
//do stuff with obj
if (shouldBeDeleted(obj)) {
[keysToDelete addObject:obj];
}
}
[yourDictionary removeObjectsForKeys:keysToDelete];
如果您使用块进行枚举,那就是同样的事情。在声明块的同一范围内声明枚举器,它将被保留并正常工作。
同样值得一看3年前的这个问题:Best way to remove from NSMutableArray while iterating?。
答案 1 :(得分:8)
无论是在枚举期间构建索引集,还是在枚举期间修改数组本身,都必须放弃NSEnumerationConcurrent
,因为大多数Cocoa对象无法从多个线程同时安全地修改。
无论如何,最简单(但可能不是最有效)的方法是枚举容器的副本。
对于数组,您可以反向枚举副本 。我假设在枚举每个项目时,您可以决定删除该项目,但不能删除之前枚举或尚未枚举的其他项目。
NSMutableArray *array = [[rows objectForKey:self.company.coaTypeCode] objectForKey:statementType];
[[array copy] enumerateObjectsWithOptions: NSEnumerationReverse
usingBlock:^(id coaItem, NSUInteger idx, BOOL *stop) {
if ([self objectIsTooUglyToExist:coaItem])
[array removeObjectAtIndex:idx];
}]
您必须反向枚举数组,以避免更改数组中尚未枚举的部分。
对于字典,您只需枚举没有特殊选项的副本:
NSMutableDictionary *dictionary = someDictionary;
[[dictionary copy] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([self object:obj isTooUglyToExistAtKey:key])
[dictionary removeObjectForKey:key];
}];
答案 2 :(得分:1)
使用数组的另一个选项是使用传统的for
循环,数组的count
作为限制。然后需要认识到一个元素是从索引的位置<=
中移除(在这种情况下索引应该递减)还是>
而不是索引(在这种情况下索引保持不变)除了for
语句的增量之外。
对于字典,您可以先使用allKeys
创建一个数组,然后遍历该数组。在这种情况下,不需要摆弄索引值。