I faced and issue with images using too much memory when running the app. A 905kb SVG image was taking around 150mb when presented and this image was being cached by the system. Loading several different SVG images on different pages led to memory pressure issue.
So I started looking into image downsampling and found a solution. I managed create a function to downsample the image based on size of the image (Had help with it).Currently I can downsample the image by using a downsampler class which needs to be set as a custom class for every imageView which I want to enable downsampling.
But I am trying to create an IBDesignable extension for UIImageView so that I can use any custom class but still get the benefit of downsampling the image.
This is the code for downsampling class
import UIKit
class DownsamplingImageView: UIImageView {
@IBInspectable
var downSample: Bool = true {
didSet {
setNeedsLayout()
}
}
override func layoutSubviews() {
super.layoutSubviews()
if downSample, let image = self.image {
let targetSize = self.bounds.size
let downsampledImage = image.downsample(to: targetSize)
self.image = downsampledImage
}
}
}
extension UIImage {
func downsample(to targetSize: CGSize) -> UIImage? {
let sourceSize = self.size
let widthRatio = targetSize.width / sourceSize.width
let heightRatio = targetSize.height / sourceSize.height
let scaleFactor = max(widthRatio, heightRatio)
let scaledSize = CGSize(width: sourceSize.width * scaleFactor, height: sourceSize.height * scaleFactor)
UIGraphicsBeginImageContextWithOptions(scaledSize, false, 0.0)
self.draw(in: CGRect(origin: CGPoint.zero, size: scaledSize))
let downsampledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return downsampledImage
}
}
This is how I tried to make an extension but unfortunately it doesn't work.
import UIKit
@IBDesignable
extension UIImageView {
@IBInspectable
var downSample: Bool {
get {
return image != nil
}
set {
setNeedsLayout()
}
}
override open func layoutSubviews() {
super.layoutSubviews()
if downSample, let image = self.image {
let targetSize = self.bounds.size
let downsampledImage = image.downsample(to: targetSize)
self.image = downsampledImage
}
}
}
extension UIImage {
func downsample(to targetSize: CGSize) -> UIImage? {
let sourceSize = self.size
let widthRatio = targetSize.width / sourceSize.width
let heightRatio = targetSize.height / sourceSize.height
let scaleFactor = max(widthRatio, heightRatio)
let scaledSize = CGSize(width: sourceSize.width * scaleFactor, height: sourceSize.height * scaleFactor)
UIGraphicsBeginImageContextWithOptions(scaledSize, false, 0.0)
self.draw(in: CGRect(origin: CGPoint.zero, size: scaledSize))
let downsampledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return downsampledImage
}
}
Could someone please help or explain why the extension on UIImageView doesn't work but using custom class works? Also is there anyway to make the extension work?
PS: 150mb usage reduced to just 6mb usage and fortunately its being released right when user leaves the page !
Just incase anybody want to enable downsampling, the first code works perfectly, all you have to do is set the UIImageView custom class as DownsamplingImageView
I ended up using an image down sampler to fix this issue.
import UIKit
class DownsamplingImageView: UIImageView {
@IBInspectable
var downSample: Bool = true {
didSet {
setNeedsLayout()
}
}
override func layoutSubviews() {
super.layoutSubviews()
if downSample, let image = self.image {
let targetSize = self.bounds.size
let downsampledImage = image.downsample(to: targetSize)
self.image = downsampledImage
}
}
}
extension UIImage {
func downsample(to targetSize: CGSize) -> UIImage? {
let sourceSize = self.size
let widthRatio = targetSize.width / sourceSize.width
let heightRatio = targetSize.height / sourceSize.height
let scaleFactor = max(widthRatio, heightRatio)
let scaledSize = CGSize(width: sourceSize.width * scaleFactor, height: sourceSize.height * scaleFactor)
UIGraphicsBeginImageContextWithOptions(scaledSize, false, 0.0)
self.draw(in: CGRect(origin: CGPoint.zero, size: scaledSize))
let downsampledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return downsampledImage
}
}
Credits : I forgot where I got this from. I am just answering this question incase someone faces the same issue. Credits to original owner.