2016-10-10 1 views
1

Je rencontre des problèmes de mémoire lors de la récupération d'objets de l'infrastructure Photos dans iOS. Je vous montre mon code:Gestion de la mémoire avec le cadre Photos

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 est un cadre pour gérer facilement les GCD. Lorsque j'appelle cette méthode, j'ai une lourde charge de mémoire. Si je l'appelle plusieurs fois, je peux voir PHAsset dans Instruments qui continue à augmenter sans rien relâcher. J'ai pensé à la autoreleasepool, mais je ne suis pas sûr de savoir comment l'utiliser correctement. Avez-vous des suggestions ou quelque chose comme ça? La dernière chose est que j'ai besoin d'utiliser ceci même dans un Widget Aujourd'hui qui se bloque continuellement à cause de cette lourde charge de mémoire.

+0

Je lis cette fois http://nshipster.com/phimagemanager/. peut-être que cela vous sert à quelque chose. –

+0

@RajanMaheshwari J'ai déjà lu cet article, intéressant, mais cela n'aide pas pour ce cas. –

+0

Essayez de réduire les points de défaillance possibles. Est-ce que le même comportement se produit lorsque vous utilisez GCD directement sans le cadre Async? – xpereta

Répondre

0

Notez que vous utilisez l'option de faire appel à l'requestImageData de manière asynchrone:

isSynchronous = false 

que vous n'avez pas besoin probablement parce que le code d'appel est déjà dans un thread d'arrière-plan.

Cela signifie également que le gestionnaire de résultats peut être appelé plusieurs fois. Et en combinaison avec l'option isNetworkAccessAllowed peut retarder la fin des demandes et la libération des instances PHAsset.

Essayez avec:

isSynchronous = true 
isNetworkAccessAllowed = false 
+0

Mais j'ai besoin de l'isNetworkAccessAllowed pour être vrai –