2012-05-17 2 views
10

Часть моего приложения имеет браузер фотографий, несколько похожий на приложение Apple's Photos, с начальным контроллером просмотра для просмотра миниатюр фотографий и подробного представления, которое отображается при нажатии на фотографию.ALAssetsLibrary - авария после получения ALAssetsLibraryChangedNotification

Я использую ALAssetsLibrary для доступа к фотографиям, и я передаю массив URL-адресов ALAsset на мой контроллер подробного представления, чтобы вы могли прокручивать с одной фотографии на другую.

Все прекрасно работает, пока не получит ALAssetsLibraryChangedNotification в то время как ударяя от одной фотографии к другой (в контроллере представления подробно), что часто приводит к аварии:

УВЕДОМЛЕНИЕ: библиотека активов изменилась // мой собственный NSLog когда уведомление происходит

загрузки активов ... // моя NSLog, когда я начинал перезагружаться активов в браузер миниатюр

Assertion не удалось: (размер == BytesRead), функция - [ALAssetRepresentation _imageData], файл /SourceCache/AssetsLibrary/MobileSlideShow-1373.58.1/Sources/ALAssetRepresentation.m, линия 224.

Конкретная строка кода он падает дальше, в вызов [currentRep метаданные], как показано здесь:

- (void)someMethod { 
     NSURL *assetURL = [self.assetURLsArray objectAtIndex:index]; 
     ALAsset *currentAsset; 

     [self.assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) { 

      [self performSelectorInBackground:@selector(configureDetailViewForAsset:) withObject:asset]; 

      } failureBlock:^(NSError *error) { 
        NSLog(@"failed to retrieve asset: %@", error); 
     }]; 
} 

- (void)configureDetailViewForAsset:(ALAsset *)currentAsset { 
    ALAssetRepresentation *currentRep = [currentAsset defaultRepresentation]; 

    if (currentAsset != nil) { 
     // do some stuff 
    } 
    else { 
     NSLog(@"ERROR: currentAsset is nil"); 
    } 

    NSDictionary *metaDictionary; 
    if (currentRep != nil) { 
     metaDictionary = [currentRep metadata]; 

     // do some other stuff 
    } 
    else { 
     NSLog(@"ERROR: currentRep is nil"); 
    } 
} 

Я понимаю, что когда-то уведомление будет получено, оно аннулирует любые ссылки на ALAsset и ALAssetRepresentation объекты ... но как я должен иметь дело с ситуацией, когда он аннулирует что-то прямо в середине пытается получить к нему доступ?

Я попытался установить логическое значение, право при получении уведомления, чтобы полностью прекратить и предотвратить [currentRep метаданные] из когда-либо называется, но даже это не поймать его каждый раз:

if (self.receivedLibraryChangeNotification) { 
    NSLog(@"received library change notification, need to abort"); 
} 
else { 
    metaDictionary = [currentRep metadata]; 
} 

Is что я могу сделать? На этом этапе я почти готов отказаться от использования структуры ALAssetsLibrary.

(обратите внимание на эту неразрешенную нить на Девых форумах Apple, описывающих один и тот же вопрос: https://devforums.apple.com/message/604430)

ответ

6

Кажется, проблема находится здесь:

[self.assetsLibrary assetForURL:nextURL 

    resultBlock:^(ALAsset *asset) { 
     // You should do some stuff with asset at this scope 
     ALAssetRepresentation *currentRep = [asset defaultRepresentation]; 
     // Assume we have a property for that 
     self.assetRepresentationMetadata = [currentRep metadata]; 
     ... 
     // assume we have a method for that 
     [self updateAssetDetailsView]; 
    } 

    failureBlock:^(NSError *error) { 
     NSLog(@"failed to retrieve asset: %@", error); 
    }]; 

После того, как вы получили пользовательский актив лучше копировать информацию об активах, предоставляя необходимые данные для просмотра данных вашего контроллера или путем кэширования для последующего использования. Это может быть полезно для предотвращения проблем с недействительностью ALAsset. При отправке уведомления ALAssetsLibraryChangedNotification вам может потребоваться отменить контроллер детали и запросить содержимое библиотеки с самого начала.

+1

Я должен сделать больше испытаний ... но это, возможно, помогло. Это не показано в моем коде выше (так как я хотел упростить его для публикации здесь), но [текущийRep метаданных] вызывается в фоновом потоке. Я изменил это, чтобы вместо этого найти словарь метаданных внутри «resultForURL» resultBlock, как вы предполагали, который находится в основном потоке. Он пока не разбился ... возможно, метод метаданных ALAssetRepresentation не является потокобезопасным? –

+0

Самое главное здесь, что для получения средств массовой информации требуется время «assetForURL». Поэтому за пределами блока завершения вы не можете быть уверены, что у вас загружен медиа ... – voromax

+0

Я обновил свой вопрос, чтобы точно показать, как я называл метод «метаданных» в фоновом потоке. Основываясь на вашем ответе, я изменил его, чтобы сначала получить словарь метаданных, а затем передать и это, и свой актив в мой метод configureDetailView. Опять же, мне нужно сделать больше тестов, но пока так хорошо ... –

Смежные вопросы