Objective-C 2.0 and Fast Enumeration throwing exceptions - objective-c

I have a block of code which is similar to the following:
for (NSDictionary *tmp in aCollection) {
if ([[bar valueForKey:#"id"] isEqualToString:[tmp valueForKey:#"id"]])
{
break;
}
else
{
[aCollection addObject:bar];
}
}
Is this technically an exception in Objective-C 2.0? It appears you cannot mutate a collection with fast enumeration. This is the result of an error:
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <NSCFArray: 0x396000> was mutated while being enumerated.'
What's the best way to solve this?

Well the way to solve it is not to mutate the array (e.g. add an object) while enumerating it :)
The problem here is that modifying the array by adding/removing elements could cause the enumeration values to become invalid, hence why it's a problem.
In your case The easiest way to solve this is fixing the bug in your code. Your code is doing the "else add" clause for every item in the array and I'm quite sure that's not what you want.
Try this;
bool found = false;
for (NSDictionary *tmp in aCollection)
{
if ([[bar valueForKey:#"id"] isEqualToString:[tmp valueForKey:#"id"]])
{
found = true;
break;
}
}
if (!found)
{
[aCollection addObject:bar];
}

Make a copy of the collection and iterate through that. Then you can swap out or add to your original collection without issues.

The line
[aCollection addObject:bar]
is your problem. You cannot modify aCollection while enumerating it. The better approach would be to create a temporary NSMutableArray, add bar to that, then call [aCollection addObjectsFromArray:] with your temporary array.
For example:
NSMutableArray *foundObjects = [NSMutableArray array];
for (NSDictionary *aDictionary in aCollection) {
if ([[bar objectForKey:#"id"] isEqual:[aDictionary objectForKey:#"id"]])
break;
[foundObjects addObject:bar];
}
[aCollection addObjectsFromArray:foundObjects];

From The Objective-C 2.0 Programming Language, you cannot modify the collection being enumerated:
Enumeration is “safe”—the enumerator has a mutation guard so that if you attempt to modify the collection during enumeration, an exception is raised.

Just copy the array. Otherwise you're messing with the collection that you're iterating:
for (NSDictionary *tmp in aCollection.copy) {
if ([[bar valueForKey:#"id"] isEqualToString:[tmp valueForKey:#"id"]])
break;
[aCollection addObject:bar];
}

Everyone else has offered useful answers, all of which seem correct.
Your code, however, does not do what they think it does. It probably doesn't do what you think it does either.
You try to add 'bar' to the collection if the first object returned by the enumerator does not match bar.
Everyone thinks that you are trying to add bar if it doesn't exist in the collection at all.
I suspect you taken a Python construct and ported it incorrectly.

solved
i has same problem in coredata objects enumeration .
do not change sub object which relies in ARRAY on which Loop is Running
Like, if i changed/Modify object while On loop .. it will give this error
for (LoadList *objLL in ArrLoadList) { // here Enumaration is Going on
// here i has removed objects in ArrLoadList and reassign the ArrLoadList ..
// it will gives me this error
// So Don't change the Main Array object
}

Related

EXC_BAD_ACCESS while doing NSDictionary objectForKey - but the object is there

Im getting a rather baffling error when trying to get an object from an NSDictionary. I get an EXC_BAD_ACCESS when calling objectForKey. When I look at the given objects, everything is fine. The dictionary exists. It contains the key I am looking for. The key is also there. Everything is totally fine. So why does objectForKey crash on this occasion? Ive taken a screenshot of both the code and of the console - you can see the properties in question in the print out. The key is there, and the dictionary contains that key. But its as though the dictionary doesnt exist or something? Baffled. By the way I 'copy'd the dictionary in an attempt to fix the crash, I wouldnt normally do that.
The problem here was todo with threading. As I was correctly reminded in comments, NSMutableDictionary is not thread safe. It was being updated on a background thread, and the code above was being called on the main thread. The simplest solution was to wrap these calls in #synchronised. Thanks to all those who chipped in to help.
if ([update uniqueId]) {
#synchronized (self.downloadProgress) {
if ([self.downloadProgress objectForKey:[update uniqueId]]) {
NSDictionary *progressInfo = [[self.downloadProgress objectForKey:[update uniqueId]] copy];
if ([progressInfo objectForKey:#"progressString"]) {
return [progressInfo objectForKey:#"progressString"];
}
}
}
} (

Assigning unarchived object to a different object works, why/how?

Assigning an archived dictionary object but unarchived and assigned to an array does not seem to produce an exception and the logged out data from the array is that of the dictionary and not in array format at all if it was possible to assign to a different return type, kinda link casting but instead your unarchiving and assigning directly. Why does this work? if anyone can explain it much more deeply it would bring to light a better understanding of the unarchiving process and the way it works.
NSDictionary *glossary = #{
#"Abstract class": #"some class",
#"Adopt": #"borrow",
#"archiving": #"Storing an object for later use"
};
if([NSKeyedArchiver archiveRootObject:glossary toFile:#"propertyList2.plist"] == YES)
NSLog(#"Archive success");
else
NSLog(#"Archive unsuccessfull");
NSArray *unArchiving = [NSKeyedUnarchiver unarchiveObjectWithFile:#"propertyList2.plist"];
NSLog(#"%#", unArchiving);
//for (NSString *obj in unArchiving) {
// NSLog(#"%#: %#", obj,unArchiving[obj]);
// }
Welcome to Objective-C! Due to the dynamism of the language, the type of an object reference (AKA variable) really only matters at compile time. At runtime, what the object is matters; what you thought it aught to be when you wrote the code doesn't.
The reason your code for unarchiving works is because the for (X x in Y) syntax is identical for arrays and dictionaries. Similarly, the indexing syntax (a[x]) is identical. All of that is handled at runtime, based on the type of the collection being iterated. As long as the semantics are the same, your code will run without error. Obviously, the moment you try to treat that dictionary as an array (e.g. refer to .lastObject) it will blow up.

<__NSCFSet: 0x74957b0> was mutated while being enumerated

I can't undarstand why my code is crashes:
<__NSCFSet: 0x74957b0> was mutated while being enumerated
Previously I read simular topics but their problem was that the code calls in different threads. My code always calls in Thread 1.
It crashes times to time.
Here is a code where it happens:
- (void)processReceivedResponse:(JTResponse *)aResponse {
NSParameterAssert(aResponse);
id <JTRequestDelegate> delegate = [self processResponseWithReceiver:aResponse];
if (delegate == nil) {
for (JTObserver *someObserver in observers) {
if (someObserver.requestType == aResponse.type &&
![someObserver.delegate isEqual:delegate]) {
[someObserver.delegate didReceiveResponse:aResponse];
}
}
}
}
The error you're getting is caused by something changing the "observers" set while you're looping through it.
It's hard to tell what that might be from just the snippet you posted. Is something in the delegate you're invoking on someObserver changing the "observers" set?
You could try simply copying the observers set and looping over the copy:
for (JTObserver *someObserver in [[observers copy] autorelease]) {
...
}
If you're using ARC (automatic reference counting), you don't need to use autorelease.

Enumeration and removing a particular object from NSMutableArray

I'm having trouble removing items from my NSMutableArray. I'm extremely new to Objective-C, so please bear with me.
So far, I have the following: I'm trying to remove a line from the array if it has certain text inside. I cannot do this while fast-enumerating, so I'm trying to store the index, for removal after the enumeration has finished. However, I'm being told that this makes a pointer from an integer without a cast. Confused!
//First remove any previous Offending entry.
//Read hostfile into array.
NSString *hostFileOriginalString = [[NSString alloc] initWithContentsOfFile:#"/etc/hosts"];
NSMutableArray *hostFileOriginalArray = [[hostFileOriginalString componentsSeparatedByString:#"\n"] mutableCopy];
NSInteger hostFileOffendingLocation;
//Use a for each loop to iterate through the array.
for (NSString *lineOfHosts in hostFileOriginalArray) {
if ([lineOfHosts rangeOfString:#"Offending"].location != NSNotFound) {
//Offending entry found, so remove it.
//[hostFileOriginalArray removeObject:lineOfHosts];
hostFileOffendingLocation = [hostFileOriginalArray indexOfObject:lineOfHosts];
//NSLog(#"%#", hostFileOffendingLocation);
}
}
//Release the Array.
[hostFileOriginalArray release];
//Remove offending entry from Array.
[hostFileOriginalArray removeObject:hostFileOffendingLocation];
My real question is why are you releasing your array before modifying it
try moving
[hostFileOriginalArray release];
to after
[hostFileOriginalArray removeObject:hostFileOffendingLocation];
You can do this without the loop by calling [hostFileOriginalArray removeObjectIdenticalTo:#"Offending"];
Note that it will remove multiple instances of the offending object, but that looks like what you want anyway. It will also do the operation in a fast way, without you having to worry about the implementation detail of which loop to use.
As a general rule (especially with the really commonly used objects like containers and NSString), check the class reference to see if Apple already has a way of doing what you want to do. It makes your code more readable to other Cocoa users (including future you), and reduces code maintenance- you're now leaving it up to Apple to add new technologies like Fast Enumeration to their code, and you get it for free when you link against new versions of the SDK.
Also, you should probably return hostFileOriginalArray at the end of the function, so it can do something useful- you can return it as an autoreleased object.
//Remove offending entry from Array.
[hostFileOriginalArray removeObjectAtIndex:hostFileOffendingLocation];
//Release the Array.
[hostFileOriginalArray release];
you should have been getting compiler warnings... take a look at them, they are usually very helpful, I always try to have 0 warnings... that way I know where I have done something careless.

Correct Structure to check for Errors using NSError

I'm coding up various routines and I'm trying my best to keep it neat and refactored.
Methods I'm creating are starting to look similar to this code:
-(IBAction)buttonPress:(id)sender {
// Create Document Shopping List with this document
[self doSomething:&error];
if(error) {
[NSApp presentError:&error];
return nil;
}
[self doSomethingElse:&error];
if(error) {
[NSApp presentError:&error];
return nil;
}
[self doYetSomethingElse:&error];
if(error) {
[NSApp presentError:&error];
return nil;
}
}
I love NSError, but this seems like an awfully clumsy way of handling all my errors.
A few thoughts I've had about alternative ways:
a) the error checking could be built into the methods doSomething, doSomethingElse etc, but then I wouldn't be able to exit the button press method without doing some kind of checking on the return value, which would lead me back to a similar structure.
b) I could set up the NSError as being Key Value Observed, but something about this feels deeply wrong. I'm very aware of the possibilities of abuse with KVO, so I'm trying to do everything without it whereever possible.
Surely I'm missing something really basic here? Is there a pattern that can help me? Or is this structure OK?
I think that none of the answers presented here are taking into account Apple's recommended practices.
Basically you should never check for the NSError object to determine if there was a problem. You check if there was a problem by checking the value returned from the method that takes a pointer to a pointer to an NSError.
From the Apple documentation:
Important Success or failure is indicated by the return value of the
method. Although Cocoa methods that indirectly return error objects in
the Cocoa error domain are guaranteed to return such objects if the
method indicates failure by directly returning nil or NO, you should
always check that the return value is nil or NO before attempting to
do anything with the NSError object.
The gist of your question is whether there are structural improvements you can make to your error handling. I think so, by essentially introducing more layers of nesting, either by extracting more code into separate methods/functions, or by introducing nesting in your high level sample method.
The idea is, when it comes to handling most errors, you probably are either interested in performing an alternate task, or in failing and propagating the error up the chain so that some responsible controller can convey the error to the user through UI.
Using this idea of "propagate or handle", I would rewrite your sample method like this:
-(IBAction)buttonPress:(id)sender {
// Create Document Shopping List with this document
[self doSomething:&error];
if(error == nil) {
[self doSomethingElse:&error];
if (error == nil) {
[self doYetSomethingElse:&error];
}
}
if(error) {
[NSApp presentError:&error];
}
}
Note that there are good arguments against introducing too much nesting in a particular method. Nesting such as this is essentially a short alternative to extracting methods. It might make more sense, for instance, that "doSomething:" itself calls doSomethingElse:, which calls doYetSomethingElse: for instance. This would impose the same structure on the code as the if-nest, but would be arguably more maintainable.
As an aside, I am not a fan of inline return statements. In this particular instance, the sample method doesn't actually call for a return value, but if it did, I prefer to set a local variable to the returned value and only return at the end of the flow control. Jumping out of a function or method prematurely is a sure way to encounter weird bugs, IMHO.
I think the real question is how much granularity you need in your error handling. Your code is fundamentally correct - but you can clean things up by checking for errors less frequently, or using a catch-all approach like teabot mentioned in his answer with NSException. A lot of the built-in functions that return errors (like NSFileManager's moveItemAtPath:) return a BOOL in addition to a providing an NSError object - so you could also use nested if statements if you don't need the NSError information.
All and all though, there's really not a great way to do this. If your code is long, KVO might be a cool solution. I've never tried it for a situation like this, though.
Note: When I posted this I was unaware of any MacOS/Cocoa exceptions debate. Please bear this in mind when you consider this answer.
Why not use exceptions instead? This will allow you to dispense with the error parameter on your methods and handle your errors in one place.
-(IBAction)buttonPress:(id)sender {
// Create Document Shopping List with this document
#try {
[self doSomething];
[self doSomethingElse];
[self doYetSomethingElse];
} #catch (NSException* e) {
[NSApp presentException:e];
}
return nil;
}
You will of course need to throw exceptions as required from within your doXXXX methods:
NSException* e = [NSException exceptionWithName:#"MyException"
reason:#"Something bad happened"
userInfo:nil];
#throw e;