2013年3月4日月曜日

【cocos2d】UIViewControllerを使用していて「コントローラ名 copyWithZone:]: unrecognized selector sent to instance アドレス」というエラーが出た

cocos2dでUIViewControllerを使用していると以下のエラーが出ました。

-[UIViewController copyWithZone:]: unrecognized selector sent to instance アドレス

やろうとしていたこと

UIViewControllerを継承したHogeViewControllerのインスタンスを次のシーンに「copy」して渡そうとした。

原因

原因としては、copy実行の際にcopyWithZone:メソッドが実行されているのですが、そのcopyWithZone:メソッドがないために起こったエラーのようです。以下のログ参照。このログも一緒に出力されました。

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[HogeViewController copyWithZone:]: unrecognized selector sent to instance 0x57a2d0'

NSStringなど(他調べてません...汗)はcopyWithZone:メソッドがはじめから実装されているのですが、実装されていないクラスもあります。UIViewControllerが恐らくそれでしょう。

対処

copyWithZone:メソッドを実装することで回避できます。

今回はUIViewControllerは外部クラスとして扱いました。
さらに、copyの実装にはプロパティを使用しました。

UIViewController側

呼び出されるUIViewControllerの定義です。

HogeViewController.h

#import <UIKit/UIKit.h>

@interface HogeViewController : UIViewController <NSCopying>
{}
@end

HogeViewController.m

#import "HogeViewController.h"

@implementation HogeViewController

/*
initとかいろいろ
*/

//こいつです
- (id)copyWithZone:(NSZone *)zone {
    id copiedObject = [[[self class] allocWithZone:zone] init];
    return copiedObject;
}
copyWithZone:メソッドを使用するため、NSCopyingプロトコルを実装しています。

呼び出す側

次は上のUIViewControllerを呼び出すクラスの定義です。

FugaLayer.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "cocos2d.h"

@class HogeViewController;

@interface FugaLayer : CCLayer
{
    HogeViewController *_hogeViewController;
}

@property(nonatomic, copy) HogeViewController *hogeViewController;  //プロパティとしてcopyを指定

@end

FugaLayer.m

#import "FugaLayer.h"
#import "HogeViewController.h"

@implementation FugaLayer

@synthesize hogeViewController=_hogeViewController;

-(id)init
{
    self = [super init];

    if (self != nil) {
        self.hogeViewController=[[HogeViewController alloc]init];
    }

    return self;

}

-(void)dealloc
{
    [self.hogeViewController release];
    self.hogeViewController=nil;

    [super dealloc];
}

//このメソッドを遷移させたいタイミングで呼ぶ
-(void)someMet
{
    CCScene *scene = [NextScene scene];
    NextSceneMainLayer *layer = [scene.children objectAtIndex:0];

    layer.hogeViewController = self.hogeViewController;  //ここで渡してる

    CCLOG(@"%p", self.hogeViewController);  //デバッグ.NextScene側でも実行して確認してみてください

    [[CCDirector sharedDirector] pushScene:
        [CCTransitionFlipX transitionWithDuration:0.4f scene:scene]];
}

@end

おわり

とりあえずこの方法でエラーは消えました。デバッグでも遷移元、遷移先で同じアドレスが出力されました。ですがメモリの解放のところがイマイチよく分かっていない状況です。

こちらの「自作クラスをプロパティにする - iOSアプリ開発記」の記事のような書き方も気になるところ。

参考記事

自作クラスをプロパティにする - iOSアプリ開発記
NSCopyingプロトコル - iPhoneメモ
UINavigationアプリのデータ渡し - 臧(ゾウ)ファクトリー
Objective-CでNSStringプロパティ実装 - TORQUES LABS

0 件のコメント:

コメントを投稿