iPhoneレシピ5:zipファイルを解凍する

ポイント

iPhoneにはzlibが入っているので、それを利用して解凍する。
zlibを使うためには、libz***.dylibへのリンクが必要。そのためには、xcodeで「グループとファイル」ビュー上で右クリック→「追加」→「既存のフレームワークを追加」でibz***.dylibを追加すればよい。

生のzlibをそのまま使うのはちょっと面倒だが、zlibと一緒に配布されているminizipをさらにObjective-Cでラップした「HetimaUnZip.framework」をHetimaさんが公開している。

HetimaUnZipはCocoaを使っているため、iPhoneで利用できるよう、Cocoaへの依存部分および不要なminizipファイルの削除と、メモリ上ではなく、直接ファイルに解凍するメソッドを追加したものを利用する。

オリジナルのFrameworkをiPhone上で使う方法が分からないため、とりあえず直接ソースのまま取り込んで使う。
改変したHetimaUnZipはここからダウンロードできる。

HetimaUnzip改変版

ソース

NSString *filePath = @"zipファイルへのパス";
HetimaUnZipContainer *unzipContainer = [[HetimaUnZipContainer alloc] initWithZipFile:filePath];
[unzipContainer setListOnlyRealFile:YES];
	
HetimaUnZipItem *item;
NSEnumerator *contentsEnum = [[unzipContainer contents] objectEnumerator];

// プログレスバー表示用に全ファイルのサイズを取得
expectedUmcompressedContentSize = 0;
for (item in contentsEnum) {
	expectedUmcompressedContentSize += [item uncompressedSize];
	LOG(@"zip\tpath:%@\t%d", [item path], [item uncompressedSize]);
}

// 解凍
contentsEnum = [[unzipContainer contents] objectEnumerator];
for (item in contentsEnum) {
	NSString *path = [[NSFileManager defaultManager] suggestFilePath:[APPLICATION_DOC_DIR stringByAppendingPathComponent:[item path]]];
	BOOL result = [item extractTo:path delegate:self];
	if (!result) {
		NSString *err = [NSString stringWithFormat:NSLocalizedString(@"Failed to extract %@.", nil), [item path]];
		UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:err delegate:actionSheet cancelButtonTitle:nil otherButtonTitles:@"OK",nil];
		[alert show];
		[alert release];
	}
}

// HetimaUnZipItemDelegate
// HetimaUnZipItem#extractTo:delegate:の解凍状況はdelegateのメソッドで取得できる。
- (void)item:(HetimaUnZipItem *)item didExtractDataOfLength:(NSUInteger)length {
	progressBar.progress = progressBar.progress + ((long double)length / (long double)expectedUmcompressedContentSize) * 0.5f;
	LOG(@"Extracting %f", progressBar.progress);
}