2015-09-16 11 views
0

Я инициализирую AVPlayerItem с помощью метода initWithUrl:.Как восстановить AVPlayerItem?

Проблема в том, что при инициализации прерывается (например, соединение потеряно)

Допустим, мы имеем следующие:

self.avPlayerItem = [[AVPlayerItem alloc] initWithUrl:url]; 

1. Что должно быть сделано? Что происходит с экземпляром avPlayerItem, когда соединение потеряно между тем? Есть ли какой-то протокол для реализации, чтобы определить, была ли инициализация успешной или нет?

2. То, что я заметил, что когда-то инициализация прерывается, то следующий «успешный» инициализация avPlayerItem не имеет следов на всех (они присутствуют, когда никакого перерыва не сделано раньше) Чтобы снова инициализировать avPlayerItem с треками от пользователя-источника требуется закрыть и открыть приложение снова.

ответ

1

При работе с кодом, основанным на подключении к Интернету, вы должны убедиться, что есть сбои, которые срабатывают, когда что-то пойдет не так, потому что в какой-то момент это произойдет.

Что делать?

1) Выполните весь код, основанный на подключении к Интернету на фоновом потоке. Вы не хотите блокировать пользовательский интерфейс.

2) Если возможно, проверьте загруженный файл перед использованием.

Есть разные способы обойти это, но с верхней части головы. Думаю, я бы использовал NSURLConnection или аналогичный API для загрузки файла во временную папку. НА ПРЕДПОСЫЛКИ.

При загрузке я инициализировал AVAsset с использованием временного URL-адреса. AVAsset имеет несколько хороших свойств, таких как playable, которые помогут вам проверить, что файл загружен ОК. (NSURLConnectionDelegate также имеет метод, который уведомляет, была ли ошибка загрузки.)

Если у вас есть это, то вы можете создать AVPlayerItem с AVAsset и прочь от вас. Не забудьте в какой-то момент стереть содержимое вашей временной папки, если вы не наведете на загруженный контент.

Помните, что вы хотите играть в основной файл, но все остальные загрузки и проверки, вероятно, лучше всего делать на фоне потока; вы определенно хотите использовать NSURLConnection из фоновой темы.

+0

спасибо за большой ответ. Я использую GCD для загрузки файла. 'dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{...' Я попытался использовать '[AVURLAsset initWithUrl: options:]', и я попытался инициализировать AVPlayerItem этим ресурсом. Элемент инициализирован, но по-прежнему не имеет треков. Вероятно, я не очищаю экземпляр должным образом, но я вижу в коде, что все наблюдатели удалены, и avplayeritem (также avplayer.currentitem и т. Д.) Установлены на нуль, когда что-то пойдет не так.) – travdu

+0

'AVAsset' имеет свойство' track' так что вы можете получить информацию о предыстории. Поэтому, если вы ожидаете 2 трека, и вы получите 1, вы знаете, что что-то пошло не так. Я ожидаю, что в процессе инициализации произошла ошибка, и поэтому у вас есть проблемы. Либо это, либо вы загрузили поврежденный файл. –

+0

Я ожидаю один трек, и я получаю 0. Файл в порядке, потому что, когда я запускаю приложение и пытаюсь снова получить тот же файл, все работает нормально. У меня проблема только в том случае, если initWithUrl прерван с потерей соединения. Затем каждый раз после прерывания я получаю 0 треков, даже когда вы присоединяетесь к другим файлам. Как я говорю. Когда соединение не теряется во время init, все работает отлично, а также при обращении к другим файлам позже. – travdu

0

Сначала сохраните объект AVPlayerItem в объекте NSPurgeableData и играйте с ним; хранить объект данных в объекте NSCache, чтобы автоматически вытеснять объект из памяти после его воспроизведения или когда соединение отбрасывается, а прежний элемент AVPlayerItem заменяется новым (все эти вещи, которые вы должны делать в любом случае, независимо от того, конкретную проблему, которую вы описываете).Вот код, чтобы вы начали:

void (^cachePlayerItem)(AVPlayerItem *, NSCache *, NSString *) = ^(AVPlayerItem *playerItem, NSCache *cache, NSString *key) { 
    NSURL *fileURL = [(AVURLAsset *)playerItem.asset URL]; 
    NSPurgeableData *data = [NSPurgeableData dataWithContentsOfURL:fileURL]; 
    [data beginContentAccess]; 
    [cache setObject:data forKey:key]; 
    [data endContentAccess]; 
    [data discardContentIfPossible]; 
}; 

Поместите этот блок в любом месте в файле реализации, определив его в файле заголовка с:

typedef void (^cachePlayerItemBlock)(AVPlayerItem *, NSCache *, NSString *); 

Называйте это в методе с:

cachePlayerItem(playerItem, playerItems, phAsset.localIdentifier); 

Принимая во внимание, что playerItem является элементом AVPlayerItem, playerItems является кешем NSCache и, в зависимости от того, какой вид актива, из которого вы приобретаете AVPlayerItem, уникальным для него идентификатором (или, в приведенном выше примере, связанный с ним актив).

Кстати, я создал свои кэши в AppDelegate соответственно:

- (NSCache *)thumbnailCache { 
    __block NSCache *t = self->_thumbnailCache; 
    if (!t) { 
     t = [[NSCache alloc] init]; 
     [t setName:@"Thumbnail Cache"]; 
     [t setEvictsObjectsWithDiscardedContent:TRUE]; 
     [t setCountLimit:self.assetsFetchResults.count]; 
     self->_thumbnailCache = t; 
    } 
    return t; 
} 

Это обеспечивает не только глобальный доступ, но и один экземпляр, кэш, что особенно важно, когда кэширование AVPlayerItems как они могут быть большого размера.

Для создания глобально доступного кэша в AppDelegate, добавить их в ваш заголовок и реализации файлов, соответственно:

+ (AppDelegate *)sharedAppDelegate; 

... и:

+ (AppDelegate *)sharedAppDelegate 
{ 
    return (AppDelegate *)[[UIApplication sharedApplication] delegate]; 
} 

Для ссылки на кэш в другом классе файлы, импортировать заголовочный файл AppDelegate и, при желании, создать ярлык для метода sharedApplication приложения AppDelegate:

#import "AppDelegate.h" 

#define AppDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate]) 

Insodoing, кэш может ссылаться ...:

AppDelegate.thumbnailCache 

... вместо:

AppDelegate.sharedAppDelegate.thumbnailCache 
Смежные вопросы