美文网首页selector
如何快速理解 swift Combine

如何快速理解 swift Combine

作者: 大成小栈 | 来源:发表于2023-11-20 14:21 被阅读0次

Combine 是 Swift 中的一个框架,用于处理和组合异步和事件驱动的操作。
要快速理解 Combine,可以从以下几个关键概念入手:

Publisher: 发布者是一个对象,它可以发出一系列的事件,比如值、错误或完成信号;
Subscriber: 订阅者是一个对象,它可以订阅一个或多个发布者,并对发布者发出的事件做出响应;

Operators(操作符):Combine 提供了许多操作符,可以用于转换、组合和处理发布者发出的事件。例如,map 用于映射值,filter 用于过滤事件,merge 用于合并多个发布者的事件等。

Cancellable(可取消):订阅一个发布者会返回一个 Cancellable 对象,你可以使用这个对象来取消订阅,释放资源;

Subject(主题):主题是 Combine 中的一种特殊类型的发布者,既可以发送值也可以接收值。有 PassthroughSubject 和 CurrentValueSubject 等类型;

Schedulers(调度器):Combine 使用调度器来确定在哪个线程上执行操作。有一些内置的调度器,比如 DispatchQueue.main 和 DispatchQueue.global();

下面是一个简单的例子,演示了 Combine 中的一些概念:

import Combine

// 创建一个发布者,发出一系列整数
let publisher = [1, 2, 3, 4, 5].publisher

// 订阅者,处理发布者发出的事件
let subscriber = Subscribers.Sink<Int, Never>(receiveValue: { value in
    print("Received value: \(value)")
})

// 订阅发布者
let cancellable = publisher.sink(receiveValue: { value in
    print("Received value: \(value)")
})

// 取消订阅
cancellable.cancel()

一个复杂一点的例子,演示了一个 viewModel 中combine的使用:

enum ContentMode: Equatable {
        case `default`
        case text(text: String)
        case voice(path: String)
    }
    
    class ViewModel {
        /// 当前选中图片index
        @Published
        var currentPhotoIndex: Int = 0
        
        /// 文字脚本内容
        @Published
        var textScript: String = ""
        var textLanguage: String = ""
        /// 文字脚本 对应的语音音色
        @Published // TODO 类型修改为 详情中对应Model
        var speechVoice: SpeechVoiceView.Voice?
        
        /// 语音脚本内容
        @Published
        var audioScript: String = ""
        
        /// 输入内容样式Mode
        @Published
        var contentMode: ContentMode = .default
        
        /// 是否能够生成
        @Published
        var enableGenerate: Bool = false
        
        /// 详情数据
        @Published
        var detail: DetailModel?
        
        /// 用户图
        @Published
        var userPhotos: [PTStylePhoto] = []
        
        /// Demo图
        @Published
        var demoPhotos: [PTStylePhoto] = []
        
        /// 用户图+Demo图
        @Published
        var allPhotos: [PTStylePhoto] = []
        
        // 是否结束播放
        @Published
        var isEndVideoPlay: Bool = false
        
        // 是否结束播放
        @Published
        var isEndAudioPlay: Bool = false
        
        let itemWidth = ScreenWidth - 16.0 * 4
        
        var contentModeName: String {
            switch contentMode {
            case .default:
                return ""
            case .text(_):
                return "text"
            case .voice(_):
                return "voice"
            }
        }
        
        
        var cancellables = Set<AnyCancellable>()
        
        init() {
            initialize()
        }
        
        private func initialize() {
            $demoPhotos
                .sink { [weak self] in
                    guard let self else { return }
                    allPhotos = userPhotos + $0
                }.store(in: &cancellables)
            
            // 查询用户图
            PTUserPhotoManager.manager.$allUserPhotos
                .map({ $0.map { PTStylePhoto(userPhoto: $0) } })
                .sink { [weak self] value in
                    guard let self else { return }
                    userPhotos = value
                }
                .store(in: &cancellables)
            //
            PTUserPhotoManager.manager.queryUserPhoto()
            
            // 请求详情数据
            PhotoTalkAPI.shared.publisher(.detail, type: DetailModel.self)
                .loading("loading...")
                .map { $0.result }
                .retry(2)
                .sink(receiveCompletion: { error in
                    
                }, receiveValue: { [weak self] value in
                    guard let self else { return }
                    detail = value
                    if let demoList = value?.demoList {
                        demoPhotos = demoList.map({
                            PTStylePhoto(demo: $0)
                        })
                    }
                })
                .store(in: &cancellables)
            
            $userPhotos.combineLatest($demoPhotos)
                .dropFirst()
                .map { $0 + $1 }
                .assign(to: &$allPhotos)
            

            // 输入内容状态
            let textPublisher = $textScript.filter({
                !$0.isEmpty
            }).map {
                ContentMode.text(text: $0)
            }.removeDuplicates()
            
            let audioPublisher = $audioScript.filter({
                !$0.isEmpty
            }).map {
                ContentMode.voice(path: $0)
            }.removeDuplicates()
            
            textPublisher
                .merge(with: audioPublisher)
                .assign(to: &$contentMode)
            
            
            // 能否合成状态
            $contentMode.sink { [unowned self] x in
                switch x {
                case .default:
                    enableGenerate = false
                case let .text(text):
                    enableGenerate = !text.isEmpty
                case let .voice(path):
                    enableGenerate = !path.isEmpty
                }
            }.store(in: &cancellables)
            
        }

    }

