今日、コードを書いてて気づいた。
ちょっと待て。いつからUIImageがNSCodingに対応しとんねん。
— Sumihiro Ueda/上田澄博 ✅さん (@sumihiro) 2013年2月5日
すると、
@sumihiro 5.0からっすね。むかし「おっ」って思った記憶があります。
— kishikawa katsumiさん (@k_katsumi) 2013年2月5日
さすがのきしかーさん。iOS5から対応していたと。
確かにシミュレータで確認してみたらiOS5.0から対応していたっぽい。
ところが、iOS5.0では正式対応されていなかったような?
ともかく、使えるのは使えるらしい。
そうすると、こう来るわけで。
@sumihiro 速度どぉ?
— nagisaworksさん (@nagisawks) 2013年2月5日
分かりました。ベンチマークとってみましょう。
今回使用したコードは以下の通り。
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test.dat"]; int loop = 1000; UIImage *image; image = [UIImage imageNamed:@"42616"]; NSLog(@"start."); NSDate *d; NSTimeInterval t; NSData *data; UIImage *imagei; // 従来使用していた UIImage を PNG の画像にして保存する方法 d = [NSDate date]; for (int i = 0; i < loop; ++ i) { @autoreleasepool { data = UIImagePNGRepresentation(image); [data writeToFile:path atomically:YES]; data = [NSData dataWithContentsOfFile:path]; imagei = [UIImage imageWithData:data]; NSAssert(imagei, @"failed."); } } t = [[NSDate date] timeIntervalSinceDate:d]; NSLog(@"Test1 %f sec",t); NSLog(@"data length: %d",data.length); NSLog(@"image size: %@",NSStringFromCGSize(imagei.size)); // -[UIImage imageNamed:] で読み込んだ UIImage を NSCoding で NSData にする方法 d = [NSDate date]; for (int i = 0; i < loop; ++ i) { @autoreleasepool { data = [NSKeyedArchiver archivedDataWithRootObject:image]; [data writeToFile:path atomically:YES]; data = [NSData dataWithContentsOfFile:path]; imagei = [NSKeyedUnarchiver unarchiveObjectWithData:data]; NSAssert(imagei, @"failed."); } } t = [[NSDate date] timeIntervalSinceDate:d]; NSLog(@"Test2 %f sec",t); NSLog(@"data length: %d",data.length); NSLog(@"image size: %@",NSStringFromCGSize(imagei.size)); // ビットマップから読み込んだ UIImage を NSCoding で NSData にする方法 UIImage *subimage = [UIImage imageNamed:@"42616"]; UIGraphicsBeginImageContext(subimage.size); [subimage drawAtPoint:CGPointZero]; image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); d = [NSDate date]; for (int i = 0; i < loop; ++ i) { @autoreleasepool { data = [NSKeyedArchiver archivedDataWithRootObject:image]; [data writeToFile:path atomically:YES]; data = [NSData dataWithContentsOfFile:path]; imagei = [NSKeyedUnarchiver unarchiveObjectWithData:data]; NSAssert(imagei, @"failed."); } } t = [[NSDate date] timeIntervalSinceDate:d]; NSLog(@"Test3 %f sec",t); NSLog(@"data length: %d",data.length); NSLog(@"image size: %@",NSStringFromCGSize(imagei.size)); NSLog(@"fin.");
バンドルに含まれている画像を読み込む -[UIImage imageNamed:] を使った画像の保存。そしてそれとは別に UIImagePNGRepresentation を使って PNG の NSData にした従来のシリアライズ方法。
使用した画像 42616.png は コードをオサレにしてくれるInstacodeが美しい の Instacode で作成したこちらの画像。
サイズは 512px x 512pxのPNG画像。大きすぎず小さすぎず。
使用した端末は iPhone5 iOS6.1。
そして結果が以下の通り。
2013-02-05 23:50:29.645 TestAutoCoding[9062:1103] start. 2013-02-05 23:52:08.185 TestAutoCoding[9062:1103] Test1: 98.538096 sec 2013-02-05 23:52:08.186 TestAutoCoding[9062:1103] data length: 454924 2013-02-05 23:52:08.187 TestAutoCoding[9062:1103] image size: {512, 512} 2013-02-05 23:52:10.562 TestAutoCoding[9062:1103] Test2: 2.373970 sec 2013-02-05 23:52:10.564 TestAutoCoding[9062:1103] data length: 393 2013-02-05 23:52:10.565 TestAutoCoding[9062:1103] image size: {512, 512} 2013-02-05 23:54:14.506 TestAutoCoding[9062:1103] Test3: 123.921053 sec 2013-02-05 23:54:14.507 TestAutoCoding[9062:1103] data length: 501234 2013-02-05 23:54:14.509 TestAutoCoding[9062:1103] image size: {512, 512} 2013-02-05 23:54:14.510 TestAutoCoding[9062:1103] fin.
なんと、TEST2 の結果がアホみたいに速い。
TEST2 と TEST3 については差があるものの、TEST2に比べれば大きくない。いや、20秒差は大きいけど。
ここで、書き込んだファイルのサイズを見てみると TEST2 のサイズだけとても小さい。
画像の PNG のデータを書き込んでいるとはとても思えない。
この NSData の中身を見てみると、どうやら plist のデータらしく、また、 42616.png のファイル名が見受けられる。
つまり、 -[UIImage imageNamed:] で読み込んだ UIImage は画像のデータではなくファイル名だけ記録している模様。そら PNG のデータ圧縮とかせんかったら速いわけやわ。
逆に、 TEST3 のデータを見てみると次のような感じ。
PNG のデータがそのまま埋め込まれているように見える。
TEST1 は純粋に PNG のデータだけ。
よって、速度比較では以下のような結果になった。
-[UIImage imageNamed:] で読み込んだ image を NSCodingで > ビットマップを PNG のデータにした NSData を保存 > ビットマップを NSCoding で
確かに -[UIImage imageNamed:] で読み込んだ image は速いけど、元ファイルが削除されてしまうと復元できなくなりそう。
UIImage が NSCoding に対応したのはいいけど、用途によって使い分けが必要、という結果になった。
追記:
@sumihiro @cqa02303 なるほど。この結果を踏まえると要するにIB(Storyboard)用に実装されたとみるべきじゃないかと。
— kishikawa katsumiさん (@k_katsumi) 2013年2月5日
なるほどねぇ。