如何解决在 SwiftUI 中,视图不会随着模型更新而更新
在项目中,我调用了 Google 的 eBook API 来列出图书。它默认列出哈利波特书籍。除此之外,我有一个搜索栏来搜索其他主题的书,比如“java”。它工作正常,当我开始在搜索字段中写入时,我的视图模型会更新模型中的书籍数组。但是,它根本没有更新我的观点。我已提供以下所有代码。
型号:
import Foundation
struct BookModel {
var books: [Book] = []
struct Book: Identifiable {
var id: String
var title: String
var authors: String
var desc: String
var imurl: String
var url: String
}
}
视图模型:
import Foundation
import SwiftyJSON
class BookViewModel: ObservableObject {
@Published var model = BookModel()
init(searchText: String) {
let url = "https://www.googleapis.com/books/v1/volumes?q=\(searchText)"
print(url)
let session = URLSession(configuration: .default)
session.dataTask(with: URL(string: url)!) { (resp,_,error) in
if error != nil {
print(error?.localizedDescription ?? "Error")
return
}
let json = try! JSON(data: resp!)
let items = json["items"].array!
for item in items {
let id = item["id"].stringValue
let title = item["volumeInfo"]["title"].stringValue
let authors = item["volumeInfo"]["authors"].array ?? []
var author: String = ""
for name in authors {
author += "\(name.stringValue)"
}
let description = item["volumeInfo"]["description"].stringValue
let imurl = item["volumeInfo"]["imageLinks"]["thumbnail"].stringValue
let webReaderLink = item["volumeInfo"]["previewLink"].stringValue
print(title)
DispatchQueue.main.async {
self.model.books.append(BookModel.Book(id: id,title: title,authors: author,desc: description,imurl: imurl,url: webReaderLink))
}
}
}
.resume()
// For testing
for i in model.books {
print(i.title)
}
}
//MARK:- Access to the model
var books: [BookModel.Book] {
model.books
}
}
内容视图:
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel = BookViewModel(searchText: "harry+potter")
var body: some View {
CustomNavigationView(view: AnyView(Home(viewModel: viewModel)),placeHolder: "Search",largeTitle: true,title: "Books") { (text) in
if text != "" {
BookViewModel(searchText: text.lowercased().replacingOccurrences(of: " ",with: "+"))
}
} onCancel: {
BookViewModel(searchText: "harry+potter")
}
.edgesIgnoringSafeArea(.all)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
主页:
import SwiftUI
import SDWebImageSwiftUI
struct Home: View {
@ObservedObject var viewModel: BookViewModel
@State private var show: Bool = false
@State var previewURL = ""
var body: some View {
List {
ForEach(viewModel.books) { book in
HStack {
if book.imurl != "" {
WebImage(url: URL(string: book.imurl))
.resizable()
.frame(width: 120,height: 170)
} else {
Image(systemName: "character.book.closed.fill")
.font(.system(size: 60))
.frame(width: 120,height: 170)
}
VStack(alignment: .leading,spacing: 10) {
Text(book.title)
.fontWeight(.bold)
Text(book.authors)
Text(book.desc)
.font(.system(size: 13))
.lineLimit(4)
.multilineTextAlignment(.leading)
}
}
.onTapGesture {
self.previewURL = book.url
show.toggle()
}
}
}
.sheet(isPresented: $show) {
NavigationView {
WebView(url: $previewURL)
.navigationBarTitle("Book Preview")
}
}
}
}
自定义导航视图:
import SwiftUI
struct CustomNavigationView: UIViewControllerRepresentable {
func makeCoordinator() -> Coordinator {
return CustomNavigationView.Coordinator(parent: self)
}
var view: AnyView
//onSearch and onCancel Closures
var onSearch: (String) -> ()
var onCancel: () -> ()
var title: String
var largeTitle: Bool
var placeHolder: String
init(view: AnyView,placeHolder: String? = "Search",largeTitle: Bool? = false,title: String,onSearch: @escaping (String) -> (),onCancel: @escaping () -> ()) {
self.title = title
self.largeTitle = largeTitle!
self.placeHolder = placeHolder!
self.view = view
self.onSearch = onSearch
self.onCancel = onCancel
}
func makeUIViewController(context: Context) -> UINavigationController {
let childView = UIHostingController(rootView: view)
let controller = UINavigationController(rootViewController: childView)
controller.navigationBar.topItem?.title = title
controller.navigationBar.prefersLargeTitles = largeTitle
let searchController = UISearchController()
searchController.searchBar.placeholder = placeHolder
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.delegate = context.coordinator
controller.navigationBar.topItem?.hidesSearchBarWhenScrolling = false
controller.navigationBar.topItem?.searchController = searchController
return controller
}
func updateUIViewController(_ uiViewController: UINavigationController,context: Context) {
uiViewController.navigationBar.topItem?.title = title
uiViewController.navigationBar.topItem?.searchController?.searchBar.placeholder = placeHolder
uiViewController.navigationBar.prefersLargeTitles = largeTitle
}
//Search Bar Delegate
class Coordinator: NSObject,UISearchBarDelegate {
var parent: CustomNavigationView
init(parent: CustomNavigationView) {
self.parent = parent
}
func searchBar(_ searchBar: UISearchBar,textDidChange searchText: String) {
self.parent.onSearch(searchText)
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.parent.onCancel()
}
}
}
完整项目链接: https://github.com/shawkathSrijon/eBook-Reader.git
解决方法
您可能需要使用 ObservableObjectPublisher
objectWillChange
来表达您对新更改的看法。
DispatchQueue.main.async {
self.model.books.append(BookModel.Book(id: id,title: title,authors: author,desc: description,imurl: imurl,url: webReaderLink))
self.objectWillChange.send() // <-- Here
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。