swift combine sink receiveValue 内存泄漏

我在处理Combine的时候遇到了困难。在发布器完成后,我想更新一个值,但每当我更新这个值时,内存就会被分配,而且永远不会消失。

每当我尝试分配图像时,就会出现泄漏。如果我不分配没有泄漏。

EDIT:这里有一个可复制的例子。https:/github.competerwarboMemoryAllocation。

这就是我的代码的样子。

final class CameraController: ObservableObject {

    private var storage = Set<AnyCancellable>()    
    var image: UIImage?

    func capture(_ image: UIImage) {

        PhotoLibrary.saveImageToTemporaryDirectory(image) // AnyPublisher<URL, Error>
            .zip(PhotoLibrary.saveImage(image, location: self.locationObserver.location) // AnyPublisher<UIImage, Error>)
            .sink(receiveCompletion: { [weak self] (completion) in
                switch completion {
                case let .failure(error):
                    Log.error(error)
                    self?.handleCaptureError(error)
                case .finished: break
                }
            }) { [weak self] (value) in
                print(value.1) // no leak
                self.image = value.1 // leak

            }
            .store(in: &self.storage)
     }
}

我也试过不使用 sink:

.receive(
    subscriber: Subscribers.Sink(
        receiveCompletion: { [weak self] completion in
            switch completion {
            case let .failure(error):
                Log.error(error)
                self?.handleCaptureError(error)
            case .finished: break
            }
        },
        receiveValue: { value in
            print(value.1) // no leak
            self.image = value.1 // leak            
        }
    )
)

解决方案:

你的代码有一个明显的问题,就是你每次都要创建和存储一个新的管道 capture 被称为。这与如何使用Combine正好相反;你可能根本就不会使用Combine。使用Combine的方法是创建一个流水线 曾经 并让信息从管道中异步下来。

你发布了一个示例项目,在这个项目中,你使用Future来引入一个延迟,以使图像在管道中传递。在你的项目中,用户从照片库中选择了一张图片,反复地选择。同样,在你的项目中,每次选择一张图片时,你都要创建和存储一个新的管道。我把这个例子改写如下。

import UIKit
import Combine

class ViewController: UIViewController, UINavigationControllerDelegate {
    let queue = DispatchQueue(label: "Queue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem)
    var image: UIImage?
    var storage: Set<AnyCancellable> = []
    let publisher = PassthroughSubject<UIImage, Never>()
    override func viewDidLoad() {
        super.viewDidLoad()
        self.publisher
            .flatMap {image in
                self.futureMaker(image: image)
            }
            .receive(on: DispatchQueue.main)
            .sink(receiveCompletion: { (completion) in
            }) { (value) in
                print("finished processing image")
                self.image = value
            }
            .store(in: &self.storage)
    }
    @IBAction func didTapPickImage(_ sender: UIButton) {
        let picker = UIImagePickerController()
        picker.delegate = self
        present(picker, animated: true)
    }
    func futureMaker(image: UIImage) -> AnyPublisher<UIImage, Never> {
        Future<UIImage, Never> { promise in
            self.queue.asyncAfter(deadline: .now() + 0.5) {
                promise(.success(image))
            }
        }.eraseToAnyPublisher()
    }
}
extension ViewController: UIImagePickerControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        dismiss(animated: true)
        guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
        print("got image")
        self.publisher.send(image)
    }
}

注意这个架构 我只创建了一次流水线,在 viewDidLoad每当有图像到达时,我都会把它传下去。一样 管道。因为我们要存储一个UIImage,所以肯定会使用一些内存;但它并没有以任何不受控制的方式增长,而是以一种最佳的方式保持平衡。

enter image description here

在反复挑选库中的所有图像后,我们使用了8.4 MB。没有问题!

enter image description here

另外,没有多余的大图片持续存在。看着在图片挑选器中挑选而来的内存。一个 图像持续存在;这是我们8.4 MB中的2.7 MB。

enter image description here

这正是我们所期望的。

给TA打赏
共{{data.count}}人
人已打赏
未分类

python中的类属性可以用protected写吗?

2022-9-9 2:01:18

未分类

筛选 基于某种属性的嵌套数组

2022-9-9 2:01:20

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索