[C++][cocos2d-x] Assert failed: reference count should greater than 0 や Thread 1:EXC_BAD_ACCESS のエラー
cocos2d-x でアプリ開発をしているとき、タイトルのようなエラーになってはまったので、その解決方法をメモ。
シーンからシーンへ切り替える際、都度 replaceScene を書きたくなかったので、
シーン切り替え用の関数を下記のように作成。
ヘッダーファイルの宣言 (BaseLayer.h)
class BaseLayer : public cocos2d::Layer { public: void gotoNextScene(float time); void setNextScene(cocos2d::Scene *scene); private: cocos2d::Scene *next_scene; };
cpp ファイルの定義 (BaseLayer.cpp)
void BaseLayer::gotoNextScene(float time) { cocos2d::TransitionCrossFade *crossFade = cocos2d::TransitionCrossFade::create(0.5f, this->next_scene); cocos2d::Director::getInstance()->replaceScene(crossFade); } void BaseLayer::setNextScene(cocos2d::Scene *next_scene) { this->next_scene = next_scene; }
呼び出しもとの cpp ファイル (SplashScene.cpp)
bool SplashScene::init() { if ( !Layer::init() ) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); Point origin = Director::getInstance()->getVisibleOrigin(); // スプラッシュ画面の生成 auto label = LabelTTF::create("splash", "Arial", 80); label->setPosition(Point(origin.x + visibleSize.width/2, origin.y + visibleSize.height - label->getContentSize().height)); this->addChild(label, 1); // ↓ここ↓ this->setNextScene(StartScene::createScene()); this->scheduleOnce(schedule_selector(StartScene::gotoNextScene), 3); return true; }
こんな感じで実行したら、ビルドは通るのに実行するとエラーになってしまった。
しかも、実行するたびにたまにエラー内容が変化するという悲しい現象。具体的には、
cocos2d/cocos/base/CCRef.cpp の
void Ref::retain() { CCASSERT(_referenceCount > 0, "reference count should greater than 0"); // ←ここ ++_referenceCount; }
で引っかかって
cocos2d: Assert failed: reference count should greater than 0
Assertion failed: (_referenceCount > 0), function retain, file
のエラーが出たり・・・・
cocos2d/cocos/2d/CCTransition.cpp の
// custom onEnter void TransitionScene::onEnter() { Scene::onEnter(); // disable events while transitions _eventDispatcher->setEnabled(false); // outScene should not receive the onEnter callback // only the onExitTransitionDidStart _outScene->onExitTransitionDidStart(); _inScene->onEnter(); // ←ここ }
でひっかかって
Thread 1:EXC_BAD_ACCESS (code=2, address=0xb0000160)
のようなエラーが出たり・・・。
ぐぐって調べていくと、どうやらメモリ管理がうまくできてないことが原因ということはあたりがついた。
最初のエラーに関しても、リファレンスカウントに関するエラーなので、おそらくすでにリリース済みのメモリ(もしくははじめから保持に失敗しているメモリ)に対して、メモリを取得しようとしている、ということのはず。
そこで、明示的にリファレンスカウントを retain(あげる)、release(さげる) してあげることで解決した。
具体的には、SplashScene.cpp を下記を追記。
void BaseLayer::gotoNextScene(float time) { cocos2d::TransitionCrossFade *crossFade = cocos2d::TransitionCrossFade::create(0.5f, this->next_scene); cocos2d::Director::getInstance()->replaceScene(crossFade); this->next_scene->release(); // ここで release } void BaseLayer::setNextScene(cocos2d::Scene *next_scene) { this->next_scene = next_scene; this->next_scene->retain(); // ここで retain }
ただし、
iOS 開発で、EXC_BAD_ACCESS とさよならするための6つのルール | Zero4Racer PRO Developer's Blog
を見ると正しい対応ではない予感はすごくしている。
とりあえずいまはこのばんそこ対応で我慢して、もっと勉強して理解が深まったらちゃんと解決するとしよう。。
有識者の方いらっしゃったらコメント欄に残していただけるとうれしいです。
おもに参考にしたページ
- リファレンスカウントの概念について
- iOS のメモリ管理について
iOS 開発で、EXC_BAD_ACCESS とさよならするための6つのルール | Zero4Racer PRO Developer's Blog
[cocos2dx][Xcode][C++] Undefined symbols for architecture i386 とか linker command failed with exit code 1 でエラー
cocos2dx で、タップを検知したいと思い、ヘッダーファイルに下記の記述を行いました。
// タッチ開始時 virtual bool onTouchBegan(cocos2d::Touch* pTouch, cocos2d::Event* pEvent);
しかしビルドすると
というエラー。。。
エラー内容でぐぐってみると、
プログラミング雑記: Undefined symbols for architecture i386
Cocos2dxで"Undefined symbols for architecture i386:"が発生した場合の対処法 - たけぞうBLOG
「clang: error: linker command failed with exit code 1」というエラーへの対処 - Action Script書きの日記
Cocoaの日々: ld: library not found for -lz.1.2.3 と出たら
Xcode4.4にアップデートしたら「linker command failed with exit code 1」エラー?! | 個人で作るiPhoneアプリ制作体験記
とかとか、いろいろ見つかったけどぜんぜん解決せず。
結局、ヘッダーファイルに宣言をするだけではだめで、cpp ファイルにて定義まで行わないとエラーになるらしいです。下のように記述し、無事解決しました。
bool TouchTest::onTouchBegan(Touch* pTouch, Event* pEvent) { return true; }
C++ の関数のプロトタイプ宣言というものは、それを記述しただけではエラーになるっていうことなのかな??
初心者丸出し。ちくしょう。。(T-T)
[Xcode][Cocos2d-x] Resouces ディレクトリ以下の画像が読み込まれない
Xcode で cocos2d-x を使い、画像を表示させてみようとしました。
PROJECTNAME/Resources 以下に finder 経由で画像を配置して
auto sprite = Sprite::create("tamulapin.png"); sprite->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
みたいな感じで記述してビルドすると、
cocos2d: cocos2d: fullPathForFilename: No file found at tamulapin.png. Possible missing file.
と怒られてエラーになりました。
Xcode のツリー構造で確認してみると、たしかに確認できません。
ツリー構造の「Resources」を右クリックし、「Add Files to PROJECTNAME」をクリックし、必要なファイルを add して解決。
それまではフルパスで記述してました。。
おわり。
test
テストでスーパー pre 記法を試してみる
class test def index pp "hoge" end end
おしまい