RxSwift图片处理流程性能优化方案咨询
RxSwift图片重绘流程性能优化建议
核心优化:调整并发策略
原流程中concatMap强制串行执行所有任务,而flatMap默认并发数不足,这是多图片处理慢的核心原因。针对不同任务类型(IO密集/CPU密集)设置合理并发数,最大化利用设备资源:
func redrawChapter(pages: [Resource]) -> Single<[UIImage]> { return Observable .from(pages) // 图片下载是IO密集,可设置较高并发数(如4-8,依设备性能调整) .flatMap(maxConcurrent: 6) { self.getImage(resource: $0) } // Vision文本识别可利用GPU,适当设置并发数 .flatMap(maxConcurrent: 4) { self.recognizeText(image: $0) } // 翻译是网络IO,控制并发避免接口限流 .flatMap(maxConcurrent: 2) { self.translate(image: $0.0, synopsys: $0.1) } // 图片重绘是CPU密集,按设备核心数设置并发(如2-4) .flatMap(maxConcurrent: 3) { self.redrawImage(image: $0.0, synopsys: $0.1) } .toArray() }
简化Observable创建,消除冗余转换
多处存在不必要的Observable转Single操作,增加调度开销,直接用Single相关操作符简化:
优化图片下载函数
利用Kingfisher官方Rx扩展(需导入KingfisherRx),避免手动创建Single:
private func getImage(resource: Resource) -> Single<UIImage> { KingfisherManager.shared.rx.retrieveImage(with: resource) .map { $0.image } }
优化文本识别函数
去掉多余的Observable包装,直接用Single.zip组合结果:
private func recognizeText(image: UIImage) -> Single<(UIImage, [Synopsis])> { return Single.zip( Single.just(image), self.imageProcessor.getRecognizedText(image: image).asSingle() ) }
优化翻译函数
移除冗余的compactMap,限制单图片内的翻译请求并发数,并将Maybe改为Single(只要有Synopsis就会有结果):
private func translate(image: UIImage, synopsys: [Synopsis]) -> Single<(UIImage, [Synopsis])> { return Observable.from(synopsys) .flatMap(maxConcurrent: 3) { synopsis in self.translator.translate(text: synopsis.text) .map { (synopsis.rect, $0) } } .map { Synopsis(text: $0.1, rect: $0.0) } .toArray() .map { (image, $0) } }
图片重绘阶段优化
1. 后台线程执行渲染
图片重绘是CPU密集操作,默认在主线程执行会阻塞UI,将渲染逻辑移到后台队列:
private func redrawImage(image: UIImage, synopsys: [Synopsis]) -> Single<UIImage> { return Single.create { single in let queue = DispatchQueue.global(qos: .userInitiated) queue.async { let format = UIGraphicsImageRendererFormat() format.scale = 1 guard let cgImage = image.cgImage else { single(.failure(NSError(domain: "ImageError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效图片"]))) return } 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) // 提前预计算所有颜色,避免循环内重复计算 let synopsisStyles = synopsys.map { syn in let bgColor = cgImage.averageColorOf(rect: syn.rect) return (syn, bgColor, bgColor.textColor()) } for (syn, bgColor, textColor) in synopsisStyles { self.setupLabel( text: syn.text, backgroundColor: bgColor, textColor: textColor, bounds: syn.rect, context: context.cgContext ) } } DispatchQueue.main.async { single(.success(final)) } } return Disposables.create() } }
2. 优化文本绘制细节
- 提前计算每个Synopsis的文本属性(字体、段落样式),避免循环内重复创建
NSAttributedString - 复用相同颜色对象,减少内存分配
- 检查
setupLabel函数,缓存文本尺寸等计算结果,避免重复计算
其他优化建议
- 缓存复用:对已下载图片、已识别文本区域、已翻译文本做本地缓存,避免重复处理相同资源
- Vision性能调优:使用
VNImageRequestHandler时,可降低输入图片分辨率(如果不需要高精度识别),减少计算量 - 批量网络请求:将多个翻译文本打包成一个接口请求,减少网络握手开销
内容的提问来源于stack exchange,提问作者Artem
相关产品推荐
相关产品推荐

