ALAssetsLibrary assetsForURL: всегда возвращает ноль для фотографий в My Photo Stream в iOS 8.1

Этот код отлично работал в iOS 7, но в iOS 8.1 все активы, расположенные в альбоме «Мой фотопоток», нулевые в блоке результатов. (FaultBlock не вызывается.) Обычные альбомы и общие альбомы работают нормально.

Я попробовал принятый ответ из: Ошибка при попытке назначение __block ALAsset изнутри assetsForURL:resultBlock:

То есть я держу ссылку на объект ALAssetsLibrary, слушая событие ALAssetsLibraryChangedNotification (которого не происходит, кстати, ну да ладно.) Я убедился, что у моего приложения есть разрешение на доступ к фотографиям, я нахожусь в сети wi-fi. , я прекрасно вижу миниатюры фотографий в своем tableView. Просто когда я пытаюсь загрузить их с помощью assetForURL:, они всегда равны нулю.

// example URL: assets-library://asset/asset.JPG?id=1ECB69B9-DC7A-45A7-B135-F43317D3412C&ext=JPG
[self.library assetForURL:[NSURL URLWithString:url] resultBlock:^(ALAsset *asset) {
    NSLog(@"Asset: %@", asset); // nil :(
} failureBlock:^(NSError *error) {
    NSLog(@"Failure, wahhh!");
}];

Кто-нибудь еще видит эту проблему?


person taber    schedule 21.10.2014    source источник


Ответы (5)


У меня такая же проблема. В данный момент я не могу переключиться на фреймворк для фотографий, но, к счастью, я нашел обходной путь. Вы можете найти его большим уродством, и я подозреваю, что он может работать медленно, когда Photo Stream содержит много фотографий, но это лучше, чем ничего.

Идея состоит в том, чтобы перечислить все элементы в группе активов Photo Stream и сравнить необходимый URL-адрес с URL-адресом каждого элемента. К счастью, он все еще работает.

У меня есть такой метод (библиотека - это свойство ALAssetsLibrary того же класса, вам может потребоваться инициализировать его внутри этого кода):

- (void)loadItem:(NSURL *)url withSuccessBlock:(void (^)(void))successBlock andFailureBlock:(void (^)(void))failureBlock {

[library assetForURL:url
        resultBlock:^(ALAsset *asset)
        {
            if (asset){
                //////////////////////////////////////////////////////
                // SUCCESS POINT #1 - asset is what we are looking for 
                //////////////////////////////////////////////////////
                successBlock();
            }
            else {
                // On iOS 8.1 [library assetForUrl] Photo Streams always returns nil. Try to obtain it in an alternative way

                [library enumerateGroupsWithTypes:ALAssetsGroupPhotoStream
                                       usingBlock:^(ALAssetsGroup *group, BOOL *stop)
                 {
                     [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
                         if([result.defaultRepresentation.url isEqual:url])
                         {
                             ///////////////////////////////////////////////////////
                             // SUCCESS POINT #2 - result is what we are looking for
                             ///////////////////////////////////////////////////////
                             successBlock();
                             *stop = YES;
                         }
                     }];
                 }

                                     failureBlock:^(NSError *error)
                 {
                     NSLog(@"Error: Cannot load asset from photo stream - %@", [error localizedDescription]);
                     failureBlock();

                 }];
            }

        }
        failureBlock:^(NSError *error)
        {
            NSLog(@"Error: Cannot load asset - %@", [error localizedDescription]);
            failureBlock();
        }
  ];
}

Надеюсь это поможет.

person Andrew Simontsev    schedule 23.10.2014
comment
Хотя это и не идеально, это действительно помогает, большое спасибо! Чтобы не быть слишком придирчивым, но похоже, что item.url должно быть просто url верно? И нам, вероятно, потребуется вызвать блок успеха, который передается в ALAsset. Еще раз спасибо! - person taber; 23.10.2014
comment
У меня есть одна и та же проблема как для Moment, так и для My Photo Stream, хотя приведенное выше решение не работает... перечисление групп ничего не дает... даже если я изменю ALAssetsGroupPhotoStream на ALAssetsGroupAll - person AkademiksQc; 23.10.2014
comment
странно, здесь сработало - вы уверены, что разрешили фото? - person taber; 23.10.2014
comment
@taber Вы правы! Я скопировал его из своего проекта, и этот код был слишком сложным. Я забыл там переименовать item.url и пропустил код successBlock, когда вставил комментарий SUCCESS POINT. Я отредактировал свой ответ и исправил ошибки. - person Andrew Simontsev; 25.10.2014
comment
Это решение не работает и для меня, так как актив также равен нулю в точке успеха № 2. - person Anas; 29.10.2014
comment
@anas, в ТОЧКЕ УСПЕХА № 2 он достигает переменной result, а не asset. - person Andrew Simontsev; 30.10.2014
comment
Где мы используем этот метод. ?? - person Sushil Sharma; 07.01.2015
comment
Вы можете просто добавить его как частный метод в класс, где вам нужно загрузить изображение из библиотеки ресурсов и вызвать его вместо активаForURL. Требуемый ресурс может появиться в двух местах, отмеченных здесь как ТОЧКА УСПЕХА №1 (в переменной актива) и ТОЧКА УСПЕХА №2 (в переменной результата). Я думаю, что имеет смысл немного изменить этот код и передать актив/результат в successBlock. Но это зависит от вас. - person Andrew Simontsev; 08.01.2015