这只是 Combine 的入门,你可以通过深入学习每个概念、查阅文档以及进行实际的应用来更全面地理解 Combine。 Combine 的强大之处在于它提供了一种声明式的方式来处理异步操作,使得代码更易于理解和维护。

想详细了解Combine,请转以下链接:
https://icodesign.me/posts/swift-combine/

Combine中的操作符,逐个举例说明

Combine 框架中提供了许多强大的操作符,用于处理和组合异步事件流。下面是一些常用的 Combine 操作符,逐个举例说明它们的用法:

map 操作符:用于映射每个元素。

let publisher = [1, 2, 3].publisher
_ = publisher.map { $0 * 2 }
          .sink { value in
              print(value) // 输出:2, 4, 6
          }

filter 操作符:用于过滤元素。

let publisher = [1, 2, 3, 4, 5].publisher
_ = publisher.filter { $0 % 2 == 0 }
          .sink { value in
              print(value) // 输出:2, 4
          }

combineLatest 操作符:用于合并多个发布者的最新元素。

let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<String, Never>()

_ = publisher1.combineLatest(publisher2)
           .sink { value in
               print(value)
           }

publisher1.send(1)
publisher2.send("A")
// 输出:(1, "A")

merge 操作符:
用于合并多个发布者的元素。

let publisher1 = PassthroughSubject<Int, Never>()
let publisher2 = PassthroughSubject<Int, Never>()

_ = Publishers.Merge(publisher1, publisher2)
          .sink { value in
              print(value)
          }

publisher1.send(1)
publisher2.send(2)
// 输出:1, 2

flatMap 操作符:
用于将每个元素映射到一个新的发布者,然后将这些发布者的元素合并成一个新的发布者。

let publisher = [1, 2, 3].publisher
_ = publisher.flatMap { value in
             Just(value * 2)
          }
          .sink { value in
              print(value) // 输出:2, 4, 6
          }

scan 操作符:
用于对元素进行累积操作。

let publisher = [1, 2, 3].publisher
_ = publisher.scan(0) { accumulator, value in
             accumulator + value
          }
          .sink { value in
              print(value) // 输出:1, 3, 6
          }

这只是一小部分 Combine 操作符,它们提供了强大的工具,用于处理和组合异步事件流。
根据具体的业务需求,你可以组合使用这些操作符来构建复杂的异步数据处理流程。

相关文章

  • 2021-01-27

    Combine之简述 用Apple的话说,Combine是: a declarative Swift API fo...

  • Apple原生Rx框架Combine简介

    Combine是什么 a declarative Swift API for processing values ...

  • Swift Combine

    简介 Combine是Apple在2019年WWDC上推出的一个新框架。该框架提供了一个声明性的Swift API...

  • 如何用 SwiftUI、Combine、Swift Concur

    先说两句废话(Don't blame me about my calculation) 为啥写这篇文章,简单说,这...

  • 151230

    快速浏览了下Swift语法: A Swift Tour php link mysql 对于闭包的理解还差得很远,...

  • SwiftUI(Combine)学习整理(三)

    如果有RxSwift的学习经验那么理解combine会更加迅速 通过对事件处理的操作进行组合 (combine) ...

  • Swift Combine 入门导读

    在具体介绍 Combine 之前,有两个重要的概念需要简要介绍一下: 观察者模式 响应式编程 观察者模式 观察者模...

  • Swift Combine 之 Subject

    Subject 观察者,继承于Publisher,作为一个观察者的身份,可以监听其他源 被观察者,可以发送数据流,...

  • Swift Combine核心概念

    OpenCombine 核心概念 Publisher数据发布源,包装器,包装了Subscriber订阅器可以链式调...

  • Swift 中的属性包装器 - Property Wrapper

    在使用 Swift 开发的过程中,经常会遇到诸如 SwiftUI 中的 @State,Combine 中的 @Pu...

网友评论

    本文标题:如何快速理解 swift Combine

    本文链接:https://www.haomeiwen.com/subject/bjevwdtx.html