Dealloc causing crash in changing between scenes in Cocos2D - ios

I'm building a Cocos2D game in which after two certain sprites collide (by simple bounding box technique), I call
[[CCDirector sharedDirector] replaceScene:gameOverScene];
to change to the game over scene.
Once it initializes the game over scene with everything in it, the game crashes and goes to this method in ccArray.m class:
void ccArrayRemoveAllObjects(ccArray *arr)
{ while( arr->num > 0 )
CC_ARC_RELEASE(arr->arr[--arr->num]);
}
with the message:
Thread 1: Program received signal: "EXC_BAD_ACCESS".
I tried to debug using breakpoints and figured out that once my gameOver scene gets initialized and ready to display, the dealloc method in the previous class (the gameplay class, which called the replace scene) gets called and after which it throws this error.
My update method:
-(void)update:(ccTime)dt
{
if (CGRectIntersectsRect(plane.boundingBox, enemy.boundingBox)) {
CCScene *gameOverScene = [GameOverLayer sceneWithWon:NO];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
} }
My dealloc method:
- (void) dealloc
{
[super dealloc];
[_monsters release];
_monsters = nil;
[mole release];
mole = nil;
[text release];
text = nil;
[mBG1 release];
mBG1 = nil;
[mBG2 release];
mBG2 = nil; }
I have no clue why this is happening. Please help.
Thanking you in anticipation.

You are calling super's dealloc before you are deallocating your gameplay scene.
Call super's dealloc at the end of your dealloc method :
- (void) dealloc {
[_monsters release];
_monsters = nil;
[mole release];
mole = nil;
[text release];
text = nil;
[mBG1 release];
mBG1 = nil;
[mBG2 release];
mBG2 = nil;
[super dealloc];
}
When you are calling super's dealloc first you are releasing your instance making it members invalid so accessing them after the dealloc will create memory bad access issues

because you didn't show enough code,i can only guess that some of these objects,such as _monsters,mole,text,mBG1,mBG2,were autoreleased before you release them in the dealloc funtion.So,they can not be released anymore.This is concerned ARC-automaic reference counting which you should know, it's basis of ios.
try this only:
- (void) dealloc {
[super dealloc];
}

Related

Cocos2D - removeChild not working

