画像を非同期でダウンロードし、UITableView に表示しています。イメージのダウンロード中、対応するテーブル行に UIProgressView が表示されます。ダウンロードが完了すると、進行状況ビューが実際のイメージに置き換えられます。
私のテーブル ビューでは、UITableViewCell からサブクラス化された ProgressTableViewCell というカスタム セルを使用しています。UIProgressView IBOutlet があります。
NSURLConnection から NSOperation を作成し、それらを NSOperationQueue に追加しました。代表として
didReceiveData
メソッドが呼び出されると、テーブルビューコントローラーに通知が投稿され、対応するテーブル行が更新されます
reloadRowsAtIndexPaths
テーブルビューの方法。私の cellForRowAtIndexPath は、リロードされた行に対して次のことを行います。
ProgressTableViewCell *cell = (ProgressTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"ProgressCell"];
float received = [[downloadInfo objectForKey:@"receivedBytes"] floatValue];
float total = [[downloadInfo objectForKey:@"totalFileSize"] floatValue];
NSNumber* percentage= [NSNumber numberWithFloat:received/total];
NSMutableDictionary* userInfo = [[NSMutableDictionary alloc] init];
NSLog(@"percentage %f", percentage.floatValue);
[userInfo setObject:cell forKey:@"cell"];
[userInfo setObject:percentage forKey:@"percentage"];
[self performSelectorOnMainThread:@selector(updateProgressView:) withObject:userInfo waitUntilDone:NO];
NSLog(@"received: %@", [downloadInfo objectForKey:@"receivedBytes"]);
NSLog(@"Progress: %f", cell.progressView.progress);
return cell;
updateProgressView メソッドは次のようになります
- (void)updateProgressView :(NSMutableDictionary *)userInfo
{
ProgressTableViewCell* cell = [userInfo valueForKey:@"cell"];
NSNumber* progress = [userInfo valueForKey:@"percentage"];
[cell.progressView setProgress:progress.floatValue ];
NSLog(@"Progress after update: %f", cell.progressView.progress);
}
メイン スレッドの進行状況ビューを更新しています。waitUntilDone を YES に設定しようとしましたが、役に立ちませんでした。私の進行状況ビューはゼロ点のままです。時折、デバッグ中に進行状況インジケーターに変化が見られ、タイミングの問題ではないかと思われることがあります。しかし、それを解決する方法は?
編集: NSURLConnection デリゲートの didReceiveData メソッドは次のとおりです。
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_responseData appendData:data];
NSNumber* bytes = [NSNumber numberWithUnsignedInt:[data length]];
NSLog(@"received bytes:%d", [bytes intValue] );
NSMutableDictionary* userInfo = [[NSMutableDictionary alloc] init];
[userInfo setObject:_responseId forKey:@"responseId"];
[userInfo setObject:bytes forKey:@"receivedBytes"];
[self fireNotification: [NSNotification
notificationWithName:@"DidReceiveData"
object:self userInfo:userInfo]];
}
- (void)fireNotification :(NSNotification *)aNotification
{
[[NSNotificationCenter defaultCenter] postNotification:aNotification];
}
そして、通知を受け取るView Controllerのメソッドは次のとおりです。
-(void) dataReceived:(NSNotification *)notification {
NSNumber* responseId = [[notification userInfo] objectForKey:@"responseId"];
NSNumber* bytes = [[notification userInfo] objectForKey:@"receivedBytes"];
NSMutableDictionary* downloadInfo = [self getConnectionInfoForId:responseId];
NSLog(@"received bytes:%ld for response %@", [bytes longValue], responseId );
NSNumber* totalBytes = [NSNumber numberWithInt:([bytes longValue] + [[downloadInfo objectForKey:@"receivedBytes"] longValue]) ];
[downloadInfo setObject:totalBytes forKey:@"receivedBytes"];
float received = [[downloadInfo objectForKey:@"receivedBytes"] floatValue];
float total = [[downloadInfo objectForKey:@"totalFileSize"] floatValue];
[downloadInfo setObject:[NSNumber numberWithFloat:received/total] forKey:@"progress"];
[self reloadRowForResponse:responseId];
}
また、推奨されるように cellForRowAtIndexpath メソッドに nil チェックを追加しました。
ProgressTableViewCell *cell = (ProgressTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"ProgressCell"];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ProgressCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
float received = [[downloadInfo objectForKey:@"receivedBytes"] floatValue];
float total = [[downloadInfo objectForKey:@"totalFileSize"] floatValue];
NSNumber* percentage= [NSNumber numberWithFloat:received/total];
NSMutableDictionary* userInfo = [[NSMutableDictionary alloc] init];
NSLog(@"cell:%@", cell);
NSLog(@"percentage %f", percentage.floatValue);
[userInfo setObject:cell forKey:@"cell"];
[userInfo setObject:percentage forKey:@"percentage"];
[self performSelectorOnMainThread:@selector(updateProgressView:) withObject:userInfo waitUntilDone:NO];
return cell;