Я заметил, что попытка получить актив с помощью assetsForURL внутри блока успеха writeImage toSavedPhotosAlbum для того же самого актива приведет к нулевому активу (в большинстве случаев).

Однако получение актива с помощью assetsForURL спустя некоторое время после завершения выполнения блока writeImage, действительно дает правильный актив.

Ожидание в течение 1 секунды сработало, а ожидание всего в 300 мс — нет. Но это, конечно, будет отличаться для каждого устройства и ситуации.

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

person Thomas Hilbert    schedule 28.11.2017
comment
Возникла та же проблема. Несмотря на то, что запись успешно разрешилась, она возвращает nil в запросе assetsForURL. Интересно, что происходит на самом деле. - person rsiemens; 31.01.2018

Начиная с iOS 8.0 и более поздних версий, Apple предлагает использовать фреймворк Photos вместо фреймворка Assets Library.

введите здесь описание изображения

person Ratan    schedule 21.10.2014
comment
Это не говорит, что мы «должны использовать» Photos.framework. Просто скажите нам, что это способ доступа к изображениям в будущем. - person herzi; 30.08.2015

Протестировано с iPad mini на iOS 8.1, вот как вы должны это делать с новым Фоторамка:

NSURL *url = /* your asset url from the old ALAsset library prior to iOS 8 */
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsWithALAssetURLs:@[url]
                                                               options:nil];
assert(assets.count == 1);
PHAsset *asset = assets.firstObject;

[[PHImageManager defaultManager] requestImageForAsset:asset
                   targetSize:CGSizeMake(800, 800) // TODO: your target size
                  contentMode:PHImageContentModeDefault
                      options:nil
                resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info)
 {
     // Do whatever you want to the result
 }];
person Yuchen    schedule 18.02.2016

Не найдя нигде ответов на этот вопрос, я создал следующее расширение для PHAsset, которое отлично работает с iOS 8.2, хотя я предполагаю, что теоретически оно медленное. Несмотря на то, что в одном из предыдущих комментариев говорится, что это исправлено в бета-версии iOS8.2, ошибка все еще присутствует для меня сейчас, когда выпущена iOS8.2.

import Photos
import UIKit

extension PHAsset {
    class func fetchAssetWithALAssetURL (alURL: NSURL) -> PHAsset? {
        let phPhotoLibrary = PHPhotoLibrary.sharedPhotoLibrary()
        let assetManager = PHImageManager()
        var phAsset : PHAsset?

        let optionsForFetch = PHFetchOptions()
        optionsForFetch.includeHiddenAssets = true

        var fetchResult = PHAsset.fetchAssetsWithALAssetURLs([alURL], options: optionsForFetch)
        if fetchResult?.count > 0 {
            return fetchResult[0] as? PHAsset
        } else {
            var str = alURL.absoluteString!
            let startOfString = advance(find(str, "=")!, 1)
            let endOfString = advance(startOfString, 36)
            let range = Range<String.Index>(start:startOfString, end:endOfString)
            let localIDFragment = str.substringWithRange(range)
            let fetchResultForPhotostream = PHAssetCollection.fetchAssetCollectionsWithType(PHAssetCollectionType.Album, subtype: PHAssetCollectionSubtype.AlbumMyPhotoStream, options: nil)
            if fetchResultForPhotostream?.count > 0 {
                let photostream = fetchResultForPhotostream![0] as PHAssetCollection
                let fetchResultForPhotostreamAssets = PHAsset.fetchAssetsInAssetCollection(photostream, options: optionsForFetch)
                if fetchResultForPhotostreamAssets?.count >= 0 {
                    var stop : Bool = false
                    for var i = 0; i < fetchResultForPhotostreamAssets.count && !stop; i++ {
                        let phAssetBeingCompared = fetchResultForPhotostreamAssets[i] as PHAsset
                        if phAssetBeingCompared.localIdentifier.rangeOfString(localIDFragment, options: nil, range: nil, locale: nil) != nil {
                            phAsset = phAssetBeingCompared
                            stop = true
                        }
                    }
                    return phAsset
                }
            }
            return nil
        }
    }
}
person Diego Rebosio    schedule 17.03.2015