【问题标题】:Where am I leaking CGMutablePathRef in this code?我在哪里泄漏了这段代码中的 CGMutablePathRef?
【发布时间】:2023-08-14 00:31:01
【问题描述】:

在我的代码中,我有 CGMutablePathRef thePath = CGPathCreateMutable();如果我不发布它,我实际上会得到成千上万的泄漏,因为我一直在做这个动作。但是,如果我确实释放它,我的游戏最终会崩溃。有任何想法吗?会不会是放错地方了?

-(void)MoveObject:(int)Tag
{   
    representationX = gameViewObj.spaceshipImageView.center.x;
    representationY = gameViewObj.spaceshipImageView.center.y;

    CALayer *spaceshipLayer = gameViewObj.spaceshipImageView.layer;
    shipAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    CGMutablePathRef thePath = CGPathCreateMutable();
    CGPathMoveToPoint(thePath, NULL, representationX, representationY);
    statusFire = YES;
    BOOL parsedF = NO;

其余代码如下:

-(void)MoveObject:(int)Tag
{   
    representationX = gameViewObj.spaceshipImageView.center.x;
    representationY = gameViewObj.spaceshipImageView.center.y;

    CALayer *spaceshipLayer = gameViewObj.spaceshipImageView.layer;
    shipAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    CGMutablePathRef thePath = CGPathCreateMutable();
    CGPathMoveToPoint(thePath, NULL, representationX, representationY);
    statusFire = YES;
    BOOL parsedF = NO;

    if(Tag==LeftButtonTag)
    {   
        gameViewObj.spaceshipImageView.transform = CGAffineTransformMakeRotation(M_PI + M_PI_2);

        previousButtonTag = LeftButtonTag;
        representationX--;
        CGPathAddLineToPoint(thePath, NULL,representationX, representationY);

        parsedF = YES;
    }   
    else if(Tag==UpButtonTag)
    {
        gameViewObj.spaceshipImageView.transform = CGAffineTransformMakeRotation(0);

        previousButtonTag = UpButtonTag;
        representationY--;

        CGPathAddLineToPoint(thePath, NULL,representationX, representationY);

        parsedF = YES;
    }
    else if(Tag==RightButtonTag)
    {
        gameViewObj.spaceshipImageView.transform = CGAffineTransformMakeRotation(M_PI/2);

        previousButtonTag = RightButtonTag;
        representationX++;

        CGPathAddLineToPoint(thePath, NULL,representationX, representationY);

        parsedF = YES;
    }
    else if(Tag==DownButtonTag)
    {
        gameViewObj.spaceshipImageView.transform = CGAffineTransformMakeRotation(M_PI);

        previousButtonTag = DownButtonTag;
        representationY++;

        CGPathAddLineToPoint(thePath, NULL,representationX, representationY);

        parsedF = YES;
    }

    if(parsedF){

        shipAnimation.path = thePath;
        shipAnimation.delegate = self;
        shipAnimation.duration = 0.003;
        [spaceshipLayer addAnimation:shipAnimation forKey:@"position"];

        //To kill spaceship when moved backwards.
        if(playField[representationX][representationY]==3){

            [self doDie];
        }

        if(playField[representationX][representationY] == 2){

            if(onSecretLine){

                [gameViewObj.spaceshipImageView setCenter:CGPointMake(representationX, representationY)];

                oldPositionX = representationX;
                oldPositionY = representationY;
            }
        }

        // case: breaking out
        if (playField[representationX][representationY]==0){
            if (onSecretLine){
                if (statusFire)
                {
                    availableOffline = YES;

                    oldPositionX=gameViewObj.spaceshipImageView.center.x;
                    oldPositionY=gameViewObj.spaceshipImageView.center.y;

                    [gameViewObj DrawLine];

                    onSecretLine = NO;
                    availableOffline = NO;
                }
            }
        }

        if (playField[representationX][representationY]==0)
            if (!onSecretLine)
            {
                BOOL doIt=true;

                // ------------------------------
                // prevent contact own line
                // ------------------------------
                // left 
                if (Tag==LeftButtonTag) { 
                    if (playField[representationX-1][representationY]==3) {

                        [self doDie];
                        doIt=false;
                    }
                }
                // right 
                if (Tag==RightButtonTag) { 
                    if (playField[representationX+1][representationY]==3) {

                        [self doDie];
                        doIt=false;
                    }
                }
                // up 
                if (Tag==UpButtonTag) { 
                    if (playField[representationX][representationY-1]==3) {

                        [self doDie]; 
                        doIt=false;
                    }
                }
                // down 
                if (Tag==DownButtonTag) {
                    if (playField[representationX][representationY+1]==3) {

                        [self doDie];
                        doIt=false;
                    }
                }

                // special things ...
                if (doIt)
                {
                    playField[representationX][representationY]=3;

                    [gameViewObj DrawLine];
                }

            }

        // case: back to the secure line
        if (playField[representationX][representationY]==2)
            if (!onSecretLine)
            {               
                [gameViewObj.spaceshipImageView setCenter:CGPointMake(representationX, representationY)];
                availableOffline = NO;  
                onSecretLine = YES;
                [[NSNotificationCenter defaultCenter] postNotificationName:@"FindBirdCenter" object:nil];

                for (int i=0; i<[gameViewObj.birdImageViewArray count]; i++) {
                    UIImageView* ImgBird=[gameViewObj.birdImageViewArray objectAtIndex:i];
                    int px=ImgBird.center.x;
                    int py=ImgBird.center.y;
                    // cristall point
                    playField[px][py]=5;
                }

                [self fillPlaygroundExtended];

                //Elan function for filling area enclosed
                [self fillAreaEnclosed:gameViewObj._myContext];

                // invert ..
                [self invertPlayground];

                // turn the 3 into -> 20+
                [self generateNewSecureLine];

            }

        if(Tag == UpButtonTag){

            [self moveShipUp];
        }

        else if(Tag == RightButtonTag){

            [self moveShipRight];
        }

        else if(Tag == DownButtonTag){

            [self moveShipDown];
        }

        else if(Tag == LeftButtonTag){

            [self moveShipLeft];

        }
        if(doScore == YES){
            [self calculateScore];
            doScore = NO;
        }
        [gameViewObj setNeedsDisplay];
    }
}

【问题讨论】:

  • 你能显示一些代码吗?如果不了解您是如何使用这些对象的,就很难回答这个问题
  • 你在哪里/如何释放路径?
  • 我在最后一次使用后发布

标签: iphone cocoa-touch core-animation core-graphics


【解决方案1】:

您应该在该行之后的路径上执行 CGPathRelease()

shipAnimation.path = thePath;

以及在

的 else 语句中
if(parsedF){

条件(否则如果parsedF 为NO,它仍然会泄漏。

【讨论】:

    【解决方案2】:

    你永远不会释放thePath。至少在那个代码 sn-p 中没有。

    Core Graphics 使用 Core Foundation Memory Rules,您可以在 Memory Management Programming Guide for Core Foundation

    阅读该规则

    简而言之:任何名称中包含Create 的函数都将返回一个保留对象,您需要使用名称中包含Release 的函数来释放该对象。如果是CGPathRef,则有CGPathRelease

    【讨论】:

    • 我遇到的问题是,当我发布它时,我的游戏最终崩溃了,但没有泄漏。当我不发布它时,实际上有成千上万的泄漏,但游戏不会崩溃。我想我不知道在哪里发布它。
    • 也许你在错误的地方释放它。从上面的代码中并不清楚你在什么上下文中实际使用了路径。
    • 在 dealloc 中释放它表示未声明。我知道我必须在最后一次使用它后的某个时间发布它。