首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Combine-常见使用场景

Combine-常见使用场景

作者头像
YungFan
发布2025-05-23 10:14:20
发布2025-05-23 10:14:20
23200
代码可运行
举报
文章被收录于专栏:学海无涯学海无涯
运行总次数:0
代码可运行

介绍

在现代 iOS 开发中,响应式编程日益重要。Apple 推出的 Combine 框架为开发者提供了强大的声明式 API,用于处理异步事件流。本文将结合常见场景,逐一展示 Combine 的实际用法,包括网络请求、输入控制、定时器、通知监听、异步任务处理以及视图控制器之间的逆向传值。

网络请求

通过 Combine 可以优雅地封装网络请求流程。

代码语言:javascript
代码运行次数:0
运行
复制
let url = URL(string: "https://api.example.com/data")!
// Publisher
let publisher = URLSession.shared.dataTaskPublisher(for: url)
    .map { $0.data }
    .decode(type: Response.self, decoder: JSONDecoder())
    .eraseToAnyPublisher()
// 订阅
let cancellable = publisher
    .sink(receiveCompletion: { completion in
        switch completion {
        case .failure(let error):
            print("Error: \(error)")
        case .finished:
            break
        }
    }, receiveValue: { response in
        print("Response: \(response)")
    })

控制输入

结合 @Published 和 debounce,可以高效地处理用户输入,避免频繁触发操作。

代码语言:javascript
代码运行次数:0
运行
复制
class ViewController: UIViewController {
    @Published var text = ""
    private var cancellables = Set<AnyCancellable>()

    override func viewDidLoad() {
        super.viewDidLoad()

        $text
            .debounce(for: 0.5, scheduler: DispatchQueue.main)
            .sink { [weak self] value in
                guard let self = self else { return }
                self.processInput(value)
            }
            .store(in: &cancellables)
    }

    func processInput(_ input: String) {
        // 处理输入内容
        print("Input: \(input)")
    }
}

定时器

使用 Combine 的 Timer.publish 可以轻松创建定时器。

代码语言:javascript
代码运行次数:0
运行
复制
private var subscription: AnyCancellable?

subscription = Timer
            .publish(every: 1, on: .main, in: .common)
            .autoconnect()
            .scan(0) { count, _ in // 累加,count为闭包最后一次返回的值
                count + 1
            }
            .sink(receiveCompletion: { _ in
                print("finish")
            }, receiveValue: { [weak self] count in // 操作UI时,[weak self]不可少
                guard let self = self else { return }
                self.countLbl.text = count.format
            })

通知

借助 NotificationCenter 和 Combine,可以优雅地响应通知事件。

代码语言:javascript
代码运行次数:0
运行
复制
private var subscriptions = Set<AnyCancellable>()

NotificationCenter
            .default
            .publisher(for: UITextField.textDidChangeNotification, object: inputTxtField) // 监听输入
            .compactMap { ($0.object as? UITextField)?.text } // 此时的publisher是通知
            .map { "The user entered: \($0)" }
            .assign(to: \.text, on: textLbl)
            .store(in: &subscriptions)

异步

通过 Future 可以将传统的回调封装为 Combine 的 Publisher。

代码语言:javascript
代码运行次数:0
运行
复制
// Publisher
func authorize() -> AnyPublisher<Bool, Error> {
        // 延期Publisher等待订阅
        Deferred {
            // 任何异步操作都可以包进Future
            Future { promise in
                UNUserNotificationCenter
                    .current()
                    .requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
                        // Promise处理
                        if let error = error {
                            // AnyPublisher的第2个参数
                            promise(.failure(error))
                        } else {
                            // AnyPublisher的第1个参数
                            promise(.success(granted))
                        }
                    }
            }
        }
        .eraseToAnyPublisher()
    }
    
private var subscriptions = Set<AnyCancellable>()
// 订阅
authorize() // AnyPublisher
            .replaceError(with: false) // 异常处理
            .receive(on: DispatchQueue.main)
            .sink { [weak self] val in
                guard let self = self else { return }
                self.permissionLbl.text = "Status: \(val ? "Granted" : "Denied")"
            }
            .store(in: &subscriptions)

UIViewController逆向传值

当需要从下一个页面传值回当前页面时,Combine 提供了比 delegate 更优雅的方式。

代码语言:javascript
代码运行次数:0
运行
复制
// 接收值的UIViewController
let nextViewController = NextViewController()
let publisher = PassthroughSubject<String, Never>()
nextViewController.publisher = publisher

subscription = publisher.sink { [weak self] info in
    guard let self = self else { return }
    // 处理info
}

present(nextViewController, animated: true)

// 传递值的UIViewController
var publisher: PassthroughSubject<String, Never>?

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    publisher?.send("传值")
    dismiss(animated: true) {
        self.publisher?.send(completion: .finished)
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 网络请求
  • 控制输入
  • 定时器
  • 通知
  • 异步
  • UIViewController逆向传值
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档