Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iphone上cocos2d分配系统的理解问题_Iphone_Objective C_Memory Management_Cocos2d Iphone - Fatal编程技术网

iphone上cocos2d分配系统的理解问题

iphone上cocos2d分配系统的理解问题,iphone,objective-c,memory-management,cocos2d-iphone,Iphone,Objective C,Memory Management,Cocos2d Iphone,我正在努力学习iphone的cocos2d,学习下面的书。我修改了源代码的Chu 08文件夹中的ShooteMP3示例(http://www.apress.com/downloadable/download/sample/sample_id/640/). 我想要实现的是拥有一个菜单场景和一个游戏场景,并且能够在游戏场景结束后返回菜单场景(例如,所有生命都丢失)。从“场景”菜单中,我可以通过点击图标访问特定的游戏场景,这些图标是一个叫做“LevelIcon”的类的距离。换句话说,我称之为“Nav

我正在努力学习iphone的cocos2d,学习下面的书。我修改了源代码的Chu 08文件夹中的ShooteMP3示例(http://www.apress.com/downloadable/download/sample/sample_id/640/).

我想要实现的是拥有一个菜单场景和一个游戏场景,并且能够在游戏场景结束后返回菜单场景(例如,所有生命都丢失)。从“场景”菜单中,我可以通过点击图标访问特定的游戏场景,这些图标是一个叫做“LevelIcon”的类的距离。换句话说,我称之为“Navigator”(CCLayer的子类)的菜单场景包含出现在菜单场景中的“LevelIcon”类(NSObject的子类)的istances,并通过调用CCDirector的ReplaceSecase方法响应触摸事件,如下所示:

//From LevelIcon.m    
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CCLOG(@"Touch");
    [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
    GameScene * game = [GameScene scene];
    [[CCDirector sharedDirector] replaceScene:game];
    return TRUE;
}
我试图在Navigator dealloc方法中释放对象,但是在LevelIcon的release方法上添加了一条CCLOG消息,我发现release方法从未被调用

//From Navigator.m

-(void)dealloc
{
    CCLOG(@"Navigator dealloc");
    CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);

    level1 = nil;
    [level1 dealloc];

    [super dealloc];
}
然后,我在更新方法中添加了一个日志,并观察到即使场景是GameSecene而不是Navigator场景,仍会调用该日志。我无法理解的是LevelIcon是在Navigator中创建的一个对象,在Navigator的dealoc方法中,我尝试释放类的istance,如上图所示(,但没有这样做)

为了证实这一点,我尝试从游戏场景到导航器来回切换,以便在游戏场景中触发以下代码:

        Navigator * navigator = [Navigator scene];
    [[CCDirector sharedDirector] replaceScene:navigator];
新导航器类的创建工作正常,但当返回游戏场景时,新的LevelIcon类实例不会消失,而是保留下来(这样它就会累积)。我们必须注意,ReplaceSecene方法是从响应触摸事件的LevelIcon类中调用的,如下所示:

GameScene * game = [GameScene scene];
[[CCDirector sharedDirector] replaceScene:game];
换句话说,在此事件之后,将调用Navigator release方法,而不是LevelIcon,如果多次调用,LevelIcon类将在内存中保持活动状态

我不确定我做错了什么,但我希望得到一些提示或帮助

我还尝试了另一种方法,通过添加LevelIcon的istance作为Navigator的子级(使用addChild方法),但它不起作用,因为它派生自NSObject类而不是cocos2d节点类。我想知道以某种方式调整它是否有意义,或者它是否可以作为两个不同的类层次结构(cocos2d和NS/Objective-C)的一部分

我粘贴完整的代码以帮助理解:

--NAVIGATOR.H-----

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

@interface Navigator : CCLayer {
    LevelIcon *level1;
}

+ (id) scene;

@end


-----NAVIGATOR.M------
#import "Navigator.h"
#import "LevelIcon.h"

@implementation Navigator

+(id) scene {
    CCScene *scene = [CCScene node];
    CCLayer *layer = [Navigator node];//??
    [scene addChild:layer];
    return scene;     
}

-(id)init 
{
    CCLOG(@"init");
    if((self=[super init])){        
        CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
        self.isAccelerometerEnabled=YES;
        self.isTouchEnabled = YES;

        [self scheduleUpdate];  
        level1 = [LevelIcon levelIconWithParentNode:self];
    }
    return self;
}

-(void)dealloc
{
    CCLOG(@"Navigator dealloc");
    CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);

    level1 = nil;
    [level1 dealloc];

    [super dealloc];
}
[..]
@end


