ゲームを最初に実行するときに、320 の画像を生成して PNG として保存する必要があります。これらの画像は、再度生成される代わりに読み込まれます。プロセスは次のとおりです。
- 画像テンプレートの読み込み (アルファ付きの白黒)
- 指定された色で透明でないピクセルをオーバーレイする
- テンプレートの上に 0.3 の不透明度で配置し、それを 1 つの最終的な画像にマージします
- UIImage を返す
- NSData に変換された UIImage を Cache ディレクトリに PNG に保存します
これは、UIGraphicsBeginImageContextWithOptions を使用して行われます。このプロセスは、バックグラウンド スレッドの10 色の 32 個の画像テンプレートに対して実行する必要があります。目的は、これらをこのゲームのアバター/プロフィール画像として使用し、特定の画面で適切に縮小することです。ただし、これはラグが大きすぎるため、毎回生成することはできません。
画像はそれぞれ 400x400 です。保存すると、それぞれ約 20/25 kB になります。現在の生成方法と保存方法を使用しようとすると、メモリ警告が表示され、(Instruments を使用して) 生きている CGImage および UIImage オブジェクトの数が急速に増加し続けていることがわかります。これは保持されているようですが、私はそれらへの言及を保持していません。
これが、私が使用しているコードを詳しく説明する私の他の質問です: UIGraphicsBeginImageContext で作成された画像
この多くの画像を作成してセカンダリ ストレージに保存する最善の方法は何ですか? 前もって感謝します。
編集:
画像を作成して保存するために現在使用しているコード全体を次に示します。
//==========================================================
// Definitions and Macros
//==========================================================
//HEX color macro
#define UIColorFromRGB(rgbValue) [UIColor \
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
//Colours
#define RED_COLOUR UIColorFromRGB(0xF65D58)
#define ORANGE_COLOUR UIColorFromRGB(0xFF8D16)
#define YELLOW_COLOUR UIColorFromRGB(0xFFD100)
#define LIGHT_GREEN_COLOUR UIColorFromRGB(0x82DE13)
#define DARK_GREEN_COLOUR UIColorFromRGB(0x67B74F)
#define TURQUOISE_COLOUR UIColorFromRGB(0x32ADA6)
#define LIGHT_BLUE_COLOUR UIColorFromRGB(0x11C9FF)
#define DARK_BLUE_COLOUR UIColorFromRGB(0x2E97F5)
#define PURPLE_COLOUR UIColorFromRGB(0x8F73FD)
#define PINK_COLOUR UIColorFromRGB(0xF35991)
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//Generate the graphics
[self generateAndSaveGraphics];
}
//==========================================================
// Generating and Saving Graphics
//==========================================================
-(void)generateAndSaveGraphics {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self createAvatarImages];
//Here create all other images that need to be saved to Cache directory
dispatch_async( dispatch_get_main_queue(), ^{ //Finished
NSLog(@"DONE"); //always runs out of memory before getting here
});
});
}
-(void)createAvatarImages {
//Create avatar images
NSArray *colours = [NSArray arrayWithObjects:RED_COLOUR, ORANGE_COLOUR, YELLOW_COLOUR, LIGHT_GREEN_COLOUR, DARK_GREEN_COLOUR, TURQUOISE_COLOUR, LIGHT_BLUE_COLOUR, DARK_BLUE_COLOUR, PURPLE_COLOUR, PINK_COLOUR, nil];
NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
for(int i = 0; i < 32; i++) { //Avatar image templates are named m1 - m16 and f1 - f16
NSString *avatarImageName;
if(i < 16) { //female avatars
avatarImageName = [NSString stringWithFormat:@"f%i", i+1];
}
else { //male avatars
avatarImageName = [NSString stringWithFormat:@"m%i", i-15];
}
for(int j = 0; j < colours.count; j++) { //make avatar image for each colour
@autoreleasepool { //only helps very slightly
UIColor *colour = [colours objectAtIndex:j];
UIImage *avatarImage = [self tintedImageFromImage:[UIImage imageNamed:avatarImageName] colour:colour intensity:0.3];
NSString *fileName = [NSString stringWithFormat:@"%@_%i.png", avatarImageName, j];
NSString *filePath = [cacheDir stringByAppendingPathComponent:fileName];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(avatarImage)];
[imageData writeToFile:filePath atomically:YES];
NSLog(@"AVATAR IMAGE CREATED");
}
}
}
}
//==========================================================
// Universal Image Tinting Code
//==========================================================
//Creates a tinted image based on the source greyscale image and tinting intensity
-(UIImage *)tintedImageFromImage:(UIImage *)sourceImage colour:(UIColor *)color intensity:(float)intensity {
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(sourceImage.size, NO, 0.0);
} else {
UIGraphicsBeginImageContext(sourceImage.size);
}
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height);
// draw alpha-mask
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, sourceImage.CGImage);
// draw tint color, preserving alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[color setFill];
CGContextFillRect(context, rect);
//Set the original greyscale template as the overlay of the new image
sourceImage = [self verticallyFlipImage:sourceImage];
[sourceImage drawInRect:CGRectMake(0,0, sourceImage.size.width,sourceImage.size.height) blendMode:kCGBlendModeMultiply alpha:intensity];
UIImage *colouredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
colouredImage = [self verticallyFlipImage:colouredImage];
return colouredImage;
}
//Vertically flips an image
-(UIImage *)verticallyFlipImage:(UIImage *)originalImage {
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:originalImage];
UIGraphicsBeginImageContext(tempImageView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, tempImageView.frame.size.height);
CGContextConcatCTM(context, flipVertical);
[tempImageView.layer renderInContext:context];
UIImage *flippedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return flippedImage;
}
@end
問題を説明するために、テスト プロジェクト (zip 内) を作成しました。
今後の参考のために、解決策は次の 1 行のコードです。
tempImageView.image = nil;
マティックのおかげです。