在 ARC 中启动新的 Cocos2d-iPhone 项目后出现内存警告。初学者

Posted

技术标签:

【中文标题】在 ARC 中启动新的 Cocos2d-iPhone 项目后出现内存警告。初学者【英文标题】:Getting memory warnings after starting a new Cocos2d-iPhone project in ARC. Beginner 【发布时间】:2013-05-31 12:06:36 【问题描述】:

为了学习 Cocos2d,最近一直在自学 Objective-c。

开始了一个新项目,通过经典的坠落宝石俄罗斯方块游戏自学基础知识。我采取的第一步是使用编辑 > 重构为 ARC 启用项目,并选择模板中的最后 4 个文件。

到目前为止,我们已经能够通过子类化 CCSprite 添加具有动态颜色精灵的单个 gem,并在它从顶部掉落的同时沿着 XCoordinates 移动它。宝石被赋予一个 gemPos 位置——例如 5,3——以便我稍后实现匹配方法。

在测试项目一段时间后,当一些块相互堆叠时,我收到了 EXC_BAD_ACCESS 警告。如果启用了 ARC,我不知道为什么会发生这种情况。

我笨拙的代码如下(省略了 .h 文件):

默认的 helloworld 层:

-(id) init
    

        if( (self=[super init]) ) 

            oldGems = [[NSMutableArray alloc]init];

            [self setIsTouchEnabled:YES];

            [self newGem];

            [self scheduleUpdate];

        
        return self;
    

    - (void)registerWithTouchDispatcher
    
        [[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
    

    - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
    
        CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
        oldPos = touchLocation;
        return TRUE;
    

    - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
    
        CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
        [self updateXCoord:(CGPoint)touchLocation];
    

    - (void)updateXCoord:(CGPoint)touchLocation
    


        CGPoint distance = ccpSub(touchLocation, oldPos);
        float xDistance = distance.x;

        if (abs(xDistance) >= 36) 
            if (touchLocation.x > oldPos.x) 
                [_thisGem setPosition:ccp([_thisGem position].x + 36, [_thisGem position].y)];
                [_thisGem setGemPos:ccp([_thisGem gemPos].x+1,[_thisGem gemPos].y)];
                NSLog(@"The gem position is %@", NSStringFromCGPoint([_thisGem gemPos]));
                oldPos = touchLocation;
             else 
                [_thisGem setPosition:ccp([_thisGem position].x - 36, [_thisGem position].y)];
                [_thisGem setGemPos:ccp([_thisGem gemPos].x-1,[_thisGem gemPos].y)];
                NSLog(@"The gem position is %@", NSStringFromCGPoint([_thisGem gemPos]));
                oldPos = touchLocation;
            
        


    

    - (void)newGem
    
        if (_thisGem) 
            PCGem *oldGem = _thisGem;
            NSLog(@"Old gem position at %@", NSStringFromCGPoint([oldGem gemPos]));
            [oldGems addObject:oldGem];
        

        _thisGem = [[PCGem alloc] initWithGemColor];
        [_thisGem setPosition:ccp(160, 450)];
        [self addChild:_thisGem];
        [_thisGem setGemPos:ccp(4,10)];

        NSLog(@"Gem added with %@ color", [_thisGem gemColorName]);
    

    - (void)update:(ccTime)dt
    

        if ([_thisGem gemPos].y > 0)  

            [self spaceBelowOccupied];

            [_thisGem setPosition:ccp([_thisGem position].x, [_thisGem position].y-1)];
            [_thisGem setGemPos:ccp([_thisGem gemPos].x, floor([_thisGem position].y / 36))];

         else 
            [self newGem];
        
    

    - (void)spaceBelowOccupied
        
            for (PCGem *occupiedTile in oldGems) 
                if (CGRectIntersectsRect(occupiedTile.boundingBox, _thisGem.boundingBox)) 
                    NSLog(@"Collision detected!");
                    [self newGem];
                
            
    

还有我笨拙的 PCGem 课:

    - (id)initWithGemColor
    
        if ((self = [super initWithFile:@"gemGS.png"])) 


            NSArray *gemColorList = [NSArray arrayWithObjects:(NSString *)@"blue", (NSString *)@"red", (NSString *)@"green", nil];

            NSInteger randColor = arc4random_uniform(3);

            switch (randColor) 
                case 0:
                
                    [self setGemColorName:[gemColorList objectAtIndex:0]];

                    ccColor3B gemColorRGB = 0,0,255;
                    [self setColor:gemColorRGB];
                    break;
                
                case 1:
                
                    [self setGemColorName:[gemColorList objectAtIndex:1]];

                    ccColor3B gemColorRGB = 255,0,0;
                    [self setColor:gemColorRGB];            
                    break;
                
                case 2:
                
                    [self setGemColorName:[gemColorList objectAtIndex:2]];

                    ccColor3B gemColorRGB = 0,255,0;
                    [self setColor:gemColorRGB];
                    break;
                
            

        

        return self;

    

这让我想到了另一个问题,我似乎无法找到答案。在启用 ARC 的 Cocos2d 项目的示例中,我看到了使用的节点便捷方法,当然是 alloc]init]autorelease]。但是我认为您不能将 Autorelease 与 ARC 一起使用,这会导致崩溃吗?这是如何工作的?

