2

カスタムモーダルレイヤーを作成しています。アイデアは、ユーザーが都市を見て、その都市をクリックし、その場所を受け入れるか拒否するというものです。

NSMethodSignatureはコールバックを処理するために使用していたので、ユーザーがモーダル レイヤーのTick(Accept) ボタンまたはCross(Reject) ボタンをクリックしたかどうかがわかります。

ただし、何らかの理由でコールバックを呼び出すとアプリがクラッシュし、モーダルから戻るときに不正なアクセス エラーが発生します。

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

クラスで都市オブジェクトが定義されているため、なぜこれが起こっているのかわかりません。

たとえば、私の .h ファイルには次のものがあります。

@interface MapMenuLayer : CCLayer
{
    CCArray *listOfCities;
    City *city;
}

@property (nonatomic, retain) CCArray *listOfCities;
@property (nonatomic, retain) City *city;

そして、私の .m ファイルには次のものがあります。

@synthesize listOfCities, city;

後で、ページ上の各都市の表示をクリック可能なCCMenuアイテムとして定義します。ユーザーが都市をクリックすると、次のように呼び出されます。

-(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);

}

アプリケーション フローがモーダル レイヤーから戻り、onDialogButtonメソッドが実行されると、不正なアクセス エラーが発生します。

ログは問題なく出力されますが、都市オブジェクトに当たるとクラッシュします。なぜこれが起こっているのかわかりません.nullにしたり、正式なエラーを引き起こしたりするべきではありません.

さて、モーダルレイヤーは少し複雑ですが、この質問のために切り詰めました:

-(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];
}

コールバックが呼び出されるまで問題を追跡しましたが、クラッシュしたり、エラーが発生したりする理由がわかりません。それはまだ都市オブジェクトをメモリに持っているべきですか?

何が原因でしょうか?

4

1 に答える 1