【问题标题】:high memory usage or good quality tradeofs while working with large images stored in a array处理存储在数组中的大图像时,内存使用率高或质量好
【发布时间】:2017-08-28 20:26:48
【问题描述】:

我有一个这样的视图控制器:

有一个 ImageView 和一个 RangeSlider。

行为应该是这样的: 如果用户滑动范围滑块,ImageView 中的图像应该切换到图像数组中的新图像。用户还可以在不损失图片质量的情况下对图片进行缩放操作。

所以我所做的就是将图像下载到viewDidLoad上的图像数组中:

//image array
var images = [UIImage]()

我正在下载 48 张图片,大小为 1920 × 1920 px,每张图片大约 120 KB,并创建下载数据的 UIImage 对象并将它们保存到数组中,如下所示:

DispatchQueue.global().async { [weak self] in
    let data = try? Data(contentsOf: url) 
    DispatchQueue.main.async {
        if data != nil {
            let img = UIImage(data: data!)
            self?.images.append(img!)
        } else {
            ...
        }
    }
}

要更改 imageView 中的图像,我创建了这个函数:

func updateImage(currentImage: UIImage) {
    self.imageView.image = currentImage
}

当用户开始滑动rangeSlider 时,应用程序的内存使用量从 40 MB 运行到 700 MB,并在用户切换所有图像后停止增加。在那之后,用户可以在不影响内存使用的情况下来回切换整个图像。

但是当我在更新图像之前稍微调整大小时,内存问题得到了解决,但是如果用户稍微放大一点,图像现在质量很差。

调整部分大小:

extension UIImage {
    func resized(_ newSize:CGSize) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
        self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    }
}

func updateImage(currentImage: UIImage) {
    let currentImg = currentImage.resized(self.imageView.bounds.size)

    self.imageView.image = currentImg
}

对于缩放,我使用这个:

@IBAction func scaleImage(_ sender: UIPinchGestureRecognizer) {
    print(self.imageView.transform)

    let tmp = self.imageView.transform.scaledBy(x: sender.scale, y: sender.scale)

    if (tmp.a >= 0.99 || tmp.d >= 0.99) && (tmp.a < 2.5 || tmp.d < 2.5) {
        self.imageView.transform = self.imageView.transform.scaledBy(x: sender.scale, y: sender.scale)
        sender.scale = 1

        if (tmp.a <= 1.2 || tmp.d <= 1.2) {
            self.imageView.center = defaultImageCenter
        }
    }
}

那么我怎样才能以一种优雅的方式来实现它,既不提供内存泄漏,又仍然使用最佳图像质量?

【问题讨论】:

  • 是否完全有必要同时下载它们?
  • 是的,因为它应该具有出色的用户体验而不会出现滞后内容。
  • 大多数执行此类操作的应用会提前加载几张图片,但不是一次全部加载
  • 您很清楚,您看到的是内存使用,而不是内存泄漏。泄漏是指分配了内存并且永远无法回收。这不是你在这里所拥有的。除非您遇到内存压力问题,否则您可能不想做任何事情。您可以使用 NSCache 或 SDWebImage 之类的框架来管理按需加载

标签: ios swift memory-leaks uiimageview


【解决方案1】:
if data != nil {
   let img = UIImage(data: data!)
   self?.images.append(img!)
}

在这部分,不是创建 UIImage 并将其添加到数组中,而是将数据保存到磁盘并将其位置存储为数组。然后,当您移动滑块时,从与滑块位置匹配的位置创建 UIImage。这样一次只会在内存中加载一个 UIImage。

如果你想让它更快,也加载上一个和下一个图像(例如你在位置 4,也加载图像 3 和 5,然后当你将滑块移动到位置 5 时,你已经有了图像- 此时释放图像 3 并加载 6)。这会占用更大的内存,但是当您移动滑块时,您会立即看到图像。

您可能还不想一次下载所有图像以加快速度,但这与内存无关,所以这应该足以解决您的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-13
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    • 2014-02-24
    相关资源
    最近更新 更多