对我的困境有什么想法吗?非常感谢澄清:)

干杯,

阿德里安

【问题讨论】:

哪一行实际崩溃了? 当我单击 EXC_BAD_ACCESS 通知程序时,它会将我带到 main.m(这表明哪些行崩溃?抱歉,新的。),并指向:int retVal = UIApplicationMain(argc, argv,无,@“AppController”);在@autoreleasepool 中。虽然这让我感到困惑,因为我认为启用 ARC 不需要这样做? 另外,通过使用 NSLogs,我发现添加了一个新的 gem,因为我在我的 -(void)newGem 方法的末尾收到“Gem added with %@ color”消息,所以我假设它与更新方法有关?也许我试图以每秒 60 帧的速度一次做太多事情(快速枚举所有不在游戏中的宝石以检测与当前掉落的宝石的碰撞 - 可以更有效地处理问题)? 【参考方案1】:

我认为这可能是由于在枚举数组时编辑数组引起的。在您的更新函数中,您调用 spaceBelowOccupied:

- (void)spaceBelowOccupied
    
        for (PCGem *occupiedTile in oldGems) 
            if (CGRectIntersectsRect(occupiedTile.boundingBox, _thisGem.boundingBox)) 
                NSLog(@"Collision detected!");
                [self newGem];
            
        

那么如果 newGem 在你的 for 循环中被调用并且这个循环成功:

if (_thisGem) 
        PCGem *oldGem = _thisGem;
        NSLog(@"Old gem position at %@", NSStringFromCGPoint([oldGem gemPos]));
        [oldGems addObject:oldGem];
    

然后您在枚举数组时将对象添加到数组中。所以把你的 spaceBelowOccupied 改成这个,看看它是否有效:

 - (void)spaceBelowOccupied
    
        for (PCGem *occupiedTile in [oldGems copy]) 
            if (CGRectIntersectsRect(occupiedTile.boundingBox, _thisGem.boundingBox)) 
                NSLog(@"Collision detected!");
                [self newGem];
            
        

这样你就可以复制 oldGems 来枚举,一旦你完成它就会自动发布。

【讨论】:

感谢 Marcus 的回复 - 我已经重新启动项目并遇到了类似的问题,因此使用不同的解决方案解决了这个问题......但我认为可能是这样!

以上是关于在 ARC 中启动新的 Cocos2d-iPhone 项目后出现内存警告。初学者的主要内容,如果未能解决你的问题,请参考以下文章

Oracle Dataguard报错:ARC1: Becoming the ‘no FAL‘ ARC

为啥 ARC 在 popViewController 之后不释放内存

xcode禁用ARC(Automatic Reference Counting)

ARC下双倍免费

ARC 和内存问题

以编程方式从 ARC 中的导航堆栈中删除 viewController