2016-10-10 12 views
1

iOSのPhotosフレームワークからオブジェクトを取得する際にメモリの問題が発生しました。私はあなたに私のコードを示しています。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は簡単GCDを管理するためのフレームワークです。 私はこのメソッドを呼び出すと、メモリ負荷が大きくなります。私が複数回呼び出すと、InstrumentのPHAssetが何もリリースせずに増加し続けるのがわかります。私はautoreleasepoolについて考えましたが、正しく使用する方法がわかりません。そのような提案がありますか?最後のことは、この重い負荷のために継続的にクラッシュするTodayウィジェットでもこれを使用する必要があることです。あなたが非同期的にrequestImageDataへの呼び出しを行うためにオプションを使用している

+0

私はhttp://nshipster.com/phimagemanager/一度これを読んで。それはあなたにいくらか役立つかもしれません。 –

+0

@ RajanMaheshwari私は既にこの記事を読んでいて面白いですが、この場合は役に立ちません。 –

+0

失敗の可能性を減らすようにしてください。 AsyncフレームワークなしでGCDを直接使用する場合、同じ動作が発生しますか? – xpereta

答えて

0

お知らせ:

isSynchronous = false 

呼び出し元のコードは、バックグラウンドスレッドにすでにあるので、あなたはおそらく必要はありません。

これは、結果ハンドラが複数回呼び出される可能性があることも意味します。また、isNetworkAccessAllowedオプションと組み合わせて、要求の終了とPHAssetインスタンスのリリースを遅らせる可能性があります。

で試してみてください:

isSynchronous = true 
isNetworkAccessAllowed = false 
+0

しかし、isNetworkAccessAllowedをtrueにする必要があります –