iPhoneレシピ6:zipファイルをダウンロードし、Documentsディレクトリに解凍する
下記4つのレシピを組み合わせて、zipファイルをダウンロードし、Documentsディレクトリに解凍する方法。
- iPhone SDKレシピ2:NSURLConnectionを使ってファイルをダウンロードする - Random Note
- iPhone SDKレシピ3:UIProgressViewの使い方 - Random Note
- iPhoneレシピ4:UIActionSheetにプログレスバーを表示する - Random Note
- iPhoneレシピ5:zipファイルを解凍する - Random Note
ポイント
基本的には上記のレシピの中にあるとおり。
ただしiPhone SDKレシピ3:UIProgressViewの使い方 - Random Noteにある、UIProgressViewのprogressプロパティを別スレッドで設定する、という部分の別スレッド呼び出しについては、NSURLConnectionとHetimaUnZipItemの中に隠蔽されている。
ソース
UIActionSheetを用意しておいて、
- (void)viewDidLoad { [super viewDidLoad]; actionSheet = [[UIActionSheet alloc] initWithTitle:@"Please wait...\n\n\n\n" delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel",nil) destructiveButtonTitle:nil otherButtonTitles:nil]; progressBar = [[UIProgressView alloc] initWithFrame:CGRectMake(30.0f, 40.0f, 240.0f, 90.0f)]; progressBar.progressViewStyle = UIProgressViewStyleDefault; progressBar.progress = 0.0f; [actionSheet addSubview:progressBar]; progressLabel = [[UILabel alloc] initWithFrame:CGRectMake(30.0f, 50.0f, 240.0f, 20.0f)]; progressLabel.backgroundColor = [UIColor clearColor]; progressLabel.textColor = [UIColor whiteColor]; progressLabel.font = [UIFont systemFontOfSize:[UIFont systemFontSize]]; progressLabel.text = NSLocalizedString(@"Downloading...", nil); [actionSheet addSubview:progressLabel]; downloaderLock = [[NSLock alloc] init]; }
ダウンロードを開始し、
- (IBAction) download:(id)sender { [urlField resignFirstResponder]; downloadedContentLength = 0; progressBar.progress = 0; NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:[urlField text]]]; [[NSFileManager defaultManager] clearTmpDirectory]; progressLabel.text = NSLocalizedString(@"Downloading...", nil); [actionSheet showInView:self.view]; downloader = [[URLDownload alloc] initWithRequest:req directory:APPLICATION_TMP_DIR delegate:self]; }
ダウンロードが終わったら解凍する。だけ。
- (void)downloadDidFinish:(URLDownload *)download { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; LOG(download.filePath); progressLabel.text = NSLocalizedString(@"Extracting...", nil); HetimaUnZipContainer *unzipContainer = [[HetimaUnZipContainer alloc] initWithZipFile:download.filePath]; [unzipContainer setListOnlyRealFile:YES]; if ([[unzipContainer contents] count] == 0) { NSString *err = NSLocalizedString(@"No zip file is found.", nil); UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:err delegate:actionSheet cancelButtonTitle:nil otherButtonTitles:@"OK",nil]; [alert show]; [alert release]; } else { 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]; } } } [unzipContainer release]; [pool release]; [self dismissActionSheet]; }
ダウンロード中の進行状況はURLDownloadDelegateで取得。
- (void)download:(URLDownload *)download didReceiveResponse:(NSURLResponse *)response { expectedContentLength = [response expectedContentLength]; } - (void)download:(URLDownload *)download didReceiveDataOfLength:(NSUInteger)length { progressBar.progress = progressBar.progress + ((long double)length / (long double)expectedContentLength) * 0.5f; LOG(@"Download: %f", progressBar.progress); }
解凍中の進行状況はHetimaUnZipItemDeletegateで取得。
- (void)item:(HetimaUnZipItem *)item didExtractDataOfLength:(NSUInteger)length { progressBar.progress = progressBar.progress + ((long double)length / (long double)expectedUmcompressedContentSize) * 0.5f; LOG(@"Extracting %f", progressBar.progress); }
終わったらdismissActionSheetを呼びだし、後始末。
UIActionSheetが非表示になった時にダウンロードに使ったURLDownloadをリリースしている。
- (void)dismissActionSheet { if (actionSheet) { [actionSheet dismissWithClickedButtonIndex:-1 animated:YES]; } } - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { [self releaseDownloader]; } - (void)releaseDownloader { [downloaderLock lock]; if (downloader != nil) { [downloader release]; downloader = nil; } [[NSFileManager defaultManager] clearTmpDirectory]; [downloaderLock unlock]; }
途中キャンセルもできる。
// なぜかactionSheetCancelが呼ばれないので、こちらで代用 - (void)actionSheet:(UIActionSheet *)sheet clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex == sheet.cancelButtonIndex) { [downloader cancel]; } }