Swift常见的支持 Publisher 响应式处理的类或场景
Swift常见的支持 Publisher 响应式处理的类或场景

Swift常见的支持 Publisher 响应式处理的类或场景

Swift 提供了多个类,通过 Combine 的 Publisher 系统 扩展了响应式处理的能力。这种设计思路常见于系统框架,目的是让传统的功能模块能够以响应式的方式与 Combine 集成。以下是一些常见的例子:

1、Timer

Timer.publish 提供了一种更现代化和响应式的方法来使用定时器。与传统的 Timer.scheduledTimer 或 Timer 构造器不同,它不是直接触发回调,而是返回一个 Combine 的 Publisher。这种机制更加适合 SwiftUI 的声明式和响应式编程风格。

使用方式

let timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()
@State private var counter = 0
Text("Hello, World!")
    .onReceive(timer) { time in
        if counter == 5 {
            timer.upstream.connect().cancel()
        } else {
            print("The time is now \(time)")
        }
        counter += 1
    }

2、NotificationCenter

NotificationCenter 是一个发布-订阅模式的中心,通常用于系统级和应用内部的事件通知。通过 Combine,可以将 NotificationCenter 的通知转化为 Publisher。

使用方式

let publisher = NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)

publisher.sink { notification in
    print("App became active!")
}

核心特性

1)publisher(for:) 方法:将特定的通知转换为一个 Combine Publisher。

2)返回值类型:NotificationCenter.Publisher,输出值为 Notification。

常见用途

监听系统通知(如键盘显示、应用状态变更)。

处理自定义的广播事件。

3、URLSession

URLSession 是用于网络请求的核心类。结合 Combine,可以将网络请求结果转化为 Publisher,避免传统的回调或闭包模式。

使用方式

let url = URL(string: "https://api.example.com/data")!
let publisher = URLSession.shared.dataTaskPublisher(for: url)

publisher
    .map(\.data)
    .decode(type: MyDataModel.self, decoder: JSONDecoder())
    .sink(
        receiveCompletion: { completion in
            print("Completion: \(completion)")
        },
        receiveValue: { data in
            print("Received data: \(data)")
        }
)

核心特性

1)dataTaskPublisher(for:) 方法:返回 URLSession.DataTaskPublisher,用来处理网络请求。

2)返回值类型:Publisher,输出值为 (Data, URLResponse)。

优势

支持链式数据处理(如解析 JSON)。

与错误处理(tryCatch 等)集成简洁。

4、CLLocationManager

CLLocationManager 是获取地理位置信息的核心类。通过 Combine 的扩展,可以将位置更新事件转化为 Publisher。

扩展实现 原生的 CLLocationManager 没有直接支持 Combine,但可以通过自定义扩展实现。例如:

import Combine
import CoreLocation

class LocationManager: NSObject, ObservableObject {
    private let manager = CLLocationManager()
    let publisher = PassthroughSubject<CLLocation, Never>()

    override init() {
        super.init()
        manager.delegate = self
        manager.requestWhenInUseAuthorization()
    }
}

extension LocationManager: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            publisher.send(location)
        }
    }
}

结合 SwiftUI 使用

import SwiftUI
import CoreLocation

struct ContentView: View {
    @StateObject private var locationManager = LocationManager()
    @State private var location: CLLocation?

    var body: some View {
        Text(location != nil ? "Lat: \(location!.coordinate.latitude)" : "Fetching location...")
            .onReceive(locationManager.publisher) { newLocation in
                location = newLocation
            }
    }
}

5、FileManager

虽然 FileManager 本身不直接支持 Combine,但可以通过封装创建一个 Publisher 来监听文件变化。例如,监控目录内容的变化。

自定义 FileManager 的 Publisher

import Combine

extension FileManager {
    func publisher(for directory: URL) -> AnyPublisher<[URL], Error> {
        Future { promise in
            do {
                let contents = try self.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil)
                promise(.success(contents))
            } catch {
                promise(.failure(error))
            }
        }
        .eraseToAnyPublisher()
    }
}

结合使用

let directoryURL = URL(fileURLWithPath: "/path/to/directory")
FileManager.default.publisher(for: directoryURL)
    .sink(
        receiveCompletion: { completion in
            print("Completion: \(completion)")
        },
        receiveValue: { files in
            print("Files: \(files)")
        }
)

6、AVPlayer

AVPlayer 是用于播放音视频的类。通过 Combine,可以监听播放器状态和时间进度。

时间进度 Publisher

let player = AVPlayer(url: URL(string: "https://example.com/video.mp4")!)

let timePublisher = player.publisher(for: \.currentTime)
timePublisher
    .sink { time in
        print("Current time: \(CMTimeGetSeconds(time))")
}

结合 KVO

Combine 提供了一种便捷的方法,通过 @Published 属性或 publisher(for:) 监听 KVO 属性。

let statusPublisher = player.publisher(for: \.status)
statusPublisher
    .sink { status in
        print("Player status: \(status)")
    }

7、UserDefaults

UserDefaults 的变化也可以转化为 Publisher。

实现方式

通过 Combine 的 @Published 属性包装 UserDefaults 的值,或者通过 NotificationCenter 的 Combine Publisher 监听变化:

let defaults = UserDefaults.standard
let publisher = NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification)

publisher.sink { _ in
    print("UserDefaults changed")
}

总结

以下是一些常见的支持 Publisher 响应式处理的类或场景:

1、Timer:publish(every:on:in:),用途为定时事件流;

2、NotificationCenter:publisher(for:) ,用途为系统或自定义通知;

3、URLSession:dataTaskPublisher(for:) ,用途为网络请求;

4、CLLocationManager:自定义 Publisher(Combine 扩展),用途为地理位置更新;

5、FileManager:自定义目录变化的 Publisher,用途为监听文件系统

6、AVPlayer:KVO 或 Combine 扩展,用途为音视频播放状态、时间更新;

7、UserDefaults:NotificationCenter 或 @Published,用途为偏好设置变化。

Combine 的设计理念是使一切皆可响应,因此许多系统类都通过 Publisher 进行扩展或者可以轻松集成到响应式流中。

相关文章

Swift和Foundation框架创建和管理定时任务的Timer类:https://fangjunyu.com/2024/12/14/swift%e5%92%8cfoundation%e6%a1%86%e6%9e%b6%e5%88%9b%e5%bb%ba%e5%92%8c%e7%ae%a1%e7%90%86%e5%ae%9a%e6%97%b6%e4%bb%bb%e5%8a%a1%e7%9a%84timer%e7%b1%bb/

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注