SwiftUI - 从 NSObject 继承的 ObservableObject 在 iOS 13 中不更新
SwiftUI - ObservableObject that inherits from NSObject does not update in iOS 13
我知道,这是“在 iOS XX 中不工作”的问题之一,但我完全被困住了...
所以我有一个继承自NSObject
的ObservableObject
class,因为我需要监听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>()
我知道,这是“在 iOS XX 中不工作”的问题之一,但我完全被困住了...
所以我有一个继承自NSObject
的ObservableObject
class,因为我需要监听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>()