I am creating a custom modal layer. the idea is a user see’s a city, clicks on said city and accepts or rejects the location.
I use NSMethodSignature to handle the callback so I know whether the user clicked Tick (Accept) or Cross (Reject) buttons in the modal layer.
However, for some reason the app crashes once it invokes the callback and gives me a bad access error when it returns from the modal.
0x000d584e <+0174> mov %eax,0x4(%esp)
0x000d5852 <+0178> call 0xd6006 <dyld_stub_objc_msgSend>
0x000d5857 <+0183> mov -0x8(%ebp),%eax Thread 1: Program received signal: EXC_BAD_ACCESS
I do not understand why this is happening as the city object is defined in the class.
For example, my .h file has:
@interface MapMenuLayer : CCLayer
{
CCArray *listOfCities;
City *city;
}
@property (nonatomic, retain) CCArray *listOfCities;
@property (nonatomic, retain) City *city;
And my .m file has:
@synthesize listOfCities, city;
Later on I define the display each city on the page as clickable CCMenu items. When the user clicks on a city it calls:
-(void) onMenuItem:(id)sender
{
NSLog(@"sender = %d", [sender tag]);
self.city = [self.listOfCities objectAtIndex:[sender tag]];
NSString *cityName = self.city.name;
NSLog(@"cityName = %@", cityName);
// Launch the modal layer
CityModalLayer *cityModalLayer = [[[CityModalLayer alloc] initWithCity:self.city target:self selector:@selector(onDialogButton:)] autorelease];
[cityModalLayer show:self];
}
// This is called when the modal is closed or actioned upon
- (void) onDialogButton:(NSInteger)buttonIndex
{
NSLog(@"onDialogButton:buttonIndex: %d", buttonIndex);
NSString *cityName = self.city.name;
NSLog(@"You selected: cityName = %@", cityName);
}
The bad access error occurs when the application flow returns from the modal layer and launches the onDialogButton method is actioned.
It outputs the log fine, but it crashes when it hits the city object. I have no idea why this is happening, it should not be null or causing any formal error.
Okay, so the modal layer is a bit complex, but I cut it down for the purposes of this question:
-(id) initWithCity:(City *)cityObj target:(id)target selector:(SEL)selector
{
if((self=[super init]))
{
[self initWithColor:ccc4(0, 0, 0, 255)];
[self setOpacity:80];
[self setIsTouchEnabled:YES];
self.city = cityObj;
// Setup the signature class
NSMethodSignature *sig = [[target class] instanceMethodSignatureForSelector:selector];
callback = [NSInvocation invocationWithMethodSignature:sig];
[callback setTarget:target];
[callback setSelector:selector];
[callback retain];
// -----
// MENU
// The frames are not in this code, but they do exist
// Add modal menu
// Modal Menu (Tick/Cross)
CCMenu *modalMenu = [CCMenu menuWithItems:nil];
CCSprite *closeButtonOff = [CCSprite spriteWithSpriteFrameName:@"closeButton_Off.png"];
CCSprite *closeButtonOn = [CCSprite spriteWithSpriteFrameName:@"closeButton_On.png"];
CCSprite *tickButtonOff = [CCSprite spriteWithSpriteFrameName:@"tickButton_Off.png"];
CCSprite *tickButtonOn = [CCSprite spriteWithSpriteFrameName:@"tickButton_On.png"];
// Tick button
CCMenuItemSprite *tickBtnItem = [CCMenuItemSprite itemFromNormalSprite:tickButtonOff selectedSprite:tickButtonOn target:self selector:@selector(onButtonPressed:)];
[tickBtnItem setTag:1];
[tickBtnItem setPosition:CGPointMake(130, -95)];
[tickBtnItem setIsEnabled:YES];
// Close button
CCMenuItemSprite *closeBtnItem = [CCMenuItemSprite itemFromNormalSprite:closeButtonOff selectedSprite:closeButtonOn target:self selector:@selector(onButtonPressed:)];
[closeBtnItem setTag:0];
[closeBtnItem setPosition:CGPointMake(-130, -95)];
[closeBtnItem setIsEnabled:YES];
// Add stuff to modal
[modalMenu addChild:closeBtnItem];
[modalMenu addChild:tickBtnItem];
// Add menu to the modalFrame
[modalFrame addChild:modalMenu z:2];
// --
// Add modalFrame to modalLayer
[self addChild:modalFrame];
} // end if
return self;
}
// This invokes the action
-(void) onButtonPressed:(id) sender
{
NSInteger buttonIndex = [sender tag];
NSLog(@"onButtonPressed: %d", buttonIndex);
[callback setArgument:&buttonIndex atIndex:1];
[callback invoke];
[self removeFromParentAndCleanup:YES];
}
-(void) dealloc
{
[callback release];
[super dealloc];
}
I have tracked the issue down to when the callback is invoked, however I do not understand why it is crashing, or giving me the error. It should still have the city object in memory?
What could be causing this?
I’ve done it now. It was the autorelease. Which I have removed
In order to prevent clicks under the modal, or someone pressing on a button lots of times really quickly I put a
CoverLayerinside my ModalLayer.m fileThen I can init this using my
ModalLayerimplementation and then dismiss the modal with a small animation, ie,Anyway, I believe I resolved the problem as it seemed to relate to autorelease