Stefano Vet
Stefano Vet

Reputation: 737

Memory issue with loading multiple UIImage in SwiftUI

I use this simple code to load image from Temp directory


struct AddNewMedia: View {

      @State var filename:String

      func imageFullPath(filename:String)->UIImage {
           let pathToTemoDir = FileManager.default.temporaryDirectory.appendingPathComponent(filename)
               return UIImage(contentsOfFile: pathToTemoDir.path)!
      }

         var body: some View {

             Image(uiImage: self.imageFullPath(filename: filename))
               .resizable()
               .scaledToFit()
     }
}

Every new image need a lot of memory to be visualized. In this project I need to load 20-30 images and therefore I should reduce the memory needed for each image which is now about 23mb per image.

Is it possible to load the image directly from its path without adding it to memory? Any suggestions? Many thanks!

Upvotes: 3

Views: 1750

Answers (1)

Burak Akkaş
Burak Akkaş

Reputation: 535

Anything that you want to display in your app should be loaded into memory, so I believe there is nothing to do on that part.

On iOS, UIImage's memory usage is relative to the image dimensions. For example, if you have 1920x1080 image, it will approximately consume about 8 megabytes in the memory (1920 * 1080 * 4 bytes).

Because as mentioned in WWDC 2018, "Memory use is related to the dimensions of the image, not the file size."

So as a solution, you can use an image that has lower dimensions, or you can downsample the image before presenting it.

Here is an example function for downsampling an image, credits to this link

func downsample(imageAt imageURL: URL,
                to pointSize: CGSize,
                scale: CGFloat = UIScreen.main.scale) -> UIImage? {

    // Create an CGImageSource that represent an image
    let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
    guard let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions) else {
        return nil
    }
    
    // Calculate the desired dimension
    let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
    
    // Perform downsampling
    let downsampleOptions = [
        kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceShouldCacheImmediately: true,
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels
    ] as CFDictionary
    guard let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions) else {
        return nil
    }
    
    // Return the downsampled image as UIImage
    return UIImage(cgImage: downsampledImage)
}

Upvotes: 7

Related Questions