Очевидная проблема с вашим кодом заключается в том, что вы создаете и сохраняете новый конвейер каждый раз, когда вызывается 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; но он не растет неконтролируемым образом, но выравнивается оптимальным образом.
Мы используем 8,4 МБ после выбора всех изображений в библиотеке неоднократно. Нет проблем!
Кроме того, излишки больших изображений не сохраняются. Если посмотреть на память, которая появляется при выборе средства выбора изображений, изображение one сохраняется; это 2,7 МБ из наших 8,4 МБ:
Это именно то, что мы ожидаем.