Пользовательский интерфейс блокируется при получении продолжительности видео из AVURLAsset в dispatch_async

У меня есть 2 контроллера просмотра Home и Home Details. В Home у меня есть табличное представление, в котором я показываю миниатюру и продолжительность видео. Когда я нажимаю на определенную строку, ее детали отображаются в разделе «Главная». Вернувшись назад, я обновляю выбранную строку. Итак, для этого в методе viewWillDisappear Home Details я написал следующий код:

if ([self.delegate respondsToSelector:@selector(changeSelectedBucketData:)]) {
        [self.delegate changeSelectedBucketData:_videoId];
    } 

Теперь в домашнем контроллере я определил этот метод как:

-(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. Он блокируется только тогда, когда я вызываю его из дома.


person Swati Gupta    schedule 21.09.2016    source источник
comment
Метод changeSelectedBucketData выглядит так, как будто он вызывается в основном потоке, что означает, что ваш запрос на получение задерживает поток пользовательского интерфейса.   -  person Stonz2    schedule 21.09.2016
comment
Я пробовал это, но это не помогает. if ([self.delegate responsesToSelector:@selector(changeSelectedBucketData:)]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self.delegate changeSelectedBucketData:_videoId]; }); }   -  person Swati Gupta    schedule 21.09.2016


Ответы (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);
        }
    }];
}
person Rhythmic Fistman    schedule 23.09.2016