I'm currently using MWPhotoBrowser in my app and when I scroll quickly through images I get the following error:
Received memory warning.
2014-02-17 16:42:35.117 App[10803:60b] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x156f3160> was mutated while being enumerated.'
*** First throw call stack:
(0x2e71de83 0x38a7a6c7 0x2e71d971 0x151167 0x15139b 0x311643ff 0x3116446f 0x31164665 0x31164805 0x3111ea67 0x38f5f0af 0x38f6072f 0x38f61959 0x2e6e85b1 0x2e6e6e7d 0x2e651471 0x2e651253 0x3338b2eb 0x30f06845 0xff035 0x38f73ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
I'm currently loading images stored in the app locally.
This is the method throwing the exception:
- (void)releaseAllUnderlyingPhotos:(BOOL)preserveCurrent {
for (id p in _photos) {
if (p != [NSNull null]) {
if (preserveCurrent && p == [self photoAtIndex:self.currentIndex]) {
continue; // skip current
}
[p unloadUnderlyingImage];
}
} // Release photos
}
Any help would be greatly appreciated!
I don't know exactly which version of MWPhotoBrowser you are using, but in the latest one here, the releaseAllUnderlyingPhotos: method reads:
- (void)releaseAllUnderlyingPhotos:(BOOL)preserveCurrent {
// Create a copy in case this array is modified while we are looping through
// Release photos
NSArray *copy = [_photos copy];
for (id p in copy) {
if (p != [NSNull null]) {
if (preserveCurrent && p == [self photoAtIndex:self.currentIndex]) {
continue; // skip current
}
[p unloadUnderlyingImage];
}
}
// Release thumbs
copy = [_thumbPhotos copy];
for (id p in copy) {
if (p != [NSNull null]) {
[p unloadUnderlyingImage];
}
}
}
Please note these two lines:
NSArray *copy = [_photos copy];
for (id p in copy) {
Before iterating through _photos, a new array copy is created to protect this iteration from _photos being modified in other places.
In your code, releaseAllUnderlyingPhotos: is deleting objects straight from the _photos array, but this array could be modified in other parts of the code, for example, didReceiveMemoryWarning, as it is your case.
Once you modify your code to iterate over a copy of _photos in releaseAllUnderlyingPhotos: your problem should go away.
Related
I have another question about checking the existence of valueForKey.
Here's my code:
id _jsonId = [NSJSONSerialization JSONObjectWithData:[_json dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&_error];
Monday = [[NSMutableArray alloc] init];
if ([_jsonId valueForKey:#"Mon"]!= Nil) {
_keyMon = [_jsonId valueForKey:#"Mon"];
[Monday addObject:#"Monday"];
for (int i=0; i<5; i++) {
if ([_keyMon objectAtIndex:i]!=[NSNull null]) {
[Monday addObject:[_keyMon objectAtIndex:i]];
}
}
} else {
[_keyTues addObject:#"No Class For Today"];
[Monday addObject:[_keyMon objectAtIndex:1]];
}
The idea is, if the _jsonId valueForKey came back nothing, I can add this NSStringaddObject:#"No Class For Today incase XCode tells me that:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
like it has been telling me now. Anyone have any solution?
I tried if ([_jsonId valueForKey:#"Mon"]!= Nil) didn't work.
I tried if ([_jsonId valueForKey:#"Mon"]!= nil) didn't work.
I tried if ([_jsonId valueForKey:#"Mon"]!= (id)[NSNull null]) didn't work.
I tried if ([_jsonId valueForKey:#"Mon"]!= [NSNull null) didn't work.
I know that _jsonId valueForKey is came back as a pointer, but I have no idea how to check if the pointer is null(or nil in Objective-C if I'm correct). Please help me.
UPDATE:
I have tried using objectForKey and here is a code(_jsonId objectForKey is nil, that I know to try testing the code)
if (_jsonId[#"Sun"]== nil) {
[_keySun addObject:#"No Class For Today"];
[Monday addObject:[_keySun objectAtIndex:1]];
}
else{
_keySun = [_jsonId objectForKey:#"Sun"];
[Monday addObject:#"Sunday"];
for (int i=0; i<5; i++) {
if ([_keySun objectAtIndex:i]!=nil) {
[Monday addObject:[_keySun objectAtIndex:i]];
}
}
}
Still, XCode telling me that I'm add a nil into NSArray.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
This is driving me crazy...
_jsonId as defined by:
id _jsonId = [NSJSONSerialization JSONObjectWithData:[_json dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&_error];
... will be either an array or a dictionary. Based on your code I think you're assuming that it's always a dictionary. So you probably want to add:
if (![_jsonId isKindOfClass:[NSDictionary class]]) ...
You then want to know what's in a dictionary, if anything. So use objectForKey:. Or, better, just _jsonId[#"Mon"]. You'll get an object or you'll get nil.
valueForKey: is a completely different mechanism, key-value coding. It is defined on NSObject so inherited by NSDictionary as well as just about everything else. It is defined to raise an exception for an unknown key. Since it raises an exception instead of returning a result, your attempts to compare a result are ineffective.
I think I figured it out. Let's look at the code:
if (_jsonId[#"Sun"]== nil) {
[_keySun addObject:#"No Class For Today"];
[Monday addObject:[_keySun objectAtIndex:1]];
}
else {
_keySun = [_jsonId objectForKey:#"Sun"];
...
If there is an object for the key "Sun" then you store it into _keySun. If there is no object, then you store nothing into _keySun. _keySun will be nil. You send an addObject message to _keySun - but any message sent to a nil object does nothing. You then call [_keySun objectAtIndex:1]. Again, sending a message to a nil object does nothing, and returns nil, which is why you add nil to the Monday object and get a crash.
If you had set _keySun to an empty NSMutableArray, you would have crashed for another reason: You try to add one object. You can read that one object with objectAtIndex:0. But to read objectAtIndex:1 you need two objects in the array.
BTW. You will get [NSNull null] from the JSON parser if the JSON document that you are reading contains an explicit null. So if your JSON contains "Sun": null then objectForKey:#"Sun" will give [NSNull null]. If your JSON doesn't contain the key "Sun" at all, objectForKey:#"Sun" will give nil.
I have found the Error Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object' when i add object to mutable array at second time first time added successfully but second time it is crash the app i think there is problem with when i added object to array.
Below code is crash.
- (void) viewWillAppear:(BOOL)animated
{
if ([defaults objectForKey:#"Groups"] != nil)
{
NSLog(#"not nil defaults.");
arrGroups = (NSMutableArray *)[defaults objectForKey:#"Groups"];
}
else
{
NSLog(#"nil defaults.");
arrGroups = [[NSMutableArray alloc] init];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(#"button index == %ld",(long)buttonIndex);
//txtCategory = [[alertView textFieldAtIndex:0] text];
if (buttonIndex == 1)
{
//[self addingCategory:self];
NSLog(#"Adding Group name = %#",[[alertView textFieldAtIndex:0]text]);
[arrGroups addObject:[[alertView textFieldAtIndex:0]text]]; **//Crash here! at the time of add second object or also when i remove first object**
NSLog(#"Added to array.");
[defaults setObject:arrGroups forKey:#"Groups"];
[defaults synchronize];
//[defaults release];
[tblGroups reloadData];
}
}
when i remove first object at that time i replace the userdefault with updated array so there is no problem i think. and i did not found proper reason for that crash.
so please support me either understood me the problem or solution but without understand the problem i can't understood solution so please any one tell that why this happen.
Thanks.
The problem with assigning to a NSMutableArray is, it will only work if defaultDefects was assigned an NSMutableArray for the given key.
Note: NSUserDefaults always returns an immutable object.
Do this instead
NSMutableArray *arrGroups = [[defaults objectForKey:#"Groups"]mutableCopy];
this guarantees a mutable copy.
Another way is.
arrGroups = [[NSMutableArray alloc]initWithArray:[defaults objectForKey:#"Groups"]]; //in your viewWillAppear where you assign array from defaults.
I creating a game in Cocos2D 2, but my issue is with NSArray/NSMutableArray.
A class called SocketManager that manages the socket class which is derived from CCSprite. Socket only has extra member variable called row which is an int. The SocketManager keeps an array with all the Sockets sprites that are within the game.
In the game class I have this code to add the sockets to the manager:
for (int i = 1; i <= numRows; i++) {
for (int j = 1; j <= i; j++) {
Socket *socket =[Socket spriteWithFile:#"Tile_Socket.png"];
socket.row = i;
socket.anchorPoint = ccp(0.5, 0.5);
/* Shortend to cut out useless code */
[socketsManager addSocket:socket];
[self addChild:socket];
}
}
This is the SocketsManger add function:
-(void)addSocket:(CCSprite *)socket {
[sockets addObject:sockets];
}
Later on in the game in the update function it checks if the row wants to be changed and calls the SocketManager's function called :
-(NSArray *)searchSocketByRow:(int)row; {
NSMutableArray *array = [[NSMutableArray alloc] init];
for (Socket *socket in sockets)
CCLOG(#"Row: %i", socket.row);
// if ([socket row] == row)
// [array addObject:socket];
// CCLOG(#"Found %i sockets.", [array count]);
// return [NSArray arrayWithArray:[array mutableCopy]];
}
When I try to call socket.row or [socket row] I get the error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM row]: unrecognized selector sent to instance
This method looks wrong try to change it to:
-(void)addSocket:(CCSprite *)socket {
[sockets addObject:socket];
}
You try to add array to array but you want to add CCSprite object.
It should help.
You have an extra S in the mix. In the add socket function change this
[sockets addObject:sockets];
to
[sockets addObject:socket];
Try
[sockets addObject:socket];
without s at the object you want to add
So I am really new at developing for iOS, and I've been doing my best, to search for an answer, to debug it and anything I could come up with.
Though, I haven't been able to find a solution to the issue.
I've been trying to fetch an external JSON document, which works fine, but when it comes to parsing it, it buggers up.
First of all, this is the error message I'm getting, the whole lot of it.
2013-01-31 22:40:19.261 demodh[6205:c07] View Loaded
2013-01-31 22:40:19.479 demodh[6205:c07] -[__NSCFStringcountByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x7554f90
2013-01-31 22:40:19.480 demodh[6205:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x7554f90'
*** First throw call stack:
(0x1c93012 0x10d0e7e 0x1d1e4bd 0x1c82bbc 0x1c8294e 0x28d3 0xbd6589 0xbd4652 0xbd589a 0xbd460d 0xbd4785 0xb21a68 0x4615911 0x4614bb3 0x4652cda 0x1c358fd 0x465335c 0x46532d5 0x453d250 0x1c16f3f 0x1c1696f 0x1c39734 0x1c38f44 0x1c38e1b 0x1bed7e3 0x1bed668 0x14ffc 0x1d6d 0x1c95 0x1)
libc++abi.dylib: terminate called throwing an exception
(lldb)
And this is the code I'm using at the moment:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *allDataDictionary = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
for(NSDictionary *dict in allDataDictionary)
{
if (![allDataDictionary isKindOfClass:[NSDictionary class]])
{
NSLog(#"2Unable to process temp array because it's an instance of %#", [allDataDictionary class]);
}
else
{
for(NSDictionary *deal in dict)
{
if (![deal isKindOfClass:[NSDictionary class]])
{
NSLog(#"Unable to process temp array because it's an instance of %#", [deal class]);
}
else
{
NSString *title = [deal objectForKey:#"title"];
NSLog(title);
}
}
}
}
}
And the JSON I'm loading is: Link
I hope you're able to assist me in finding a solution.
The problem is you're fast-enumerating a NSDictionary and expecting to get its values, when in fact you'll get its keys. When you try to fast-enumerate an NSString you get the assertion you're seeing. You probably wanted this:
for(NSObject *key in allDataDictionary) {
NSDictionary *dict = allDataDictionary[key];
...
for (NSObject *dealKey in dict) {
NSDictionary *deal = dict[dealKey];
}
...
Alternatively, if you really want to enumerate the values and don't need the keys:
for(NSDictionary *dict in [allDataDictionary allValues]) {
...
I have checked the examples of how to fix this problem but I am still facing it..
My Code is
NSEnumerator *enu= [obstacles objectEnumerator];
NSMutableArray *delete = [[NSMutableArray alloc] init];
Object *obj;
while ((obj=[enu nextObject])!=nil)
{
if ([obj isKindOfClass: [BObject class]] && CGPointEqualToPoint(obj.position, point) ) {
[view.objects removeObject: obj];
//[obstacles removeObject: obj];
[delete addObject:obj];
}
}
[obstacles removeObjectsInArray:delete];
[delete release];
the error is *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x6a97ba0> was mutated while being enumerated.'
Update: My code work if there is only one object in my obstacles array. it fails with multiple objects..