【发布时间】: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