Combine

数据绑定与界面刷新

920 发布: 2025/2/8 17:20 本文总阅读量

界面刷新

// 扩展属性并监听输入变化
extension UISearchBar {
    var textDidChangePublisher: AnyPublisher<String, Never> {
        let textField = value(forKey: "searchField") as? UITextField
        return NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: textField)
            .compactMap { $0.object as? UITextField }
            .map { $0.text ?? "" }
            .eraseToAnyPublisher()
    }
}

class SearchViewModel {
    // 当你使用 @Published 修饰一个属性时,Swift 会自动为该属性创建一个 Published 类型的包装器实例,并且可以通过属性名加 $ 前缀的方式来访问对应的发布者
    @Published private(set) var searchRes: [String] = []

    func search(query: String) {
        // 模拟网络请求
        DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {
            let res = (0..<10).map { val in
                "\(query) reslt \(val)"
            }
            self.searchRes = res
        }
    }
}
func dTs2() {
     //
     let searchBar = UISearchBar()
     searchBar.frame = CGRect(x: 100, y: 200, width: 200, height: 40)
     searchBar.backgroundColor = .hex("#ff0000",0.6)
     view.addSubview(searchBar)

     var viewModel = SearchViewModel()

     // 订阅输入变化
     searchBar.textDidChangePublisher
         .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
         .removeDuplicates()
         .sink { val in
             viewModel.search(query: val)
         }
         .store(in: &cancelSet)

     // 订阅搜索结果,这里可以显示到tableview
     viewModel.$searchRes
         .receive(on: DispatchQueue.main)
         .sink { val in
             debug.log("ui-res:", val)
         }
         .store(in: &cancelSet)
 }

数据绑定

class UserModel {
    @Published var name: String
    @Published var age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

class UserViewModel {
    @Published private(set) var displayName = ""
    private var user: UserModel
    private var cancellable = Set<AnyCancellable>()
    init(user: UserModel) {
        self.user = user
        setupBindings()
    }

    private func setupBindings() {
        Publishers.CombineLatest(user.$name, user.$age)
            .map { name, age in
                return "\(name) (\(age) years old)"
            }
            .assign(to: \.displayName, on: self)
            .store(in: &cancellable)
    }

    func changeData() {
        user.name = "xiaoming"
        user.age = 12
    }
}
 func dTs1() {
     // 数据绑定
     let user = UserModel(name: "Joy", age: 30)
     let viewModel = UserViewModel(user: user)

     // 订阅
     viewModel.$displayName
         .receive(on: DispatchQueue.main)
         .sink { val in
             debug.log("binddata-val:", val)
         }
         .store(in: &cancelSet)

     // 测试改变
     viewModel.changeData()
 }