Wednesday, 26 July 2023

iOS Swift: Crash while loading HD images

App’s memory usage spikes up pretty high when we start loading HD images on screen.

Memory use is related to the dimensions of the image, not the file size.

Downsampling Using ImageIO:


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)
}

Let us first go through the function’s parameters:

  • imageURL: The image URL. It can be a web URL or a local image path.
  • pointSize: The desired size of the downsampled image. Usually, this will be the UIImageView‘s frame size.
  • scale: The downsampling scale factor. Usually, this will be the scale factor associated with the screen (we usually refer to it as @2x or @3x). That’s why you can see that its default value has been set to UIScreen.main.scale.

let’s talk about kCGImageSourceShouldCache. When this flag is set to false, we let the core graphic framework know that we only need to create a reference to the image source and do not want to decode the image immediately when the CGImageSource object is being created.

Pro tip:

In the situation where you do not have access to the path of the image source, you can create a CGImageSource object using the CGImageSourceCreateWithData() initializer.

Next on the list is kCGImageSourceShouldCacheImmediately. This flag indicates that the core graphic framework should decode the image at the exact moment we start the downsampling process.

Therefore, by using both kCGImageSourceShouldCache and kCGImageSourceShouldCacheImmediately option flags, we can have full control on when we want to take the CPU hit for image decoding.

Lastly is the kCGImageSourceCreateThumbnailWithTransform option flag. Setting this flag to true is very important as it lets the core graphic framework know that you want the downsampled image to have the same orientation as the original image.

 filePath = Bundle.main.url(forResource: "men", withExtension: "svg")!
let downsampledLadyImage = downsample(imageAt: filePath, to: imageView.bounds.size)
imageView.image = downsampledLadyImage

Note:

Keep in mind that downsampling is a process that takes up CPU power. Therefore, it is still preferable to use a properly scaled image source rather than downsampling an HD image.

In other words, you should consider using downsampling only when you need to display an image where its dimension is much higher than the required on-screen dimension.

Saturday, 8 July 2023

Video Error: Check video URL is valid in SWIFT

 This the code to find the Video URL is valid or not.

Before adding the video URL to AVplayer, check whether AVplayer can play video using that url using AVAsset.



func getVideoPlayer(url: String) -> AVPlayer? {
    guard let url = URL(string: url) else {
        print("url not found")
            return nil
        }
    //test if video is playable
    if AVAsset(url: url).isPlayable {
        let player = AVPlayer(url: url)
        return player
    } else {
        return nil
    }
}

Setting Up Multiple App Targets in Xcode from a Single Codebase

 To create two different apps (like "Light" and "Regular") from the same codebase in Xcode, you can follow these steps b...