Ios 基于照片框架的内存管理

Ios 基于照片框架的内存管理,ios,swift,image,memory,photos,Ios,Swift,Image,Memory,Photos,在iOS中从照片框架检索对象时出现内存问题。我向您展示我的代码: public class func randomImageFromLibrary( completion: @escaping (_ error: ImageProviderError?, _ image: UIImage?, _ creationDate: Date?, _ location: CLLocation?) -> Void) { // Create the fetch opti

在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)
                    }
                }
            )
            }
        }
公共类func randomImageFromLibrary(
完成:@转义(\uError:ImageProviderError?,\uImage:UIImage?,\uCreationDate:Date?,\uLocation:CLLocation?->Void){
//创建按创建日期排序资产的获取选项
让fetchOptions=PHFetchOptions.init()
fetchOptions.sortDescriptors=[NSSortDescriptor.init(键:“creationDate”,升序:true)]
fetchOptions.predicate=NSPredicate.init(格式:“mediaType==\(PHAssetMediaType.image)”)
DispatchQueue.global(qos:.userInitiated).async{
让fetchResult=PHAsset.fetchAssets(带:PHAssetMediaType.image,选项:nil)
如果fetchResult.count==0{
//restoreAnimationAfterFetching方法包含UI更改,这就是原因
//我们在主线程上执行此代码
Async.main({
打印(“库中没有照片!”)
完成(.PhotoLibraryEmpty,nil,nil,nil)
})
返回
}
var照片:[PHAsset]=[]
//枚举阵列中存在的相集,并将所有内容移动到照片阵列中
fetchResult.enumerateObjects({(对象:PHAsset,index,stop:UnsafemeutablePointer)在
//让资产=对象
照片。附加(对象)
})
let asset=photos[0]//这可以是任何数字,0只是一个测试
//图像请求的选项
//我们希望HQ图像,当前版本(编辑或未编辑),异步,并有可能访问网络
let options=PHImageRequestOptions.init()
options.deliveryMode=PhImageRequestOptions deliveryMode.highQualityFormat
options.version=PHImageRequestOptionsVersion.current
options.isSynchronous=false
options.isNetworkAccessAllowed=true
PHImageManager.default().requestImageData(
用途:资产,
选项:选项,
resultHandler:{(imageData:Data?,dataUTI:String?,方向:UIImageOrientation,信息:[AnyHashable:Any]?)在中
//如果图像数据不是零,则将其设置到图像视图中
如果(imageData!=nil){
Async.main({
//从imageData获取图像
让image=UIImage.init(数据:imageData!)
完成(无,图像,asset.creationDate,asset.location)
})
}否则{
//TODO:检索图像时出错。显示警报
打印(“检索图像时出错!\n\(信息![PHImageErrorKey]))
完成(.GenericError,nil,nil,nil)
}
}
)
}
}
是一个易于管理
GCD
的框架。
当我调用这个方法时,我有一个很重的内存负载。如果我多次调用它,我可以在仪器中看到
PHAsset
,它在不释放任何东西的情况下继续增加。我考虑过
自动释放池
,但我不确定如何正确使用它。你有什么建议吗?最后一件事是,即使是在今天的小部件中,我也需要使用它,因为内存负载太重,它会持续崩溃。

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

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

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

尝试:

isSynchronous = true
isNetworkAccessAllowed = false

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

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

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

尝试:

isSynchronous = true
isNetworkAccessAllowed = false

我读过一次。也许它对你有一些用处。@RajanMaheshwari我已经读过那篇文章,很有趣,但对这个案例没有帮助。试着减少可能的失败点。在没有异步框架的情况下直接使用GCD时是否会发生相同的行为?@xpereta已经尝试过,同样的情况也会发生。奇怪的是,即使在图像数据被下载并显示为UIImage对象之后,内存仍在不断增加(在“所有堆分配”的声音下),而该集合是一个非常小的对象(它不包含照片或类似的内容)。这真的有什么大不了的吗?我读过一次。也许它对你有一些用处。@RajanMaheshwari我已经读过那篇文章,很有趣,但对这个案例没有帮助。试着减少可能的失败点。在没有异步框架的情况下直接使用GCD时是否会发生相同的行为?@xpereta已经尝试过,同样的情况也会发生。奇怪的是,即使在图像数据被下载并显示为UIImage对象之后,内存仍在不断增加(在“所有堆分配”的声音下),而该集合是一个非常小的对象(它不包含照片或类似的内容)。那么这真的是一件大事吗?