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

ahe*_*eze 7 ios swift swiftui observableobject

我知道,这是“无法在 iOS XX 中工作”问题之一,但我完全陷入困境......

所以我有一个ObservableObject继承自 的类NSObject,因为我需要监听 的委托方法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 
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,即使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()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

5秒后,控制台中打印出“updated”,但Text没有改变。在 iOS 14 中,“搜索​​文本:已更新”Text的更改符合预期。

"Updated" printed in console but simulator does not change

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

class SearchBarTester: ObservableObject {

    @Published var searchText: String = ""

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

"Updated" printed in console and simulator also changes

我认为这个问题与从类继承有关。也许这是 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"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Cun*_*eyt 2

似乎在 iOS 13 上,如果您对对象进行子类化并且不ObservableObject直接符合(如 中所示class SearchBarTester: ObservableObject),则需要添加以下样板代码:

@Published var searchText: String = "" {
    willSet {
        objectWillChange.send()
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,调用默认值objectWillChange仍然不起作用,因此您需要自己再次定义它:

let objectWillChange = PassthroughSubject<Void, Never>()
Run Code Online (Sandbox Code Playgroud)