问题
for (int i = 0; i< [optionDataArr count]; i++) {
NSString *sName = [[optionDataArr objectAtIndex:i] objectForKey:kOptionName];
NSString *sPrice = [[optionDataArr objectAtIndex:i] objectForKey:kOptionExtraPrice];
if (sName.length == 0 && sPrice.length == 0) {
[optionDataArr removeObjectAtIndex:i];
}
}
Suppose optionDataArr
contains a dictionary having no values and when above code executes i receive:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
回答1:
You can remove items when using a plain old for loop, you cannot when using fast enumeration.
Your code is buggy, though. When you delete the nth element, the next element will be (n+2)th. You need to manually decrement the index by one to account for the shifted elements.
Also keep in mind, that in this case you really need to do "real time" bounds checking of the array length in the loop, and not just use a temporary variable holding the length (or you need to decrement that one as well).
回答2:
Below this line:
[optionDataArr removeObjectAtIndex:i];
add this line:
i--;
So, the code would be:
if (sName.length == 0 && sPrice.length == 0) {
[optionDataArr removeObjectAtIndex:i];
i--;
}
Reason: When you remove an item from an array while you are iterating on it, the indexes get changed. So, that's why you would need to manually decrement index.
回答3:
Eiko answer is correct, but i wanted to show an other version using fast enumeration. You cannot remove items using fast enumeration, so you have do store the indexes and then remove the corresponding items later :
NSMutableIndexSet * indexesToRemove = [NSMutableIndexSet indexSet];
[optionDataArr enumerateObjectsUsingBlock:^(NSDictionary *dico, NSUInteger idx, BOOL *stop) {
if ([dico count] == 0)
[indexesToRemove addIndex:idx];
}];
[optionDataArr removeObjectsAtIndexes:indexesToRemove];
EDIT :
As Martin R sugested, you can also use indexesOfObjectsPassingTest
method :
NSIndexSet * indexesToRemove = [optionDataArr indexesOfObjectsPassingTest:^BOOL(NSDictionary *dico, NSUInteger idx, BOOL *stop) {
return ([dico count] == 0);
}];
[optionDataArr removeObjectsAtIndexes:indexesToRemove];
回答4:
You can certainly use a standard for loop for this, provided you make the modifications that Eiko has already mentioned.
However, the idomatic way to handle this in Objective C is to iterate over a copy of the array:
for (id obj in [optionDataArr copy]) {
// some processing code
if (condition) {
[optionDataArr removeObject:obj]
}
}
While this does require a copy of the array, unless you know for sure that you are dealing with a significant amount of data, I would start with the readable version and optimise to the plain for loop when and if necessary.
来源:https://stackoverflow.com/questions/25238436/is-it-possible-to-delete-dictionary-from-mutablearray-while-iterating