这个RxSwift代码运行得很慢,所以你能给我一个如何提高它性能的建议吗?

此功能是获取图像资源并将其映射到重新绘制的图像中

func redrawChapter(pages: [Resource]) -> Single<[UIImage]> {
     return Observable
        .from(pages)
        .flatMap(getImage)
        // MARK: Detect synopsys
        .flatMap(recognizeText)
        // MARK: Translate synopsys
        .concatMap(translate)
        // MARK: Image redraw
        .concatMap(redrawImage)
        .toArray()
}

我在用翠鸟下载图片

private func getImage(resource: Resource) -> Single<UIImage> {
    return Single.create { single in
        let disposables = Disposables.create()
        
        KingfisherManager.shared.retrieveImage(with: resource) { result in
            switch result {
            case .success(let value):
                single(.success(value.image))
            case .failure(let error):
                single(.failure(error))
            }
        }
        return disposables
    }
}

我正在使用Apple Vision来识别文本区域

private func recognizeText(image: UIImage) -> Single<(UIImage, [Synopsis])> {
    return Observable.of(image)
        .flatMap {
            Observable.combineLatest(
                Observable.just($0),
                // MARK: Apple vision to detect text regions
                self.imageProcessor.getRecognizedText(image: $0).asObservable()
            )
        }
        .asSingle()
}

和网络方面的莫亚

private func translate(image: UIImage, synopsys: [Synopsis]) -> Maybe<(UIImage, [Synopsis])>{
    return Observable.from(synopsys)
        .flatMap {
            Observable.combineLatest(
                Observable.just($0.rect),
                self.translator.translate(text: $0.text).asObservable()
            )
        }
        .compactMap {
            return Synopsis(
                text: $0.1,
                rect: $0.0
            )
        }
        .toArray()
        .compactMap {
            return (image, $0)
        }
}

使用UIGraphics渲染器重绘图像

private func redrawImage(
    image: UIImage,
    synopsys: [Synopsis]
) -> Single<UIImage> {
    return Single.create { single in
        
        let format = UIGraphicsImageRendererFormat()
        format.scale = 1
        
        guard let cgImage = image.cgImage else {
            return Disposables.create()
        }
        
        let size = image.size
        
        let bounds = CGRect(
            origin: .zero,
            size: size
        )
        
            let final = UIGraphicsImageRenderer(
                bounds: bounds,
                format: format
            ).image { context in
                
                image.draw(in: bounds)
                
                for syn in synopsys {
                    
                    let backgroundColor = cgImage.averageColorOf(rect: syn.rect)
                    let textColor = backgroundColor.textColor()
                    
                    self.setupLabel(
                        text: syn.text,
                        backgroundColor: backgroundColor,
                        textColor: textColor,
                        bounds: syn.rect,
                        context: context.cgContext
                    )
                }
            }
            single(.success(final))
        
        return Disposables.create()
    }
}

我觉得有另一种方法可以不让如此大量的可观测数据发挥作用,让它发挥作用,也许它会以某种方式提高这种功能的性能.感谢你的帮助.

推荐答案

以下是最新的解决方案.试一试,看看效果如何:

func redrawChapter(pages: [Resource]) -> Single<[UIImage]> {
    let image = Observable.from(pages)
        .flatMap(getImage(resource:))

    let translatedSynopses = image
        .flatMap(imageProcessor.getRecognizedText(image:))
        .flatMap { Single.zip($0.map(translate(synopses:))) }

    return Observable.zip(image, translatedSynopses)
        .observe(on: MainScheduler.instance) // if you need it, you may not.
        .compactMap(redrawImage(image:synopses:))
        .toArray()
}

func getImage(resource: Resource) -> Single<UIImage> {
    Single.create { observer in
        KingfisherManager.shared.retrieveImage(with: resource, completion: observer)
        return Disposables.create()
    }
    .map(\.image)
}

func translate(synopses: Synopsis) -> Single<Synopsis> {
    translator.translate(text: synopses.text)
        .map { Synopsis(text: $0, rect: synopses.rect) }
}

func redrawImage(image: UIImage, synopses: [Synopsis]) -> UIImage? {
    guard let cgImage = image.cgImage else { return nil }
    let format = UIGraphicsImageRendererFormat()
    format.scale = 1
    let size = image.size
    let bounds = CGRect(origin: .zero, size: size)

    return UIGraphicsImageRenderer(bounds: bounds, format: format).image { context in
        image.draw(in: bounds)
        for syn in synopses {
            let backgroundColor = cgImage.averageColorOf(rect: syn.rect)
            let textColor = backgroundColor.textColor()
            setupLabel(
                text: syn.text,
                backgroundColor: backgroundColor,
                textColor: textColor,
                bounds: syn.rect,
                context: context.cgContext
            )
        }
    }
}

什么可能会让这一切变得更快?因为我删除了concatMap,所以它将一次执行多个转换(我假设这是一个网络请求).随着映像的转换传入,它将处理该映像.

关于这段代码(和您的代码)的一件事是,发出的图像数组的顺序可能与传入的资源不同.如果这将是一个问题,那么就必须做出调整.

Swift相关问答推荐

VisionOS发送通知

如何设置两个不同的视图模型以在我的SwiftUI应用程序中使用相同的数据源?

OBJC代码中Swift 演员的伊瓦尔:原子还是非原子?

如何在SWIFT中使用DiscardingTaskGroup获得任务结果

MacOS 13-如何使用SwiftUI创建Message.App设置工具栏?

当将新值推送到 NavigationStack 时,SwiftUI 的 navigationDestination 已在堆栈的早期声明

BLE 在 ESP32 和 Iphone 之间发送字符串

Xcode 15 Beta中如何使用@Observable?

如何在不将变量转换为字符串的情况下判断变量在 Swift 中是否为 Optional(nil)?

如何删除 macOS 中的所有命令?

SwiftUI 分段 Select 器的问题

Swift Swiftui - 将 colored颜色 保存到 UserDefaults 并从 @AppStorage 使用它

Swift初始化具有可变ID的重复值数组

如何根据 SwiftUI 中的字体大小定义按钮的大小?

使用 swift 运行 pod install 时出错

根据禁用与否更改 SwiftUI 中按钮的 colored颜色

如何在 Swift 中复制字典?

自定义 MKAnnotation 标注视图?

Swift 2.0 最低系统版本要求(部署目标)

使用 swift IOS 使 UIBarButtonItem 消失