在处理存储在阵列中的大图像时,高内存使用或高质量的交易

时间:2017-04-03 20:26:59

标签: ios swift memory-leaks uiimageview

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

enter image description here

有一个ImageView和一个RangeSlider。

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

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

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

我正在下载48张图像,大小为1920×1920像素,每张图像大约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
        }
    }
}

那么我怎样才能以优雅的方式实现它,不会造成内存泄漏,但仍能使用最佳的图像质量?

1 个答案:

答案 0 :(得分:2)

if data != nil {
   let img = UIImage(data: data!)
   self?.images.append(img!)
}

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

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

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