SwiftUI - 从 NSObject 继承的 ObservableObject 在 iOS 13 中不更新

SwiftUI - ObservableObject that inherits from NSObject does not update in iOS 13

我知道,这是“在 iOS XX 中不工作”的问题之一,但我完全被困住了...

所以我有一个继承自NSObjectObservableObjectclass,因为我需要监听UISearchResultsUpdating的委托方法。

class SearchBarListener: NSObject, UISearchResultsUpdating, ObservableObject {
    
    @Published var searchText: String = ""
    let searchController: UISearchController = UISearchController(searchResultsController: nil)
    
    override init() {
        super.init()
        self.searchController.searchResultsUpdater = self
    }
    
    func updateSearchResults(for searchController: UISearchController) {
        
        /// Publish search bar text changes
        if let searchBarText = searchController.searchBar.text {
            print("text: \(searchBarText)")
            self.searchText = searchBarText
        }
    }
}

struct ContentView: View {
    @ObservedObject var searchBar = SearchBarListener()
    
    var body: some View {
        Text("Search text: \(searchBar.searchText)")
        .padding()

        /// more code that's not related 
    }
}

问题是即使 print("text: \(searchBarText)") 打印正常,Text("Search text: \(searchBar.searchText)") 从未更新(在 iOS 13 中)。它在 iOS 14.

中工作正常

这是一个最小的可重现示例:

class SearchBarTester: NSObject, ObservableObject {

    @Published var searchText: String = ""

    override init() {
        super.init()
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            print("updated")
            self.searchText = "Updated"
        }
    }
}

struct ContentView: View {
    @ObservedObject var searchBar = SearchBarTester()
    
    var body: some View {
        NavigationView {
            Text("Search text: \(searchBar.searchText)")
            .padding()
        }
    }
}

5 秒后,“已更新”打印在控制台中,但 Text 没有改变。在 iOS 14 中,Text 更改为 "Search text: Updated",如预期的那样。

但是,如果我不从 NSObject 继承, iOS 13 和 iOS 14 都可以工作!

class SearchBarTester: ObservableObject {

    @Published var searchText: String = ""

    init() {
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            print("updated")
            self.searchText = "Updated"
        }
    }
}    

我认为问题与从 class 继承有关。也许这是在 iOS 14 中修复的问题。但是有人知道发生了什么吗?


编辑

感谢@Cuneyt的回答!这是最终起作用的代码:

import SwiftUI
import Combine /// make sure to import this

class SearchBarTester: NSObject, ObservableObject {

    let objectWillChange = PassthroughSubject<Void, Never>()
    @Published var searchText: String = "" {
        willSet {
            self.objectWillChange.send()
        }
    }

    override init() {
        super.init()

        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            print("updated")
            self.searchText = "Updated"
        }
    }
}

它似乎在 iOS 13 上,如果你子类化一个对象并且不直接符合 ObservableObject(如 class SearchBarTester: ObservableObject),你需要添加这个样板代码:

@Published var searchText: String = "" {
    willSet {
        objectWillChange.send()
    }
}

但是调用默认的objectWillChange还是不行,需要自己重新定义:

let objectWillChange = PassthroughSubject<Void, Never>()