Program crashed in iOS5 and normal in iOS4? - ios

My game created in cocos2d 0.99.5.I tested it and released in App Store already.
After I updated my iPhone from iOS4.3.3 to iOS5.0, my game crashed so frequent.
* Terminating app due to uncaught exception 'NSGenericException', reason: '* Collection <__NSArrayM: 0x668a540> was mutated while being enumerated.'
* First throw call stack:
(0x30bed8bf 0x37d921e5 0x30bed3e3 0x5cd1 0x2f837 0xa577b 0xae245 0xcc29d 0xcdfed 0x322ee423 0x322ee379 0x358d3f93 0x31e81891 0x30bb6f43 0x30bc1553 0x30bc14f5 0x30bc0343 0x30b434dd 0x30b433a5 0x33771fed 0x32bb5743 0x2c65 0x2bf8)
terminate called throwing an exception
This crash broken memory stack.After I added "objc_exception_throw" breakpoint. I found crash happening in for{} NSArray loop.
I don't know why this crash only happened is iOS5.This test of game is ready for new version and new content.I can't resolve this problem and feel dejected.
Could someone help me?
====================================
update(11/3/11):
NSMutableArray *monsterArray; // monsters information
[gameObject schedule:#selector(gameSchedule:) interval:1.0/30]; // schedule for everything update
- (void) gameSchedule:(ccTime)_dt
{
...
for ( Monster *mon in monsterArray ) // here causing crash
{
...
// check every monster state
}
}
I don't know thread module of cocos2d thoroughly.In my game project, there are some CCAction do sequence action:
id action = [CCSequence actions:
...,
[CCCallFunc actionWithTarget:self selector:#selector(doSth:)],
nil];
[object runaction:action];
- (void)doSth:(id)_sender
{
//some selector modified object value in monsterArray
//some selector deleted or added object in monsterArray
}
Whether cocos2d creat a new thread for doSth: and causing the crash ?
There are many selector which did these action(modify, delete and add) in my game project.
How can I resolve this problem?
===================================================================
update(11/4/11):
#Amorya
I checked Documents about NSCopying protocol.
[monsterArray copy] return a new NSMutableArray.New object in [monsterArray copy] run actions which like CCMove\CCSequence\CCJump will causing correct process?I don't understand.Please explain it.
#Brad Larson
I added a Symbolic breakpoint "objc_exception_throw" and find out the for{} NSMutableArray loop caused the crash.

Change this line
for ( Monster *mon in monsterArray )
to
for ( Monster *mon in [monsterArray copy] )
You're not allowed to modify an array while iterating over it using fast enumeration (as LearnCocos2D mentioned in a comment). Copying the array is the simplest way to fix that without changing your code's logic.
If you're not using ARC, you'll also need to throw an autorelease in there.

Related

Odd error (UITextSelectionView) while calling a method?

I'm facing a problem while calling a method and I don't know how figure it out.
Basically, during the main menu, I want to call a SKNode showing a tutorial part. The code is the following:
- (void)didMoveToView:(SKView *)view
{
...
if ([[GameData sharedData] openingTutorial]) { // Checks if the menu needs the tutorial
[_tutorialObj performSelector:#selector(runTutorialWithStep:)
withObject:[NSNumber numberWithInt:8]
afterDelay:3.0
];
}
}
When the method didMoveToView: is called (even before waiting the 3 seconds for the runTutorialWithStep:), I got this error:
[UITextSelectionView name]: unrecognized selector sent to instance 0x1576e6c0
2014-10-14 11:01:19.430 [406:130379] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITextSelectionView name]: unrecognized selector sent to instance 0x1576e6c0'
The odd thing is that in the previous class I use the same tutorial's action in the didMoveToView: and it's working right. But...
Thing is getting more strange here!!!
If I use an intermediary method for this calls:
- (void)didMoveToView:(SKView *)view
{
...
[self performSelector:#selector(intermediaryMethod)
withObject:nil
afterDelay:3.0
];
}
- (void)intermediaryMethod
{
[_tutorialObj performSelector:#selector(runTutorialWithStep:)
withObject:[NSNumber numberWithInt:8]
afterDelay:0.0
];
}
Everything works without issues. I don't want to avoid the problem but solve this. Any advices?
The error says it all. You try to send a 'name' message to object that doesn't implement it (UITextSelectionView). Since your second take works the cause is either in
[[GameData sharedData] openingTutorial]
method or before this call. Search for objects calling 'name' and check if it's the UITextSelectionView in question.
That or maybe you have weak reference to general view object and during those three seconds before calling runTutorialWithStep you reassign it to object that implements 'name' message.
Ok, I solved the problem.
I added a breakpoint for every exception and I realized that the issues was due to an other class (the only one with UITextView).
Basically I removed the text field from its parent ([self removeFromParent]) by my own once I did not need it anymore.
I suppose the error was fired during the deallocation 'cause the program can't find the UITextView. I managed to remove this statement and everything works right.
Actually I still have doubts because I don't understand why this exception is throw only if I call the [_tutorialObj runTutorialWithStep:] method.
I found the way to fix it.
UITextView *textView = .....
textView.selectable = NO;

How to lookup code relating to variable memory address from Xcode IOS crash?

I have a weird crash here that I believe is stemming from an external library, but I'm having trouble tracking down the stack trace, and not sure how to use Xcode's memory exploration tools.
This is what I'm getting in the console when it crashes:
*** Terminating app due to uncaught exception 'NSGenericException',
reason: '*** Collection <__NSArrayM: 0x208c5d00> was mutated while being enumerated.'
*** First throw call stack:
(0x37ae32a3 0x35e0d97f 0x37ae2d85 0x7c57d 0x728b1 0x6b865 0x34d9f11f 0x34d9e4b7 0x34da31bd 0x37ab6f3b 0x37a29ebd 0x37a29d49 0x368602eb 0x38ffb2f9 0x643d1 0x64358)
libc++abi.dylib: terminate called throwing an exception
I'm using MKNetworkKits UIImageView setImageFromURL additions to supply images to a UITableViewCell imageview (a custom imageview object, not the default imageview that comes with UITableViewCell). When I remove this setImageFromURL call, I don't get any crashes.
I tried using dwarfdump and atos on the command line but none of the addresses in the crash above link to any specific function addresses.
I have scoured for places where forin enumeration loops are being performed, but can't seem to find any that actually mutate data. Clearly I'm overlooking something..
Any advice/tips/help here would be super appreciated..
EDIT: Thanks so far for the comments. Any tips on how to utilize the memory address to trace down actual lines of codes would be helpful - can Xcode do some of what Visual Studio debugger can do, with respect to code & memory inspection?
Steps :
Run application and check on which ViewController the app is crashing with this exception.
Once you find the ViewController check entire code for that controller for NSArray.
Check related delegate you are calling from that controller, if any.
Check all custom subclasses you are using in that controller.
From the description it seems like you are enumerating an NSArray and checking values of it. Once you find the value you want to change those value. So, you are creating a mutableCopy of NSArray and trying to change inside the current running enumeration.
Solution :
Create NSMutableArray outside enumeration. While enumerating NSArray the objectAtIndex: will remain same for both array when you find the value you want to change. Change it inside mutable copy(created outside). [Bad for memory]
Create NSMutableArray outside enumeration of current NSArray. Then enumerate NSMutableArray. [Enumeration Will be Slower as you are enumerating mutable copy]
Hunt the Bug down!
This maybe useful for you:
replace your main.m file code with this (for ARC):
int main(int argc, char *argv[])
{
#autoreleasepool {
int retVal = -1;
#try {
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([FRAppDelegate class]));
}
#catch (NSException* exception) {
NSLog(#"Uncaught exception: %#", exception.description);
NSLog(#"Stack trace: %#", [exception callStackSymbols]);
}
return retVal;
}
}
I suggest, starting simple, somewhere, you are altering an array, probably an NSMutableArray inside a loop. This can be easily fixed by using temporary store, them remove the temp objects AFTER the loop completes.
If this does not help, set an exception break point to break on all exceptions. This will likely stop on the line of code causing the error.
This helped:
https://stackoverflow.com/a/12266856/420594
Editing the Debug scheme and switching from LLDB to GDB helped a great deal - the crash points directly to a line of my own code now.

