在开发一个待办事项App时,你可能希望用户输入文字时,界面上的文字实时更新。过去这种需求需要写不少代理方法或通知,代码绕来绕去,容易出错。而现在,SwiftUI与Combine结合,让这类响应式编程变得自然又简洁。
数据驱动界面的新方式
SwiftUI的核心是声明式语法,界面由数据状态决定。当数据变化时,界面自动刷新。Combine是Apple推出的响应式框架,用来处理随时间变化的数据流。两者搭配,就像拼积木一样顺手。
比如,你有一个文本框,想让用户每输入一个字符,就立刻过滤出匹配的搜索结果。用@State配合@Published属性,再接入Combine的订阅机制,几行代码就能搞定。
import SwiftUI
import Combine
class SearchViewModel: ObservableObject {
@Published var searchText = ""
@Published var results: [String] = []
private var cancellables = Set<AnyCancellable>()
init() {
$searchText
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.removeDuplicates()
.flatMap { query -> Future<[String], Never> in
Future { promise in
if query.isEmpty {
promise(.success([]))
} else {
let filtered = allItems.filter { $0.localizedCaseInsensitiveContains(query) }
promise(.success(filtered))
}
}
}
.receive(on: RunLoop.main)
.assign(to: \..results, on: self)
.store(in: &cancellables)
}
}
界面同步不再靠手动刷新
在SwiftUI中,只要数据被@Published标记,任何对它的修改都会触发视图更新。Combine负责监听这些变化,并在合适时机处理逻辑,比如防抖、异步请求、合并多个信号等。
想象你在做一个天气App,位置变化时要自动刷新天气。你可以把CLLocationManager封装成一个Publisher,然后和网络请求链式连接。一旦位置更新,整个流程自动走完,最后刷新UI,中间不需要手动调用刷新方法。
减少样板代码,聚焦业务逻辑
以前处理网络回调嵌套、KVO观察、通知中心注册注销,常常要写一堆模板代码。现在通过Combine的操作符,像map、filter、catch、retry,可以把逻辑串联起来,错误处理也更集中。
比如用户登录后要拉取用户信息和设置默认头像,可以使用zip操作符并行请求:
let userRequest = URLSession.shared.dataTaskPublisher(
for: userUrl)
.map(\..data)
.decode(type: User.self, decoder: JSONDecoder())
let avatarRequest = URLSession.shared.dataTaskPublisher(
for: avatarUrl)
.map(\..data)
Publishers.Zip(userRequest, avatarRequest)
.receive(on: RunLoop.main)
.sink { completion in
if case .failure(let error) = completion {
print("加载失败:\(error)")
}
} receiveValue: { user, imageData in
self.currentUser = user
self.avatarImage = UIImage(data: imageData)
}
.store(in: &cancellables)
SwiftUI与Combine结合,不只是技术升级,更是一种思维方式的转变——从“什么时候该做什么”变成“数据变了会怎样”。对于刚入门iOS开发的人来说,早点接触这种模式,以后写复杂功能会轻松不少。