0

我正在创建的 iPad 应用程序必须能够为之前在我的应用程序中生成的 4096x2992 图像创建图块。

4096x2992 图像不是很复杂(我正在测试的内容),当以 png 格式写入文件时大约为 600kb ...

在模拟器上,这段代码似乎工作正常,但是当我在更严格的内存条件下(在我的 iPad 上)运行应用程序时,进程退出,因为它内存不足......

我一直在应用程序中使用相同的代码,以前工作正常(但是只为 3072x2244 图像创建图块)......

要么我必须做一些愚蠢的错误,要么我的@autoreleasepool 没有按应有的方式工作(我想我提到我使用 ARC)......在仪器中运行时,我只能看到使用的内存攀升到 ~500mb然后崩溃!

我已经分析了代码,但没有发现与我的应用程序的这一部分相关的单个内存泄漏,所以我真的很困惑为什么这会在我身上崩溃......

只是关于如何调用我的函数的一点历史,所以你知道发生了什么......该应用程序使用 CoreGraphics 渲染一个 UIView (4096x2992),其中包含一些 UIImageView,然后它将 UIImage 引用发送到我的函数buildFromImage:(如下)开始切割向上/调整图像大小以创建我的文件...

这是代码...内存问题是在...buildFromImage:下的主循环中建立的NSLog(@"LOG ------------> Begin tile loop ");

-(void)buildFromImage:(UIImage *)__image {

NSLog(@"LOG ------------> Begin Build ");



//if the __image is over 4096 width of 2992 height then we must resize it! (stop crashes ect)
if (__image.size.width > __image.size.height) {
    if (__image.size.width > 4096) {
        __image = [self resizeImage:__image toSize:CGSizeMake(4096, (__image.size.height * 4096 / __image.size.width))];
    }
} else {
    if (__image.size.height > 2992) {
        __image = [self resizeImage:__image toSize:CGSizeMake((__image.size.width * 2992 / __image.size.height), 2992)];
    }
}

//create preview image (if landscape, no more than 748 high... if portrait, no more than 1004 high) must keep scale
NSString *temp_archive_store = [[NSString alloc] initWithFormat:@"%@/%i-temp_imgdat.zip",NSTemporaryDirectory(),arc4random()];
NSString *temp_tile_store = [[NSString alloc] initWithFormat:@"%@/%i-temp_tilestore/",NSTemporaryDirectory(),arc4random()];


//create the temp dir for the tile store
[[NSFileManager defaultManager] createDirectoryAtPath:temp_tile_store withIntermediateDirectories:YES attributes:nil error:nil];

//create each tile and add it to the compressor once its made
//size of tile
CGSize tile_size = CGSizeMake(256, 256);
//the scales that we will be generating the tiles too
NSMutableArray *scales = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:1000],[NSNumber numberWithInt:500],[NSNumber numberWithInt:250],[NSNumber numberWithInt:125], nil]; //scales to loop round over

NSLog(@"LOG ------------> Begin tile loop ");
@autoreleasepool {
    //loop through the scales
    for (NSNumber *scale in scales) {

        //scale the image
        UIImage *imageForScale = [self resizedImage:__image scale:[scale intValue]];

        //calculate number of rows...
        float rows = ceil(imageForScale.size.height/tile_size.height);

        //calulate number of collumns
        float cols = ceil(imageForScale.size.width/tile_size.width);

        //loop through rows and cols

        for (int row = 0; row < rows; row++) {

            for (int col = 0; col < cols; col++) {

                NSLog(@"LOG ------> Creating Tile (%i,%i,%i)",col,row,[scale intValue]);

                //build name for tile...
                NSString *tile_name = [NSString stringWithFormat:@"%@_%i_%i_%i.png",@"image",[scale intValue],col,row];

                @autoreleasepool {

                    //build tile for this coordinate
                    UIImage *tile = [self tileForRow:row column:col size:tile_size image:imageForScale];

                    //convert image to png data
                    NSData *tile_data = UIImagePNGRepresentation(tile);

                    [tile_data writeToFile:[NSString stringWithFormat:@"%@%@",temp_tile_store,tile_name] atomically:YES];

                }


            }

        }

    }

}
}        

这也是我的调整大小/裁剪功能,因为这些也可能导致问题..

-(UIImage *)resizeImage:(UIImage *)inImage toSize:(CGSize)scale {

@autoreleasepool {

    CGImageRef inImageRef = [inImage CGImage];

    CGColorSpaceRef clrRf = CGColorSpaceCreateDeviceRGB();

    CGContextRef ctx = CGBitmapContextCreate(NULL, ceil(scale.width), ceil(scale.height), CGImageGetBitsPerComponent(inImageRef), CGImageGetBitsPerPixel(inImageRef)*ceil(scale.width), clrRf, kCGImageAlphaPremultipliedFirst );

    CGColorSpaceRelease(clrRf);

    CGContextDrawImage(ctx, CGRectMake(0, 0, scale.width, scale.height), inImageRef);

    CGImageRef img = CGBitmapContextCreateImage(ctx);

    UIImage *image = [[UIImage alloc] initWithCGImage:img scale:1 orientation:UIImageOrientationUp];

    CGImageRelease(img);
    CGContextRelease(ctx);

    return image;

}

}

- (UIImage *)tileForRow: (int)row column: (int)col size: (CGSize)tileSize image: (UIImage*)inImage
{

@autoreleasepool {

    //get the selected tile
    CGRect subRect = CGRectMake(col*tileSize.width, row * tileSize.height, tileSize.width, tileSize.height);

    CGImageRef inImageRef = [inImage CGImage];

    CGImageRef tiledImage = CGImageCreateWithImageInRect(inImageRef, subRect);

    UIImage *tileImage = [[UIImage alloc] initWithCGImage:tiledImage scale:1 orientation:UIImageOrientationUp];

    CGImageRelease(tiledImage);

    return tileImage;

}

}

现在我从来没有在内存管理方面做得那么好,所以我确实花时间阅读它,并将我的项目转换为 ARC,看看是否可以解决我的问题(那是前一段时间),但从结果来看,我在仪器中对其进行分析后,我必须做一些非常错误的事情,以使内存泄漏得如此糟糕,但我只是看不出我做错了什么。

如果有人能指出我可能做错的任何事情,那就太好了!

谢谢

利亚姆

(如果您需要更多信息,请告诉我)

4

1 回答 1

0

我使用“UIImage+Resize”。在 @autoreleasepool {} 内,它可以在循环中与 ARC 一起正常工作。

https://github.com/AliSoftware/UIImage-Resize

-(void)compress:(NSString *)fullPathToFile {
@autoreleasepool {
    UIImage *fullImage = [[UIImage alloc] initWithContentsOfFile:fullPathToFile];
    UIImage *compressedImage = [fullImage resizedImageByHeight:1024];
    NSData *compressedData = UIImageJPEGRepresentation(compressedImage, 75.0);
    [compressedData writeToFile:fullPathToFile atomically:NO];
}

}

于 2013-12-01T09:53:50.143 回答