0

私が作成している iPad アプリは、アプリで以前に生成された 4096x2992 画像のタイルを作成できる必要があります..

4096x2992 の画像はそれほど複雑ではなく (私がテストしているもの)、png 形式でファイルに書き込むと約 600kb になります...

シミュレーターでは、このコードは正常に動作しているように見えますが、(iPad で) より厳しいメモリ条件でアプリを実行すると、メモリが不足したためにプロセスが終了します...

以前はアプリで同じコードを使用していましたが、正常に機能していました(ただし、3072x2244 画像のタイルのみを作成していました)...

私が何か愚かなことをしているに違いないか、@autoreleasepool が正常に動作していないかのどちらかです (私は ARC を使用していると述べたと思います)...その後クラッシュ!

コードを分析しましたが、アプリのこの部分に関連するメモリ リークは 1 つも見つからなかったので、なぜこれがクラッシュするのか本当に混乱しています...

私の関数がどのように呼び出されるかについてのほんの少しの歴史なので、何が起こっているかがわかります... アプリは CoreGraphics を使用して、内部にいくつかの UIImageView を持つ UIView (4096x2992) をレンダリングし、その 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 に答える