Управление памятью с помощью фреймворка Photos

#ios #swift #image #memory #photos

#iOS #swift #изображение #память #Фото

Вопрос:

У меня проблемы с памятью при извлечении объектов из фреймворка Photos в iOS. Я показываю вам свой код :

 public class func randomImageFromLibrary(
        completion: @escaping (_ error: ImageProviderError?, _ image: UIImage?, _ creationDate: Date?, _ location: CLLocation?) -> Void) {

        // Create the fetch options sorting assets by creation date
        let fetchOptions = PHFetchOptions.init()
        fetchOptions.sortDescriptors = [ NSSortDescriptor.init(key: "creationDate", ascending: true) ]
        fetchOptions.predicate = NSPredicate.init(format: "mediaType == (PHAssetMediaType.image)")

        DispatchQueue.global(qos: .userInitiated).async {

            let fetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: nil)

            if fetchResult.count == 0 {

                // The restoreAnimationAfterFetching method contains UI changes, this is why
                // we perform this code on the main thread
                Async.main({

                    print("No photos in the library!")

                    completion(.PhotoLibraryEmpty, nil, nil, nil)
                })

                return
            }

            var photos: [PHAsset] = []

            // Enumerate the PHAssets present in the array and move everything to the photos array
            fetchResult.enumerateObjects({ (object: PHAsset, index, stop: UnsafeMutablePointer<ObjCBool>) in
                //let asset = object
                photos.append(object)
            })


            let asset = photos[0] // This could be any number, 0 is only a test

            // The options for the image request
            // We want the HQ image, current version (edited or not), async and with the possibility to access the network
            let options = PHImageRequestOptions.init()
            options.deliveryMode = PHImageRequestOptionsDeliveryMode.highQualityFormat
            options.version = PHImageRequestOptionsVersion.current
            options.isSynchronous = false
            options.isNetworkAccessAllowed = true

            PHImageManager.default().requestImageData(
                for: asset,
                options: options,
                resultHandler: { (imageData: Data?, dataUTI: String?, orientation: UIImageOrientation, info: [AnyHashable : Any]?) in

                    // If the image data is not nil, set it into the image view
                    if (imageData != nil) {

                        Async.main({

                            // Get image from the imageData
                            let image = UIImage.init(data: imageData!)

                            completion(nil, image, asset.creationDate, asset.location)
                        })
                    } else {

                        // TODO: Error retrieving the image. Show alert
                        print("There was an error retrieving the image! n(info![PHImageErrorKey])")

                        completion(.GenericError, nil, nil, nil)
                    }
                }
            )
            }
        }
  

Async — это фреймворк для простого управления GCD .
Когда я вызываю этот метод, у меня большая нагрузка на память. Если я вызываю его несколько раз, я вижу PHAsset в инструментах, которые продолжают увеличиваться, ничего не выпуская. Я думал о autoreleasepool , но я не уверен, как правильно его использовать. У вас есть какие-либо предложения или что-то в этом роде? Последнее, что мне нужно использовать это даже в виджете Today, который постоянно падает из-за большой нагрузки на память.

Комментарии:

1. Я прочитал это однажды nshipster.com/phimagemanager . может быть, это вам пригодится.

2. @RajanMaheshwari Я уже читал эту статью, интересно, но в данном случае это не помогает.

3. Постарайтесь уменьшить возможные точки отказа. Происходит ли такое же поведение при использовании GCD напрямую без Async framework?

4. @xpereta уже пробовал, произошло то же самое. Странно то, что даже после того, как данные изображения были загружены и отображены в виде объекта UIImage, объем памяти продолжает увеличиваться (под голосом: «Все выделения кучи»)

5. PHAsset — это очень маленький объект (он не содержит фотографии или чего-то подобного). Так действительно ли это важно?

Ответ №1:

Обратите внимание, что вы используете опцию для асинхронного вызова requestImageData:

 isSynchronous = false
  

который вам, вероятно, не нужен, потому что вызывающий код уже находится в фоновом потоке.

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

Попробуйте с:

 isSynchronous = true
isNetworkAccessAllowed = false