In my app I've use the particle designer to produce an animation when bodies collide,
the code is....
-(void)collision
{
for (IceCream *iceCream in [iceDict allValues]) {
if (CGRectIntersectsRect(iceCream.sprite.boundingBox, player.boundingBox)) {
if(actualType == 0)
{
[self increaseLooseCounts];
[self updateLives];
}
else{
[self increaseWinCounts];
[self updateLives];
}
//DEFINING THE PARTICLE ANIMATION
particle = [CCParticleSystemQuad particleWithFile:#"part.plist"]; //alt plist working with rainbow.plist
particle.position = ccp(iceCream.sprite.boundingBox.origin.x,iceCream.sprite.boundingBox.origin.y);
[self addChild:particle z:2];
[particle release];
//CALLING SELECTOR TO END THE PARTICLE ANIMATION
[self performSelector:#selector(killBlast) withObject:nil afterDelay:0.3f];
int icecreamKey = iceCream.sprite.tag;
[self removeChild:iceCream.sprite cleanup:YES];
[iceDict removeObjectForKey:[NSNumber numberWithInt:icecreamKey]];
}
}
}
-(void)killBlast{
[particle removeFromParentAndCleanup:YES];
}
But as soon as the killBlast is called the app crashes.
Please help !!
Remove this line:
[particle release];
You don't own particle object so you don't need to release it. You get it from autoreleased method and then it's retained when becomes added as a child. It will be released once it's removed from parent

Dealloc not called on subview with ARC

I have a not usual architecture. With one UIViewController and many subview's. I use UIView like viewController and UIViewController for transition animation.
UIView with many subview, which i push on main window, i removeFromSuperview and all ok, but subview not call dealloc method. Also i try to clean objects
- (void) dealloc {
NSLog(#"ActivityShowVC dealloc");
[showView removeFromSuperview];
showView = nil;
}
This called.
- (void) dealloc {
NSLog(#"ActivityShowView dealloc");
[mainScroll removeFromSuperview];
[titleView setDelegate:nil];
[titleView removeFromSuperview];
titleView = nil;
[photoView setDelegate:nil];
[photoView removeFromSuperview];
photoView = nil;
[predictionView setDelegate:nil];
[predictionView removeFromSuperview];
predictionView = nil;
[calendarView setDelegate:nil];
[calendarView removeFromSuperview];
calendarView = nil;
[descriptionView setDelegate:nil];
[descriptionView removeFromSuperview];
descriptionView = nil;
}
But this have some problem.
If dealloc is implemented and not called then there is something retaining the instance. You need to rethink the strong references to it.
Dealloc is not a good place to do anything other than releasing resources since the instance is no longer fully functional nor in a complete state. Doing things like: [showView removeFromSuperview]; are best done explicitly prior to deallocation.
As #Greg stated, most or all of what you are doing in dealloc is not needed under ARC. Subviews are now generally weak so no explicit dealloc is necessary. In fact they may be already gone depending on the order of the teardown of the view hierarchy.
I have solved a similar problem. In my Viewcontroller, I have a NSTimer pointer created, when I put the code below in 'viewWillDisappear', 'dealloc' is called.
if (_timer) {
[_timer invalidate];
_timer = nil;
}

iOS dealloc crash

find a strange code here
I have a viewcontroller, it has an array with books, and click the cell, then push to a detailViewController, detailVC has a variable infoDict,
#property (nonatomic,retain) NSMutableDictionary * infoDict;
navigationController push
DetailViewController * tDVC = [[DetailViewController alloc] init];
tDVC.infoDict = infoDict;
[self.navigationController pushViewController:tDVC animated:YES];
[tDVC release];
tap the back button, pop back, and inside dealloc of DetailVC
-(void)dealloc
{
[super dealloc];
NSLog(#"before %d",infoDict.retainCount);
[infoDict release];
}
but when I tap back, in this dealloc app crashes randomly, EXC_BAD_ACCESS.
when move [super dealloc] to the bottom of dealloc, it seems back to normal.
pls help me to understand this , many thanks
[super dealloc] deallocates the object itself. If you type dealloc and let Xcode autocomplete, you get this:
- (void)dealloc
{
<#deallocations#>
[super dealloc];
}
Meaning you should release objects and properties before you call [super dealloc]
Your -dealloc implementation is out of order. The call to -[super dealloc] must be the absolute last invocation in the dealloc method. When you access the ivar infoDict, the compiler is really doing something like self->infoDict and by this point, self has been deallocated and is no longer valid.
If at all possible, I recommend using ARC instead of manually managing memory.
Try
its better if you use self.infoDict = nil; instead of [infoDict rlease];
-(void)dealloc
{
NSLog(#"before %d",infoDict.retainCount);
[infoDict release];
[super dealloc];
}

App is crashing while releasing view controller object

My app is crashing while releasing view controller object.
Here is my code.
TagCloudWebViewController *controller=[[[TagCloudWebViewController alloc]init]autorelease];
controller.htmlString=[[notification userInfo] valueForKey:#"url"];
[self.navigationController pushViewController:controller animated:YES];
This is my code from wheny above method is called
-(void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(openTextInWebview:) name:#"kTouchTextUrl" object:Nil];
}
and
#pragma mark - UIGestureDelegate
- (void)longPressRecognized:(UILongPressGestureRecognizer *)longPressRecognizer {
CGPoint touchPoint = [longPressRecognizer locationInView:self];
NSArray *subviews = self.subviews;
for (int i=0; i<subviews.count; i++) {
TagView * tagLabel = (TagView *)[subviews objectAtIndex:i];
if ( CGRectContainsPoint( [tagLabel frame], touchPoint ) ) {
NSArray*objectArray=[[[NSArray alloc] initWithObjects:tagLabel.customLink, nil] autorelease];
NSArray*keyArray=[[[NSArray alloc] initWithObjects:#"url", nil] autorelease];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objectArray forKeys:keyArray ];
[[NSNotificationCenter defaultCenter] postNotificationName:#"kTouchTextUrl" object:nil userInfo:userInfo];
//[[UIApplication sharedApplication] openURL:[NSURL URLWithString: tagLabel.customLink]];
break;
}
}
}
and this is notification method
DidLoad method
- (void) viewDidLoad {
[super viewDidLoad];
_webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
_webView.delegate = self;
_webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight);
_webView.scalesPageToFit = YES;
[self.view addSubview:_webView];
[self initSpinner];
if (htmlString) {
[self openURL:[NSURL URLWithString:htmlString]];
}
}
WebView delgate method
-(void) webViewDidStartLoad:(UIWebView *)webView {
self.navigationItem.title = #"Loading...";
[spinnerView startAnimating];
isLoading = YES;
}
-(void) webViewDidFinishLoad:(UIWebView*)webView {
self.navigationItem.title = [_webView stringByEvaluatingJavaScriptFromString:#"document.title"];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
-(void) webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {
[self webViewDidFinishLoad:webView];
[self performSelector:#selector(stopSpinner) withObject:nil afterDelay:0.1];
isLoading = NO;
}
(void) openURL:(NSURL*)URL {
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:URL];
[_webView loadRequest:request];
}
Update: The following answer was in response to the original question of why the UIViewController with a UIWebView was not appearing. The OP's original theory was that it was related to some problem regarding the premature releasing of the view controller object. But, as outlined in my answer below, I suspect the problem was related to the creation of the view controller itself. Anyway, my answer to the original question follows (but it unfortunately has nothing to do with the revised question):
I personally don't suspect the problem has anything to do with the
releasing of the controller. I think it is in the creation of the
controller's view. There's nothing in the above code that causes the
object to be released, so you problem rests elsewhere and you need to
show more code. If you're concerned about your notification center
stuff, try bypassing it and just add a button that does your
TagCloudWebViewController alloc/init, sets htmlString and pushes,
and see if that still causes your program to crash, which I suspect it
will.
I notice that you're creating your controller via alloc and init,
but not initWithNibNamed. According to the UIViewController Class
Reference:
"If you cannot define your views in a storyboard or a nib file,
override the loadView method to manually instantiate a view
hierarchy and assign it to the view property."
So, bottom line, either use a NIB, use a storyboard or define a
loadView. Defining a viewDidLoad doesn't preclude the need for a
loadView. You need to create a view for your controller, which is
done for you if you use NIB or storyboard, or you have to do manually
via loadView, if you don't use NIB or storyboard.
See
iPhone SDK: what is the difference between loadView and viewDidLoad?
for a discussion of the differences between viewDidLoad and
loadView.
I don not see any thing that causing crashing.I think you have changed your question.As per question you not using ViewController any where.Please show more details.
Updated: Please check, you are creating autoreleased object, it might be you are releasing some where by mistake.Try to avoid autoreleased object as it remain in the Pool and later releases ,which may causes a memory issue for you.
The above problem is occurs due to WebView delgate. After pressing back button the reference of the object is deallocating from memory due to this app is crashing while releasing the viewcontroller object. I did some thing like
-(void) viewDidDisappear:(BOOL)animated{
if([_webView isLoading]) {
[_webView stopLoading];
}
[_webView setDelegate:nil];
}
due to above code my crashing has been resolved

CALayer delegation causes zombie crash -- why?

I am new to Core Animation and having trouble implementing a CALayer object with the drawLayer method in a delegate.
I have narrowed the problem down to a very simple test. I have a main viewController named LBViewController that pushes a secondary viewController called Level2ViewController. In the level 2 controller, in viewWillAppear:, I create a CALayer object with it's delegate=self (i.e. the level 2 controller). Whether or not I actually implement the drawLayer:inContext: method I have the same problem -- when I return to the main viewController I get a zombie crash. In the profiler it appears that the object in trouble is the level 2 viewController object -- which is being dealloc'ed after it's popped.
I've tried using a subclassed CALayer object instead of the delegate and it works fine. If I comment out the delegate assignment it also runs fine. I would like to understand why delegation is causing this problem. Any advice is greatly appreciated.
Here's my code ---
Level2ViewController
#implementation Level2ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CALayer *box1 = [[CALayer alloc] init];
box1.delegate = self; // problem disappears if I comment out this assignment
box1.backgroundColor = [UIColor redColor].CGColor;
box1.frame = CGRectMake(10,10,200,300);
[self.view.layer addSublayer:box1];
[box1 setNeedsDisplay];
}
// makes no difference whether or not this method is defined as long
// as box1.delegate == self
- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext
{
CGContextSaveGState(theContext);
CGContextSetStrokeColorWithColor(theContext, [UIColor blackColor].CGColor);
CGContextSetLineWidth(theContext, 3);
CGContextAddRect(theContext, CGRectMake(5, 5, 40, 40));
CGContextStrokePath(theContext);
CGContextRestoreGState(theContext);
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
The method in LBViewController (the main controller) that pushes the level 2 view controller
- (IBAction)testAction:(id)sender {
Level2ViewController *controller = [[Level2ViewController alloc]
initWithNibName:#"Level2ViewController" bundle:nil];
controller.title = #"Level2";
// this push statement is where the profiler tells me the messaged zombie has been malloc'ed
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
You may want to set the layer's delegate to nil before the delegate object is released. So in your Leve2ViewController do this:
-(void)viewWillDisappear:(BOOL)animated
{
if (box1) {
box1.delegate = nil;
}
box1 = nil;
}
Obviously this requires, that box1 is turned into a field (so it is accessible in viewWillDisappear:)
Since you create box1in viewWillAppear: the code above uses viewWillDisappear:. Recently, when I ran into a similar problem, I had a separate delegate object in which I used init and dealloc.
Note: You call [super viewDidAppear:animated]; in viewWillAppear. Looks like a typo or copy/paste glitch :-)

Resources