iOS 17中如何用Swift并发与Observation框架监听搜索栏值变化
iOS 17 @Observable 监听搜索文本变化的正确方式
在iOS 17的@Observable框架中,属性并没有直接提供类似@Published的$values异步序列,所以直接使用searchText.async无法监听到变化。下面提供两种可靠的实现方式:
方法一:结合Combine PassthroughSubject(兼容旧习惯)
利用Combine的PassthroughSubject转发searchText的变化,再转换成AsyncStream供并发监听,逻辑和你之前用@Published的写法最接近:
import Combine @Observable final class SearchableViewModel { // 用@ObservationIgnored标记,避免Observation框架跟踪该Subject @ObservationIgnored private let searchTextSubject = PassthroughSubject<String, Never>() var searchText: String = "" { didSet { searchTextSubject.send(searchText) } } func listenToSearchQuery() async { // 将Subject转换为AsyncStream进行监听 for await searchQuery in searchTextSubject.values { print(searchQuery) // 可选:添加防抖逻辑,避免输入过程中频繁触发 // try? await Task.sleep(nanoseconds: 300_000_000) // if searchQuery == self.searchText { ... } } } }
视图代码无需修改,保持你原来的写法即可。
方法二:纯Observation框架实现(无Combine依赖)
如果不想依赖Combine,可使用withObservationTracking构建AsyncStream来监听属性变化:
@Observable final class SearchableViewModel { var searchText: String = "" // 创建监听searchText变化的AsyncStream private func searchTextStream() -> AsyncStream<String> { AsyncStream { continuation in // 监听应用退后台事件,防止内存泄漏 let backgroundTask = Task { for await _ in NotificationCenter.default.notifications(named: UIApplication.willResignActiveNotification) { continuation.finish() } } continuation.onTermination = { @Sendable _ in backgroundTask.cancel() } // 启动Observation跟踪,递归调用持续监听下一次变化 func trackChanges() { withObservationTracking { _ = self.searchText } onChange: { continuation.yield(self.searchText) trackChanges() } } trackChanges() } } func listenToSearchQuery() async { for await searchQuery in searchTextStream() { print(searchQuery) } } }
额外优化:防抖处理
搜索场景通常需要防抖,避免输入过程中频繁触发逻辑,可在监听代码中添加延迟判断:
func listenToSearchQuery() async { for await searchQuery in searchTextSubject.values { try? await Task.sleep(nanoseconds: 300_000_000) // 仅当当前文本与触发时的文本一致时,才执行后续逻辑(避免处理过时输入) if searchQuery == self.searchText { print("处理搜索请求:\(searchQuery)") } } }
内容的提问来源于stack exchange,提问作者svranaw
相关产品推荐
相关产品推荐

