Пользовательский интерфейс блокируется при получении продолжительности видео из AVURLAsset в dispatch_async
У меня есть 2 View Controllers Home и Home Details. В Home у меня есть табличное представление, в котором я показываю миниатюру и продолжительность видео. Когда я нажимаю на конкретную строку, ее детали отображаются в разделе "Домашняя страница". Вернувшись назад, я обновляю выбранную строку. Итак, для этого в viewWillDisappear Method of Home Details я написал следующий код:
if ([self.delegate respondsToSelector:@selector(changeSelectedBucketData:)]) {
[self.delegate changeSelectedBucketData:_videoId];
}
Теперь в Home Controller я определил этот метод как:
-(void)changeSelectedBucketData:(NSString*)videoId {
NSString *dataStr = [NSString stringWithFormat:@"%@bucket_id=%@",kGetBucketById,videoId];
[[WebServiceCall sharedInstance] sendGetRequestToWebWithData:dataStr success:^(NSDictionary *json) {
if([[json valueForKey:@"ResponseCode"] integerValue] == 0) {
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[_arrayOfContent replaceObjectAtIndex:selectedIndex withObject:[json valueForKey:@"GetData"]];
if (_arrayOfContent.count) {
TableViewCellHome *cell = [self.mTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:selectedIndex inSection:0]];
[self fillDataForIndexPath:[NSIndexPath indexPathForRow:selectedIndex inSection:0] forCell:cell];
}
});
}
} failure:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
});
}];
}
-(void)fillDataForIndexPath:(NSIndexPath*)indexPath forCell:(TableViewCellHome*)cell{
NSDictionary *dict = [_arrayOfContent objectAtIndex:indexPath.row];
NSURL *url = [NSURL URLWithString:[[_arrayOfContent objectAtIndex:indexPath.row] valueForKey:@"video_URL"]];
[self downloadDurationAtURL:url cellTag:indexPath];
}
Теперь я использовал следующий код для загрузки продолжительности видео:
- (NSUInteger)videoDuration:(NSURL *)videoURL {
AVURLAsset *videoAVURLAsset = [AVURLAsset assetWithURL:videoURL];
CMTime durationV = videoAVURLAsset.duration;
return CMTimeGetSeconds(durationV);
}
- (NSString *)videoDurationTextDurationTotalSeconds:(NSUInteger)dTotalSeconds {
NSUInteger dHours = floor(dTotalSeconds / 3600);
NSUInteger dMinutes = floor(dTotalSeconds % 3600 / 60);
NSUInteger dSeconds = floor(dTotalSeconds % 3600 % 60);
if (dHours > 0) {
return [NSString stringWithFormat:@"%i:%02i:%02i",dHours, dMinutes, dSeconds];
} else {
return [NSString stringWithFormat:@"%02i:%02i",dMinutes, dSeconds];
}
}
-(void)downloadDurationAtURL:(NSURL *)videoURL cellTag:(NSIndexPath*)indexPath {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//retrive image on global queue
NSUInteger dTotalSeconds = [self videoDuration:videoURL];
NSLog(@"dTotalSeconds %i",dTotalSeconds);
if (dTotalSeconds > 0) {
NSString *videoDurationText = [self videoDurationTextDurationTotalSeconds:dTotalSeconds];
dispatch_async(dispatch_get_main_queue(), ^{
TableViewCellHome *cell = [self.mTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
[[_arrayOfContent objectAtIndex:indexPath.row] setObject : videoDurationText forKey:@"duration"];
cell.labelDuration.text = videoDurationText;
cell.labelDuration.hidden = false;
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
TableViewCellHome *cell = [self.mTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
[[_arrayOfContent objectAtIndex:indexPath.row] setObject : @"" forKey:@"duration"];
cell.labelDuration.hidden = true;
cell.labelDuration.text = @"";
});
}
});
}
Теперь проблема в том, что пользовательский интерфейс блокируется, пока продолжительность в ячейке не изменится. Я не могу выбрать конкретную строку, пока продолжительность не отображается в ячейке. Но он работает нормально, когда я впервые отображаю контроллер Home после вызова API. Он блокируется только тогда, когда я звоню из Home детали.
1 ответ
Вам нужно загрузить продолжительность асинхронно, например так:
- (void)videoDuration:(NSURL *)videoURL completion:(void (^)(CMTime))durationCallback {
AVURLAsset *videoAVURLAsset = [AVURLAsset assetWithURL:videoURL];
[videoAVURLAsset loadValuesAsynchronouslyForKeys:@[ @"duration"] completionHandler:^{
NSError *error;
if([videoAVURLAsset statusOfValueForKey:@"duration" error:&error]) {
NSLog(@"error getting duration: %@", error);
durationCallback(kCMTimeZero); // or something
} else {
durationCallback(videoAVURLAsset.duration);
}
}];
}