【问题标题】:Memory management with Photos framework使用照片框架进行内存管理
【发布时间】:2017-02-18 14:32:29
【问题描述】:

我在从 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 的框架。 当我调用此方法时,我的内存负载很重。如果我多次调用它,我可以在 Instruments 中看到 PHAsset 继续增加而没有释放任何东西。我想到了autoreleasepool,但我不确定如何正确使用它。你有什么建议或类似的吗?最后一件事是,即使在由于内存负载过重而不断崩溃的 Today Widget 中,我也需要使用它。

【问题讨论】:

  • 我读过一次nshipster.com/phimagemanager。可能对你有用。
  • @RajanMaheshwari 我已经读过那篇文章,很有趣,但它对这种情况没有帮助。
  • 尽量减少可能的故障点。在没有 Async 框架的情况下直接使用 GCD 时是否会出现相同的行为?
  • @xpereta 已经尝试过了,同样的事情发生了。奇怪的是,即使在图像数据被下载并显示为 UIImage 对象之后,内存仍在增加(在语音下:“All Heap Allocations”)
  • PHAsset 是一个非常小的对象(它不包含照片或类似的东西)。那么这真的很重要吗?

标签: ios swift image memory photos


【解决方案1】:

请注意,您正在使用异步调用 requestImageData 的选项:

isSynchronous = false

您可能不需要,因为调用代码已经在后台线程中。

这也意味着结果处理程序可能会被多次调用。结合 isNetworkAccessAllowed 选项可能会延迟请求的完成和 PHAsset 实例的释放。

尝试:

isSynchronous = true
isNetworkAccessAllowed = false

【讨论】:

    猜你喜欢
    • 2014-11-28
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多