------LEVELICON.H------------
#import <Foundation/Foundation.h>
#import "cocos2d.h"

@interface LevelIcon : NSObject<CCTargetedTouchDelegate> {
    CCSprite* levelIconSprite;
 }

+(id) levelIconWithParentNode:(CCNode*)parentNode;
-(id) initWithParentNode:(CCNode*)parentNode;

@end



-----LEVEL ICON.M----------------
#import "LevelIcon.h"
#import "GameScene.h"

@implementation LevelIcon

// Static autorelease initializer, mimics cocos2d's memory allocation scheme.
+(id) levelIconWithParentNode:(CCNode*)parentNode
{
    CCLOG(@"levelIconWithParentNode");  
    return [[[self alloc] initWithParentNode:parentNode] autorelease];
}

-(id) initWithParentNode:(CCNode*)parentNode 
{
    CCLOG(@"initWithParentNode");
    if ((self = [super init]))
    {
        CCLOG(@"initWithParentNode: inside if");
        CGSize screenSize = [[CCDirector sharedDirector] winSize];

        levelIconSprite = [CCSprite spriteWithFile:@"Icon.png"];
        levelIconSprite.position = CGPointMake(CCRANDOM_0_1() * screenSize.width, CCRANDOM_0_1() * screenSize.height);
        [parentNode addChild:levelIconSprite];

        // Manually schedule update via the undocumented CCScheduler class used internally by CCNode.
        [[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:0 paused:NO];

        // Manually add this class as receiver of targeted touch events.
        [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES];
    }

    return self;
}

-(void) dealloc
{
    CCLOG(@"Level icon dealloc");
    // Must manually unschedule, it is not done automatically for us.
    [[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self];

    // Must manually remove this class as touch input receiver!
    [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
    [super dealloc];
}

-(void) update:(ccTime)delta
{
    CCLOG(@"Icon Update!");
}


-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CCLOG(@"Touch");
    [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
    GameScene * game = [GameScene scene];
    [[CCDirector sharedDirector] replaceScene:game];
    return TRUE;
}

@end
--NAVIGATOR.H-----
#进口
#导入“cocos2d.h”
#导入“LevelIcon.h”
@接口导航器:CCLayer{
LevelIcon*level1;
}
+(id)现场;
@结束
-----NAVIGATOR.M------
#导入“Navigator.h”
#导入“LevelIcon.h”
@实现导航器
+(id)现场{
CCScene*scene=[CCScene节点];
CCLayer*层=[Navigator节点];/??
[场景添加子对象:层];
返回场景;
}
-(id)init
{
CCLOG(@“init”);
if((self=[super init]){
CCLOG(@“%@:%@”、NSStringFromSelector(_cmd)、self);
self.isAccelerometerEnabled=是;
self.isTouchEnabled=是;
[自计划更新];
level1=[LevelIcon-levelIconWithParentNode:self];
}
回归自我;
}
-(无效)解除锁定
{
CCLOG(“导航器解除锁定”);
CCLOG(@“%@:%@”、NSStringFromSelector(_cmd)、self);
级别1=零;
[1级解除锁定];
[super dealoc];
}
[..]
@结束
------LEVELICON.H------------
#进口
#导入“cocos2d.h”
@接口级别图标:NSObject{
CCSprite*leveliconspite;
}
+(id)levelIconWithParentNode:(CCNode*)parentNode;
-(id)initWithParentNode:(CCNode*)parentNode;
@结束
-----水平图标.M----------------
#导入“LevelIcon.h”
#导入“GameSecene.h”
@实现级别图标
//静态自动释放初始化器,模仿cocos2d的内存分配方案。
+(id)levelIconWithParentNode:(CCNode*)parentNode
{
CCLOG(@“levelIconWithParentNode”);
返回[[[self alloc]initWithParentNode:parentNode]autorelease];
}
-(id)initWithParentNode:(CCNode*)parentNode
{
CCLOG(@“initWithParentNode”);
if((self=[super init]))
{
CCLOG(@“initWithParentNode:inside if”);
CGSize screenSize=[[CCDirector sharedDirector]winSize];
levelIconSprite=[CCSprite spriteWithFile:@“Icon.png”];
levelIconSprite.position=CGPointMake(CCRANDOM_0_1()*screenSize.width,CCRANDOM_0_1()*screenSize.height);
[parentNode addChild:levelIconSprite];
//通过CCNode内部使用的未记录CCScheduler类手动安排更新。
[[CCScheduler sharedScheduler]scheduleUpdateForTarget:自优先级:0暂停:否];
//手动添加此类作为目标触摸事件的接收器。
[[CCTouchDispatcher sharedDispatcher]AddTargetedLegate:自优先级:-1燕子接触:是];
}
回归自我;
}
-(无效)解除锁定
{
CCLOG(@“级别图标解除锁定”);
//必须手动取消计划,这不是为我们自动完成的。
[[CCScheduler sharedScheduler]目标的非计划更新:self];
//必须手动删除该类作为触摸输入接收器!
[[CCTouchDispatcher sharedDispatcher]removeDelegate:self];
[super dealoc];
}
-(无效)更新:(ccTime)增量
{
CCLOG(@“图标更新!”);
}
-(BOOL)cctouch开始:(UITouch*)触摸事件:(UIEvent*)事件
{
CCLOG(@“触摸”);
[[CCTouchDispatcher sharedDispatcher]removeDelegate:self];
游戏场景*游戏=[游戏场景];
[[CCDirector sharedDirector]替换场景:游戏];
返回TRUE;
}
@结束
谢谢阅读!:)

这很奇怪:

level1 = nil;
[level1 dealloc];
1) 如果不想直接调用dealloc,请使用[level1 release],当引用计数达到0时,它将自动解除锁定

2) 这个顺序是错误的,在将level1设置为nil后,下一行没有任何效果(您可以无害地向nil指针发送消息,它们安静地不做任何事情)。

在一天结束时,我
[[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self];
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
//From CCTouchDispatcher.m line 121
-(void) addTargetedDelegate:(id<CCTargetedTouchDelegate>) delegate priority:(int)priority swallowsTouches:(BOOL)swallowsTouches 
{
    CCTouchHandler *handler = [CCTargetedTouchHandler handlerWithDelegate:delegate priority:priority swallowsTouches:swallowsTouches];
    if( ! locked ) {
        [self forceAddHandler:handler array:targetedHandlers];
    } else {
        [handlersToAdd addObject:handler];
        toAdd = YES;
    }
}

//From ccCArray.h line 115 (after having opened the definition of several function starting from **addObject** being called by addTargetedDelegate I got here)
/** Appends an object. Bahaviour undefined if array doesn't have enough capacity. */
static inline void ccArrayAppendObject(ccArray *arr, id object)
{
    arr->arr[arr->num] = [object retain];
    arr->num++;
}
//From LevelIcon.m 
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CCLOG(@"Touch");
    [[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self];
    [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];

    GameScene * game = [GameScene scene];
    [[CCDirector sharedDirector] replaceScene:game];



    return TRUE;
}

//From CCTouchDispatcher.m line 153
-(void) removeDelegate:(id) delegate
{
    if( delegate == nil )
        return;

    if( ! locked ) {
        [self forceRemoveDelegate:delegate];
    } else {
        [handlersToRemove addObject:delegate];
        toRemove = YES;
    }
}