Cocos2d: nasty exception with batched sprites

I can't quiet figure how to debug this. I have a CCScene running and when the scene is replaced I get the following error message.
The scene has a sprite batch node where the CCSpriteSubclass is added.
That's the cleanup method and below that you will find the assertion failure message:
-(void) cleanup
{
[[GameController sharedGameController].musicLayer removeMusicSourceForKey:backgroundMusicFileName];
[CCTextureCache purgeSharedTextureCache];
[CCSpriteFrameCache purgeSharedSpriteFrameCache];
[CCAnimationCache purgeSharedAnimationCache];
// [[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
[super cleanup];
}
The batch node is created as following in the initWithId:(int)sceneId method:
//Prepare sprites sheets for the rest of the game art
[frameCache addSpriteFramesWithFile:[NSString stringWithFormat:#"art%i-hd.plist", sceneId]];
sharedSpriteMainBatchNode = [CCSpriteBatchNode batchNodeWithFile:[NSString stringWithFormat:#"art%i-hd.png", sceneId]];
And then I add all CCSpriteSubclass objects.
That's the assertion failure message:
** Assertion failure in -[CCSpriteSubclass setTexture:], /Users/xxx/Desktop/xxx/xxx/libs/cocos2d/CCSprite.m:934
2012-12-03 12:54:33.335 RockTale[869:707] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'CCSprite: Batched sprites should use the same texture as the batchnode'
*** First throw call stack:
(0x338d28bf 0x303c61e5 0x338d27b9 0x311193b3 0x9ad43 0x9a2fb 0x4bca3 0x44ddf 0x38b07 0x503f7 0x94c03 0xbbeed 0xbcfe7 0x34fb7423 0x34fb7379 0x31b4cf93 0x36e52891 0x3389bf43 0x338a6553 0x338a64f5 0x338a5343 0x338284dd 0x338283a5 0x37f9afcd 0x3128b743 0x2edf 0x2ea0)
terminate called throwing an exception(lldb)
EDIT: Added a breakpoint to the setTexture method and here is what I "DON't" see :)
EDIT 2: I whish I could manage to retrieve the full stacktrace like in Java.. I have asked this in a different question and I was told I should add a global exception.. I still need to figure out how to retrieve the stacktrace..
From the text of your exception message it seems that you create sprites with spriteframes from different spritesheets.
I solved this problem in the same way as here. It was due to the fact that sprite frames where referred while the previous class was replacing the existing one and hence the previous class cleanup method was calling the purge frame cache which was consequently removing the yet unused sprite frames which where being loaded in memory by the newly created object.

cocos2d - NSMutableArray with levels, restart level and crash, next level works good

I've nsmutablearray with levels and two buttons. Next level and try again. When user touched next level, I set objectAtIndex:indexCurrLevel+1 and next level is loading without problem. But if user touched try again and I try to set level to objectAtIndex:indexCurrLevel app crashed with children already added error.
That is crazy because if I set manually try again for ex. objectAtIndex:5 works perfectly until user don't playing on 5 level, because app crashed.
For index different than current level index, works perfectly. (objectAtIndex:index - works)
manually set index gave the same reason as with index.
[self removeFromParentAndCleanup:YES];
Levels *l = [levels2 objectAtIndex:index-1];
Game *hl = [[Game alloc]initWithObstacles:[l staticO] :[l rotateO]:[l lvl]:[l level]:[l pendulumO]:self.levelsArray];
[hl setLevels2:self.levels2];
[hl setBasketY:[l basketY]];
[hl setBasketX:[l basketX]];
[l release];
[[CCDirector sharedDirector] replaceScene:(CCScene*) hl];
[hl configureLevel];
[hl release];
Eroor:
Assertion failure in -[Game addChild:z:tag:],
../libs/cocos2d/CCNode.m:388
2012-05-11 19:03:20.349 Game[932:10a03] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'child already added. It can't be added again'
* First throw call stack:
Guessing an array-bounds issue, but it's impossible to verify without a code sample or crash log.
Try removing the statement [l release]. In general you should only release an object on which you have called retain or else which you have obtained using a method that begins with init, new or copy. The array levels2 will also be retaining each level, and it may be appropriate to leave it as the levels' owner. Run the static analyser in Xcode to pick up these issues.
Read the message : you are trying to addChild an object which already has a parent ... ie has already been added as a child of a CCNode descendant somewhere else in your code base. Line 388 of CCNode is an NSAssert, not breakable. Change CCNode temporarily to have a breakable instruction, as follows:
if (nil==child) {
CCLOG(#"%#<addChild> : have nil child. not adding.",self.class);
return;
}
if (child.parent) {
CCLOG(#"%#<addChild> : This child is already added somewhere. not adding.",self.class); // **** PUT BREAKPOINT HERE *****//
return;
}
NSAssert( child != nil, #"Argument must be non-nil"); // was line 388
NSAssert( child.parent == nil, #"child already added. It can't be added again");
the last 2 lines are from CCNode (in my project). If the error you mention occurs, i would put a break at the line indicated, rerun, and look at the stack trace. When you are done with your dev/test cycle, and such things matter to you, remember to restore cocos2d to its original state for such temporary mods.

XCode4 Debugger Always Breaks in Main

After upgrading to XCode4 (v. 4.2, 4D199) it seems every time my apps crash while debugging, the debugging points to main(), and the stack is unsymbolicated and useless.
This has been working fine for years, I have no idea what has gone wrong.
I'm using GDB. I also tried the LLDB as per this advice, and it didn't work either (similar, useless stack).
My breakpoints work, I get the full stack, and can inspect variables when my code hits those.
Steps to reproduce:
NB. this happens with my own project, but I'll use Apple's code here to remove that variable from the equation
Download the following sample from Apple: https://developer.apple.com/library/ios/#samplecode/UICatalog/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007710
In the ImagesViewController class, add the following code to the viewDidLoad method (so it will crash – we want it to crash for this test):
// please note: this code is designed to crash! I want it to crash, to highlight my issue with XCode.
NSMutableArray* test = [NSMutableArray new];
[test insertObject:NULL atIndex:0];
Then run the app & hit the 'Images' row.
It crashes with a message like:
2011-12-23 14:07:02.788 UICatalog[13394:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x37bbb8bf 0x316a11e5 0x37b1020f 0x699f 0x34fac7ff 0x34fb8c39 0x34fb8aa9 0x34fb898f 0x34fb815b 0x34fb7f53 0x34fac673 0x34fac349 0x66c1 0x35026565 0x3509ece7 0x31aec943 0x37b8fa63 0x37b8f6c9 0x37b8e29f 0x37b114dd 0x37b113a5 0x3768ffcd 0x34fa1743 0x2459 0x2418)
terminate called throwing an exception(gdb)
View in xcode:
Thanks to brigadir for pointing me to the solution!
It works well. Here's some screenshots for how to solve this for anyone finding my question:
Tap the plus button of the breakpoints tab
Then click Done

Resources