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的主要内容,如果未能解决你的问题,请参考以下文章