#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