TableView 重新加载不适用于 SwiftUI 中的 UIViewRepresentable

Posted

技术标签:

【中文标题】TableView 重新加载不适用于 SwiftUI 中的 UIViewRepresentable【英文标题】:TableView Reload Not working with UIViewRepresentable in SwiftUI 【发布时间】:2020-08-06 14:09:26 【问题描述】:

在收到 API 响应后,我正在尝试重新加载 tableView。 TableView 重新加载不会调用cellForRowAt,因为它最初是用空项目初始化的。我添加了复制问题所需的最少代码。

UIViewRepresentable的代码

import SwiftUI
import UIKit

struct UIListView: UIViewRepresentable 
    
    @Binding var reload: Bool
    
    var items: [String]
    private let tableView =  UITableView()
    
    func makeUIView(context: Context) -> UITableView 
        print("*************** make")
        tableView.dataSource = context.coordinator
        return tableView
    
    
    func updateUIView(_ uiView: UITableView, context: Context) 
        print("*************** update", items.count)
        print("********* RELOAD", reload)
        if reload 
            DispatchQueue.main.async 
                //                uiView.reloadData()
                //                tableView.reloadData()
                context.coordinator.reload()
            
        
    
    
    func makeCoordinator() -> Coordinator 
        Coordinator(self)
    


extension UIListView 
    
    final class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate 
        
        private var parent: UIListView
        
        init(_ parent: UIListView) 
            self.parent = parent
        
        
        func reload() 
            parent.tableView.reloadData()
        
        
        //MARK: UITableViewDataSource Methods
        
        func numberOfSections(in tableView: UITableView) -> Int 
            return 1
        
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
            return parent.items.count
        
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
            print("*********Cell for row at")
            let cell = UITableViewCell()
            cell.textLabel?.text = parent.items[indexPath.row]
            return cell
        
    

CustomListView 和 ViewModel 的代码

    struct CustomListView: View 
    @ObservedObject var model = VM()
    
    var body: some View 
        print("******* BODY")
        return UIListView(reload: $model.reload, items: model.items)
            .onAppear 
                model.fetchData()
            
    


class VM: ObservableObject 
    
    @Published var reload = false
    var items = [String]()
    
    func fetchData() 
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) 
            self.items = ["asdas", "asdasdas"]
            self.reload.toggle()
        
    

【问题讨论】:

【参考方案1】:

我假设 UITableView 成员刚刚重新创建,因为它是成员,而是如下使用

使用 Xcode 12 / ios 14 测试

struct CustomListView: View 
    @StateObject var model = VM()

    var body: some View 
        print("******* BODY")
        return UIListView(reload: $model.reload, items: $model.items)
            .onAppear 
                model.fetchData()
            
    


class VM: ObservableObject 

    @Published var reload = false
    var items = [String]()

    func fetchData() 
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) 
            self.items = ["asdas", "asdasdas"]
            self.reload.toggle()
        
    


struct UIListView: UIViewRepresentable 

    @Binding var reload: Bool
    @Binding var items: [String]

    func makeUIView(context: Context) -> UITableView 
        print("*************** make")
        let tableView =  UITableView()
        tableView.dataSource = context.coordinator
        return tableView
    

    func updateUIView(_ tableView: UITableView, context: Context) 
        print("*************** update", items.count)
        print("********* RELOAD", reload)
        if reload 
            DispatchQueue.main.async 
                tableView.reloadData()
            
        
    

    func makeCoordinator() -> Coordinator 
        Coordinator(self)
    


extension UIListView 

    final class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate 

        private var parent: UIListView

        init(_ parent: UIListView) 
            self.parent = parent
        

        //MARK: UITableViewDataSource Methods

        func numberOfSections(in tableView: UITableView) -> Int 
            return 1
        

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
            return parent.items.count
        

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
            print("*********Cell for row at")
            let cell = UITableViewCell()
            cell.textLabel?.text = parent.items[indexPath.row]
            return cell
        
    

【讨论】:

它对你有用吗?它在 Xcode beta 3 上对我不起作用,已经尝试过你提到的方式。 很好用。你有什么解释为什么只使用 reload as Binding 不起作用? items 是值和结构的一部分,所以Coordinator init 只是复制空并存储它。绑定允许访问可更新的数据存储。 现在这对我来说很有意义,这意味着如果我删除重新加载绑定,它应该仍然可以工作。

以上是关于TableView 重新加载不适用于 SwiftUI 中的 UIViewRepresentable的主要内容,如果未能解决你的问题,请参考以下文章

使用 DirtiesContext 注释重新加载 Spring 应用程序不适用于嵌套类

tableview 不会从第二类正确重新加载

然后在 Promisekit 中重新加载 tableview

modalview 关闭后 TableView 未重新加载

Swift - 添加到数组后 tableView 不重新加载

Swift 3:TableView 刷新不适用于行操作