英文:
How to make an IBDesignable image down sampling function in Swift?
问题
我遇到了一个关于图像内存使用过多的问题,当运行应用程序时,一个 905kb 的 SVG 图像在显示时占用了大约 150mb 的内存,并且该图像被系统缓存。在不同页面加载多个不同的 SVG 图像导致了内存压力问题。
所以我开始研究图像降采样并找到了一个解决方案。我成功创建了一个基于图像大小的降采样函数(得到了帮助)。目前,我可以通过使用一个降采样器类来降采样图像,需要为我想要启用降采样的每个 imageView 设置为自定义类。
但是我正在尝试创建一个 UIImageView 的 IBDesignable 扩展,以便我可以使用任何自定义类,但仍然获得降采样图像的好处。
这是降采样类的代码:
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
}
}
这是我尝试创建的扩展,但不幸的是它不起作用:
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
}
}
是否有人能帮助或解释为什么 UIImageView 的扩展不起作用,而使用自定义类却起作用?还有没有办法使扩展起作用?
附注:内存使用从 150mb 减少到仅 6mb,并且幸运的是当用户离开页面时它会被释放!如果有人想要启用降采样,第一段代码完美地工作,你只需将 UIImageView 的自定义类设置为 DownsamplingImageView
。
英文:
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
答案1
得分: 0
我最终使用了图像降采样器来解决这个问题。
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 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论