Wednesday, 30 September 2020

iOS 14 WidgetKit Memory Issue - Photo Asset Dimensions

With iOS 14 WidgetKit, I am trying to display a widget with a 'particular' photo asset from the library. With a medium-size widget, I want the photo asset to fill the whole area (Aspect Fill), just like the native Photos widget.

    struct My_WidgetEntryView : View 
    {
       var entry : Provider.Entry
       var body: some View 
       {
         PhotoView(user: 1)
       }
    }
    
    struct PhotoView: View 
    {
                                 var user            : Int
        @ObservedObject  private var assetImageModel = AssetImageModel()
    
        init(user: Int)
        {
            self.user = user
            self.assetImageModel.loadAsset()
        }
    
        var body: some View {
                if self.assetImageModel.assetImage != nil {
                    Image(uiImage: self.assetImageModel.assetImage!)
                        .resizable()
                    
                } else {
                    Image(uiImage: UIImage(systemName: "photo")!)
                        .resizable()
                }
        }
    }
    
    
    class AssetImageModel: ObservableObject {
        @Published var assetImage: UIImage?
    
        init() {
            loadAsset()
        }
    
        func loadAsset() {
            if PHPhotoLibrary.authorizationStatus() == .authorized {
    
                let allPhotosOptions = PHFetchOptions()
                allPhotosOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
                let assetsFetchResults = PHAsset.fetchAssets(with: allPhotosOptions)
                if assetsFetchResults.count > 0 {
                    let asset = assetsFetchResults.lastObject
                    if asset != nil {
                        let options = PHImageRequestOptions()
                        options.isSynchronous = true
                        options.deliveryMode = .highQualityFormat
                        options.resizeMode = .exact
                        options.version = .current
    
                        PHCachingImageManager().requestImage(for: asset!, targetSize: CGSize(width: 360 * UIScreen.main.scale, height: 170 * UIScreen.main.scale), contentMode: .aspectFill, options: options, resultHandler: { image, _ in
                              
                            //DispatchQueue.main.async {
                              self.assetImage = image
                            //}
     
                        })
                    } else {
                        //Asset was nil
                    }
                } else {
                    //No assets
                }
            } else {
                //No persmission    
            }
        }
    }

When the above is run, I get a crash with a memory warning stating allowed 30 MB memory limit has exceeded. This obvious due to this:

  • For the medium-size widget, I had to go by a 360 x 170 point size since there was no way to get the actual view dimensions before the the view gets displayed.
  • The actual target size then has to be multiplied by the screen scale, at the moment the test device is a 3x. Aspect Fill as to be the fill type. Due to this, PHCachingImageManager is returning a 360-point width with 480-point height for a portrait photo in order to fill the view. The final dimensions of the image end up being 1080 x 1440 pixel size. I imagine this is the reason for memory pressure.

Question

Is there a way to ask for a properly cropped 360 x 170 point size image? The stock Photos widget seems to manage this.

Things I Tried

  • I tried normalizedCropRect in PHImageRequestOptions and had no luck.
  • Lowering the image size by a huge margin works, but the image looks blurred visually.


from iOS 14 WidgetKit Memory Issue - Photo Asset Dimensions

No comments:

Post a Comment