I'm working on my first app and have a few questions on memory management.
First Question:
I'm working on an intro scene that looks like this
#import "Intro_Scene.h"
#import "Main_Menu.h"
#import "Label.h"
#implementation Intro_Scene
#synthesize logo,label;
-(id) init
{
self = [super init];
if(self != nil)
{
//Load logo image and set position
logo = [Sprite spriteWithFile:#"AVlogo_1.png"];
logo.position = ccp(-50, 0);
logo.scale = 1.8f;
[self addChild: logo];
//Creates 3 actions for the logo sprite
id action0 = [MoveTo actionWithDuration:0 position:ccp(160,270)];
id action1 = [FadeIn actionWithDuration:3];
id action2 = [FadeOut actionWithDuration:3];
//Logo runs the actions
[logo runAction: [Sequence actions:action0,action1, action2, nil]];
//Schedules the changeScene method to switch scenes to main menu within 6 seconds of loading.
[self schedule: #selector(changeScene) interval:6.0f];
//Creates a label and positions it, Alternative Visuals
label = [Label labelWithString:#"Alternative Visuals" fontName:#"Verdana" fontSize:22];
label.position = ccp(160, 120);
[self addChild:label];
}
return self;
}
//Method called after intro has run its actions, after 6 seconds it switches scenes.
-(void)changeScene
{
[self removeChild:logo cleanup:YES];
[self removeChild:label cleanup:YES];
Main_Menu *mainMenu = [Main_Menu node];
[[Director sharedDirector] replaceScene: mainMenu];
}
-(void)dealloc
{
[[TextureMgr sharedTextureMgr] removeUnusedTextures];
[label release];
[logo release];
[super dealloc];
}
#end
Have I released everything correctly, and avoided leaks? I ran it in instruments multiple times and it found no leaks and used about 2mb of memory, is that to much or the amount to be expected? Also does the dealloc method get called when the scene is replaced?
Question 2:
My main menu is set up like this
#import "Main_Menu.h"
#import "Sprite.h"
#import "cocos2d.h"
#implementation Main_Menu
#synthesize background, controlLayer;
-(id) init
{
self = [super init];
if(self != nil)
{
//Create the default background for main menu not including directional pad and highlight box
background = [Sprite spriteWithFile:#"Main_Menu_bg.png"];
background.position = ccp(160,240);
[self addChild:background];
//Adds the control later class to the main menu, control layer class displays and controls the directional pad and selector.
ControlLayer *layer = [[ControlLayer alloc] init];
self.controlLayer = layer;
[layer release];
[self addChild: controlLayer];
}
return self;
}
-(void) dealloc
{
[seld removeChild:background cleanup:YES];
[[TextureMgr sharedTextureMgr] removeUnusedTextures];
[background release];
[controlLayer release];
[super dealloc];
}
#end
Once again am I doing everything correctly? The layer ControlLayer I'm adding to this scene contains a directional pad sprite that the user uses to navigate the menu. In instruments It also confirms that their is no memory leaks, and it uses 4.79 mb of memory. Once again is that a reasonable amount? I will most likely switch to using AtlasSprite and AtlastSpriteManager to conserve memory.
I'm new to cocos2d, so if you see I'm doing anything wrong point it out! I'd rather fix bad habits in the early stages. And if you have any future tips for memory management please share.
Don't release logo, label, or background. You didn't alloc/copy/new/retain them, so you don't own them and must not release them.
I assume the controllerLayer property has the retain attribute? If not, you probably mean to do so.
In general I'd suggest two things going forward.
Read and understand the Cocoa Memory Management Fundamentals
Run the Clang analyzer on your code. This is available in Xcode 3.2 via Build->Build and Analyze. It will help detect these memory issues.
Also check out this SO question.
Related
I'm facing a performance issue whenever the code reach "replaceScene". It happens only in the Play Scene. So after the game is over, I display a score, and then, it's time for CCDirector to do replaceScene in order to go back to the main menu.
After waiting for around 20 seconds then it finally display the main menu. But somehow this is not right, player will feel that the game suddenly hang. Then I tried to put some animation like preloader, it happens the same, the preloader picture did animate a while then suddenly stop, and I think due to the same issue triggered by replaceScene, although still it'll display the main menu scene. Care to give some tips how to speed up the releasing of all the objects which no longer needed.
Hoping to get a solution from experts here. Thanks.
Here is my code :
............
//button at the score pop up sprite
CCMenuItem *btContinue = [CCMenuItemImage itemFromNormalImage:BTCONTINUE
selectedImage:BTCONTINUE_ON
target:self
selector:#selector(goLoader)];
btContinue.anchorPoint = ccp(0,0);
btContinue.position = ccp(340, 40);
CCMenu *menu = [CCMenu menuWithItems:btContinue, nil];
menu.position = CGPointZero;
[self addChild:menu z:ZPOPUP_CONTENT];
//prepare the loader, but set visible to NO first
CCSprite *loaderBg = [CCSprite spriteWithFile:LOADER_FINISH];
loaderBg.anchorPoint = ccp(0,0);
loaderBg.position = ccp(0,0);
loaderBg.visible = NO;
[self addChild:loaderBg z:ZLOADER_BG tag:TAG_LOADER_BG];
NSLog(#"prepare loader finish");
//animate loader
CCSprite *loaderPic = [[CCSprite alloc] initWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache]
spriteFrameByName:LOADER]];
loaderPic.anchorPoint = ccp(0.5,0.5);
loaderPic.position = ccp(200,35);
loaderPic.visible = NO;
[self addChild:loaderPic z:ZLOADER_PIC tag:TAG_LOADER_PIC];
[loaderPic runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:0.05f angle:10.0f]]];
}
-(void)goLoader {
NSLog(#"goMainMenuScene");
CCSprite *tmpBg = (CCSprite *) [self getChildByTag:TAG_LOADER_BG];
if (tmpBg != nil)
tmpBg.visible = YES;
CCSprite *tmpPic = (CCSprite *) [self getChildByTag:TAG_LOADER_PIC];
if (tmpPic != nil)
tmpPic.visible = YES;
double time = 2.0;
id delay = [CCDelayTime actionWithDuration: time];
id proceed = [CCCallFunc actionWithTarget:self selector:#selector(goMainMenuScene)];
id seq = [CCSequence actions: delay, proceed, nil];
[self runAction:seq];
}
-(void)goMainMenuScene {
[[GameManager sharedGameManager] runSceneWithID:SCENE_MAIN_MENU];
}
Your problem is most likely the new scene, and whatever happens in the new scene's and its child node's init methods. Loading resource files can take quite a while. If you defer doing this into onEnter you might see better results. But 20 seconds, that's a lot. Check what you're doing that takes THIS long. I bet it's loading a gross amount of resources, or loading them in an extremely inefficient way. JPG files are known to load very slowly, if you use JPG convert them to PNG.
I have been working on an app for a couple of months now, but have finally run into an issue that I can't solve myself, and can't find anything on the internet to help.
I am using several normal UIAlertViews, in my app. Some have 2 buttons, some have 3 buttons, and a couple have 2 buttons and a text field. However all have the same issue. When you call [someAlertView show]; the alert view appears as normal, but then suddenly its graphics context seems to get corrupted as you can see from the screenshot.
This happens on both iPhone and iPad simulators (both 5.0 and 5.1), and happens on an iPad and iPhone4S device as well.
The image showing through is whatever happens to be behind the alertView.
The Alert still works, I can click the buttons, type in the text field, then when it dismisses the delegate methods are called correctly and everything goes back to normal. When the alertView appears again, the same thing happens.
The view behind the alert is a custom UIScrollView subclass with a content size of approximately 4000 pixels by 1000 with a UIImage as the background. The png file is mostly transparent, so is only about 80kB in memory size, and the phone is having no issues rendering it - the scroll view is still fully responsive and not slow.
It also has a CADisplayLink timer attached to it as part of the subclass. I have tried disabling this just before the alertView is shown, but it makes no difference so I am doubtful that is the issue.
This app is a partial rewrite of one I made for a university project, and that one could display UIAlertViews over the top of a scrollView of the same size and subclass without issue. The difference between this app and that one is that in my old app, I had subclassed UIAlertView to add extra things such as a pickerView, however I decided that I didn't like the way it looked so moved everything out of the alert and am just sticking with a standard UIAlertView.
This is how the alertView in the screenshot is called:
- (IBAction)loadSimulation:(id)sender {
importAlert = [[UIAlertView alloc] initWithTitle:#"Load Simulation" message:#"Enter Filename:" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Load", nil];
[importAlert setAlertViewStyle:UIAlertViewStylePlainTextInput];
[importAlert showPausingSimulation:self.simulationView]; //Calling [importAlert show]; makes no difference.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
[self hideOrganiser]; //Not an issue as the problem occurs on iPad as well.
}
}
With this being the categorised AlertView to add the ability to stop the scrollViews CADisplay link.
#interface UIAlertView(pauseDisplayLink)
- (void)showPausingSimulation:(UILogicSimulatorView*)simulationView;
#end
#implementation UIAlertView(pauseDisplayLink)
- (void)showPausingSimulation:(UILogicSimulatorView *)simulationView {
[simulationView stopRunning];
[simulationView removeDisplayLink]; //displayLink needs to be removed from the run loop, otherwise it will keep going in the background and get corrupted.
[self show];
}
I get no memory warnings when this happens, so I am doubtful it is due to lack of resources.
Has anyone come across an issue like this before? If you need further information I can try to provide it, but I am limited in what code I can post. Any help would be appreciated, I've been trying to solve this for two weeks and can't figure it out.
Edit:
It appears that it is not the AlertView at all (or rather it is not just the alertView), as the problem goes away when I remove the scroll view behind it, so there must be some issue between the two. This is the code for my UIScrollView subclass:
.h file:
#import
#import
#class ECSimulatorController;
#interface UILogicSimulatorView : UIScrollView {
CADisplayLink *displayLink;
NSInteger _updateRate;
ECSimulatorController* _hostName;
}
#property (nonatomic) NSInteger updateRate;
#property (nonatomic, strong) ECSimulatorController* hostName;
- (void) removeDisplayLink;
- (void) reAddDisplayLink;
- (void) displayUpdated:(CADisplayLink*)timer;
- (void) startRunning;
- (void) stopRunning;
- (void) refreshRate:(NSInteger)rate;
- (void) setHost:(id)host;
- (void)setMinimumNumberOfTouches:(NSInteger)touches;
- (void)setMaximumNumberOfTouches:(NSInteger)touches;
#end
.m file:
#import "UILogicSimulatorView.h"
#import "ECSimulatorController.h"
#import <QuartzCore/QuartzCore.h>
#implementation UILogicSimulatorView
#synthesize updateRate = _updateRate;
#synthesize hostName = _hostName;
- (void)reAddDisplayLink {
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; //allows the display link to be re-added to the run loop after having been removed.
}
- (void)removeDisplayLink {
[displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; //allows the display link to be removed from the Run loop without deleting it. Removing it is essential to prevent corruption between the games and the simulator as both use CADisplay link, and only one can be in the run loop at a given moment.
}
- (void)startRunning {
[self refreshRate:self.updateRate];
[displayLink setPaused:NO];
}
- (void)refreshRate:(NSInteger)rate {
if (rate > 59) {
rate = 59; //prevent the rate from being set too an undefined value.
}
NSInteger frameInterval = 60 - rate; //rate is the number of frames to skip. There are 60FPS, so this converts to frame interval.
[displayLink setFrameInterval:frameInterval];
}
- (void)stopRunning {
[displayLink setPaused:YES];
}
- (void)displayUpdated:(CADisplayLink*)timer {
//call the function that the snakeController host needs to update
[self.hostName updateStates];
}
- (void)setHost:(ECSimulatorController*)host;
{
self.hostName = host; //Host allows the CADisplay link to call a selector in the object which created this one.
}
- (id)initWithFrame:(CGRect)frame
{
//Locates the UIScrollView's gesture recogniser
if(self = [super initWithFrame:frame])
{
[self setMinimumNumberOfTouches:2];
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(displayUpdated:)]; //CADisplayLink will update the logic gate states.
self.updateRate = 1;
[displayLink setPaused:YES];
}
return self;
}
- (void)setMinimumNumberOfTouches:(NSInteger)touches{
for (UIGestureRecognizer *gestureRecognizer in [self gestureRecognizers])
{
if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
{
//Changes the minimum number of touches to 'touches'. This allows the UIPanGestureRecogniser in the object which created this one to work with one finger.
[(UIPanGestureRecognizer*)gestureRecognizer setMinimumNumberOfTouches:touches];
}
}
}
- (void)setMaximumNumberOfTouches:(NSInteger)touches{
for (UIGestureRecognizer *gestureRecognizer in [self gestureRecognizers])
{
if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
{
//Changes the maximum number of touches to 'touches'. This allows the UIPanGestureRecogniser in the object which created this one to work with one finger.
[(UIPanGestureRecognizer*)gestureRecognizer setMaximumNumberOfTouches:touches];
}
}
}
#end
Well, I have managed to come up a solution to this. Really it is probably just masking the issue rather than finding the route cause, but at this point I will take it.
First some code:
#interface UIView (ViewCapture)
- (UIImage*)captureView;
- (UIImage*)captureViewInRect:(CGRect)rect;
#end
#implementation UIView (ViewCapture)
- (UIImage*)captureView {
return [self captureViewInRect:self.frame];
}
- (UIImage*)captureViewInRect:(CGRect)rect
{
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenShot;
}
#end
- (void)showPausingSimulation:(UILogicSimulatorView *)simulationView {
[simulationView stopRunning];
UIView* superView = simulationView.superview;
CGPoint oldOffset = simulationView.contentOffset;
for (UIView* subview in simulationView.subviews) {
//offset subviews so they appear when content offset is (0,0)
CGRect frame = subview.frame;
frame.origin.x -= oldOffset.x;
frame.origin.y -= oldOffset.y;
subview.frame = frame;
}
simulationView.contentOffset = CGPointZero; //set the offset to (0,0)
UIImage* image = [simulationView captureView]; //Capture the frame of the scrollview
simulationView.contentOffset = oldOffset; //restore the old offset
for (UIView* subview in simulationView.subviews) {
//Restore the original positions of the subviews
CGRect frame = subview.frame;
frame.origin.x += oldOffset.x;
frame.origin.y += oldOffset.y;
subview.frame = frame;
}
[simulationView setHidden:YES];
UIImageView* imageView = [[UIImageView alloc] initWithFrame:simulationView.frame];
[imageView setImage:image];
[imageView setTag:999];
[superView addSubview:imageView];
[imageView setHidden:NO];
superView = nil;
imageView = nil;
image = nil;
[self show];
}
- (void)dismissUnpausingSimulation:(UILogicSimulatorView *)simulationView {
UIView* superView = simulationView.superview;
UIImageView* imageView = (UIImageView*)[superView viewWithTag:999];
[imageView removeFromSuperview];
imageView = nil;
superView = nil;
[simulationView setHidden:NO];
[simulationView startRunning];
}
Then modifying the dismiss delegate method in my class to have this line:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
[alertView dismissUnpausingSimulation:self.simulationView];
...
When the alert view is called, but before it is shown, I need to hide the simulator to prevent it corrupting the alert. However just hiding it is ugly as then all is visible behind is a empty view.
To fix this, I first make a UIImage from the simulator views graphics context. I then create a UIImageView with the same frame as the simulator and set the UIImage as its image.
I then hide the simulator view (curing the alert issue), and add my new UIImageView to the simulators superview. I also set the tag of the image view so I can find it later.
When the alert dismisses, the image view is then recovered based on its tag, and removed from its superview. The simulator is then unhidden.
The result is that the rendering issue is gone.
I know its too late for an answer to this question. Lately I had experianced this very same issue.
My Case:
Added couple of custom UIViews with background images and some controlls to the scroll view with shadow effect. I had also set the shadowOffset.
The Solution:
After some step by step analysis, I found out that setting the setShadowOpacity caused The rendering problem for me. When i commented that line of code, it cured the UIAlertView back to normal appearance.
More:
To make sure, I created a new project mimicing the original ui with shadowOpacity. But it didnt caused the rendering problem as i expected. So I am not sure about the root cause. For me it was setShadowOpacity.
fresh to objC and cocos2d :)
i'm following "learn cocos2d game development with iOS5", in chapter4, there is a "DoodleDrop" game.
define some variable in GameScene.h like this
#interface GameScene : CCLayer
{
CCSprite *player;
CGPoint playerVelocity;
CCArray *spiders;
CGSize screenSize;
int dropedSpidersCount;
float duration;
}
+ (CCScene *)scene;
#end
in GameScene.m the init method looks like this
- (id)init
{
if (self = [super init]) {
duration = 4.0;
[self createPlayer];
[self createSpiders]; // spiders were inited here.
[self resetSpiders];
[self schedule:#selector(chooseSpider:) interval:0.7];
}
return self;
}
while in chooseSpider, i cannot access spiders, xcode broke
in other methods, spiders or duration just behave normally, why does this happens?
gist code added
https://gist.github.com/2940466
After inspecting your code, I suggest you to try this fix:
- (void)createSpiders
{
CCSprite *tempSpider = [CCSprite spriteWithFile:#"spider.png"];
CGSize spiderSize = [tempSpider texture].contentSize;
int spiderCount = screenSize.width / spiderSize.width;
spiders = [[CCArray arrayWithCapacity:spiderCount] retain];
for (int i = 0; i < spiderCount; i++) {
CCSprite *spider = [CCSprite spriteWithFile:#"spider.png"];
[self addChild:spider];
[spiders addObject:spider];
}
}
where the only difference is in the line:
spiders = [[CCArray arrayWithCapacity:spiderCount] retain];
Indeed, if you do not retain you spiders object, it will be autoreleased at the next run loop iteration.
OLD ANSWER:
Without seeing more code it is not possible to say exactly what is happening, but it seems that in the interval between creating the spiders and the actual execution of chooseSpiders, your spiders array gets deallocated.
As a quick try, I would suggest adding:
[spiders retain];
before calling
[self schedule:#selector(chooseSpider:) interval:0.7];
and see wether the crash keeps happening.
if you provide more code, it could be possible to help you further.
I am writing a pause menu using a CCLayer. I need the layer to swallow touches so that you cannot press the layer below, however I also need to be able to use the buttons on the pause layer itself.
I can get the layer to swallow touches, but the menu won't work either.
Here is my code:
pauseLayer.m
#import "PauseLayer.h"
#implementation PauseLayer
#synthesize delegate;
+ (id) layerWithColor:(ccColor4B)color delegate:(id)_delegate
{
return [[[self alloc] initWithColor:color delegate:_delegate] autorelease];
}
- (id) initWithColor:(ccColor4B)c delegate:(id)_delegate {
self = [super initWithColor:c];
if (self != nil) {
NSLog(#"Init");
self.isTouchEnabled = YES;
CGSize wins = [[CCDirector sharedDirector] winSize];
delegate = _delegate;
[self pauseDelegate];
CCSprite * background = [CCSprite spriteWithFile:#"pause_background.png"];
[self addChild:background];
CCMenuItemImage *resume = [CCMenuItemImage itemFromNormalImage:#"back_normal.png"
selectedImage:#"back_clicked.png"
target:self
selector:#selector(doResume:)];
resume.tag = 10;
CCMenu * menu = [CCMenu menuWithItems:resume,nil];
[menu setPosition:ccp(0,0)];
[resume setPosition:ccp([background boundingBox].size.width/2,[background boundingBox].size.height/2)];
[background addChild:menu];
[background setPosition:ccp(wins.width/2,wins.height/2)];
}
return self;
}
-(void)pauseDelegate
{
NSLog(#"pause delegate");
if([delegate respondsToSelector:#selector(pauseLayerDidPause)])
[delegate pauseLayerDidPause];
}
-(void)doResume: (id)sender
{
if([delegate respondsToSelector:#selector(pauseLayerDidUnpause)])
[delegate pauseLayerDidUnpause];
[self.parent removeChild:self cleanup:YES];
}
- (void)onEnter {
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:YES];
[super onEnter];
}
- (void)onExit {
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
[super onExit];
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
-(void)dealloc
{
[super dealloc];
}
#end
why dont you just disable touches on the game layer?
like in the onEnter method disable the touches on the game layer..and onExit re enable them
something like
-onEnter{
gameLayer.isTouchEnabled=NO;
....
}
-onExit{
gameLater.isTouchEnabled=YES;
...
}
also you wont need CCTouchDispatcher
According to your code, the problem is the modal layer is swallowing events even if it's for the own children.
To solve this problem, you have to set the touch priority of the children even higher than the modal layer itself.
In other words, set the menu's touch priority value below modal layer's.
There are two solutions.
Simply override "CCMenu::registerWithTouchDispatcher()" method and set the priority higher from the beginning.
Change menu's touch priority using "setPriority" method of the touchDispatcher or "setHandlerPriority" of menu itself.
To achieve second solution, you have to pay attention to the timing.
"CCMenu::registerWithTouchDispatcher()" is called somewhere AFTER "onEnter" and "onEnterTransitionDidFinish".
So, use "scheduleOnce" or something like that.
Sample codes.
- (id) initWithColor:(ccColor4B)c delegate:(id)_delegate {
self = [super initWithColor:c];
if (self != nil) {
//your codes...... put CCMenu in instance
[self scheduleOnce:#selector(setMenuPriority:) delay:0];
}
return self;
}
- (void) setMenuPriority (ccTime)dt {
[[[CCDirector sharedDirector] touchDispatcher] setPriority:INT_MIN forDelegate:menu];
//priority "INT_MIN" because you set the layer's priority to "INT_MIN+1".
}
PS: My english is not so good, so if there are loose sentences, correction will be very pleased :)
The problem is, that the layer/node hierarchy is not considered when propagating touches.
The touches are handed from the touch handler with the smallest priority value to the ones with the highest.
The touches are not forwarded anymore, once one of the responders swallows the touch.
You can use an approach similar to CCMenu. CCMenu handles all touches and detects which CCMenuItemhas been selected, based on the position of these items.
If you implement this the same way, you let your PauseLayer handle and swallow all touches and use a seperate mechanism to determine which child element in your PauseLayer has been selected.
Example Implementation: CCMenu Subclass
I have implemented a solution in this repository:
https://github.com/Ben-G/MGWU-Widgets/tree/master/Projectfiles/Components/CCMenuBlocking
That component is a CCMenuSubclass that swallows all touches and does not forward them.
Example Implementation: CCNode
Here is a more general solution of a CCNode that swallows touches and only forwards them to its own children:
https://github.com/Ben-G/MGWU-Widgets/blob/master/Projectfiles/Components/Popup/PopUp.m
I have written a few games using Cocos2d iPhone. In all of my previous games I would change scenes when I setup a CCMenu and then leave that scene when I was finished. In my current project, I need the menu to exist in my current scene and be able to open and then close the menu many times. For some reason, I can't seem to understand, removeChild will not remove the menu. I have seen several examples online that show using removeChild, but it does not work for me. Below is my menu code, when the Start/CreateNewAccount button is pressed I want the current menu to be removed from the scene completely.
This is in my init method.
CCMenuItemImage *Start = [CCMenuItemImage itemFromNormalImage:#"MakeLemonade.png" selectedImage:#"MakeLemonadePressed.png"
target:self
selector:#selector(CreateNewAccount:)];
CCMenuItemImage *About = [CCMenuItemImage itemFromNormalImage:#"About.png" selectedImage:#"AboutPressed.png"
target:self
selector:#selector(About:)];
Start.position = ccp(-175, -90);
About.position = ccp(175, -90);
CCMenu *MainMenu = [CCMenu menuWithItems: Start, About, nil];
[Start runAction:[CCFadeIn actionWithDuration:1.0]];
[About runAction:[CCFadeIn actionWithDuration:1.0]];
[self addChild:MainMenu z:6];
}
return self;
}
-(void) BeginMenuLayer {
//this is not working
[self removeChild:MainMenu cleanup:YES];
}
In your init method you've declared MainMenu as a local variable. You're not setting it as a property, so you don't have a reference when you go to remove it later.
1) Make sure you have a property declared for it like this:
#property (nonatomic, retain) CCMenu *MainMenu;
2) Synthesize it at the top of your implementation:
#synthesize MainMenu;
3) Make sure you release it in your dealloc:
-(void)dealloc {
self.MainMenu = nil;
[super dealloc];
}
4) When you construct it, assign it to your property rather than a local variable:
self.MainMenu = [CCMenu menuWithItems: Start, About, nil];
Now you have a retained reference to the object, which you can pass later to removeChild:cleanup:.