繁体   English   中英

在 SwiftUI 中实例化自定义视图时,如何动态声明变量类型然后将其用作参数?

[英]How can I dynamically declare a variable type then use it as an argument when instantiating a custom view in SwiftUI?

我在做什么:

我正在制作一个可重用的tableView并且刚刚完成,但是我无法在我的视图 model 中引用属性,因为我已将我的 model 类型声明为表视图结构中的AnyObject

我想在实例化tableView时动态声明变量类型。

例如,这是我使用自定义表格视图的方式:

struct MyView: View {
    @EnvironmentObject var myViewModel: MyViewModel

    var body: some View {

        return

          CustomTableView(model: myViewModel as MyViewModel)
    }
}

如您所见,我必须在视图中声明类型,因为我在表视图结构中使用AnyObject类型。 这是因为 model 会根据我使用自定义表格视图的位置而有所不同,因此我需要灵活性。

这是我的表视图结构:

struct CustomTableView: UIViewRepresentable {

    var model: AnyObject
    class Coordinator: NSObject, UITableViewDelegate, UITableViewDataSource {

        var customTableView: CustomTableView
        let cellIdentifier = "MyCell"

        init(_ customTableView: customTableView) {
            self.customTableView = customTableView
        }

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

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 7
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MyTableViewCell
            return cell
        }
    }

    func makeCoordinator() -> DabbleTableView.Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UITableView {  
        let cellIdentifier = "MyCell"
        let tableView = UITableView()
        tableView.delegate = context.coordinator
        tableView.dataSource = context.coordinator
        tableView.register(MyTableViewCell.self, forCellReuseIdentifier: cellIdentifier)
        tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
        return tableView    
    }

    func updateUIView(_ uiViewController: UITableView, context: Context) {           
    }
}

我想做的事:

要么让表视图自动使用在实例化表视图时声明的ViewModel类型名称,要么在实例化表视图时传入正确的ViewModel类型。

我不清楚如何做到这一点。 我在想类型别名可能有用,但我读得越多,我就越意识到这不是正确的解决方案。

将类型作为字符串传递不起作用,因为 Swift 会将参数识别为字符串。

最干净的方法是什么?

提前致谢。

可能的方法是使用 generics (如果/需要时也符合任何自定义协议),因此您不需要转换类型并将其用作

struct MyView: View {
    @EnvironmentObject var myViewModel: MyViewModel

    var body: some View {
        CustomTableView(model: myViewModel)
    }
}

所以CustomTableView应该声明为

struct CustomTableView<Model:ObservableObject>: UIViewRepresentable {

    var model: Model

    ...

使用 Xcode 11.4 / iOS 13.4 测试

更新:下面是可编译的例子

// base protocol for CustomTableView model
protocol CustomTableViewModel {
    func numberOfSections() -> Int
    func numberOfRows(in section: Int) -> Int
}

// some specific model
class MyViewModel: ObservableObject, CustomTableViewModel {
    func numberOfSections() -> Int { 1 }
    func numberOfRows(in section: Int) -> Int { 7 }
}

// usage
struct MyView: View {
    @EnvironmentObject var myViewModel: MyViewModel

    var body: some View {
        CustomTableView(model: myViewModel)
    }
}

// generic table view
struct CustomTableView<Model:ObservableObject & CustomTableViewModel>: UIViewRepresentable {

    var model: Model

    class Coordinator: NSObject, UITableViewDelegate, UITableViewDataSource {

        var customTableView: CustomTableView
        let cellIdentifier = "MyCell"

        init(_ customTableView: CustomTableView) {
            self.customTableView = customTableView
        }

        func numberOfSections(in tableView: UITableView) -> Int {
            customTableView.model.numberOfSections()
        }

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            customTableView.model.numberOfRows(in: section)
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MyTableViewCell
            return cell
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UITableView {
        let cellIdentifier = "MyCell"
        let tableView = UITableView()
        tableView.delegate = context.coordinator
        tableView.dataSource = context.coordinator
        tableView.register(MyTableViewCell.self, forCellReuseIdentifier: cellIdentifier)
        tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
        return tableView
    }

    func updateUIView(_ uiViewController: UITableView, context: Context) {
    }
}

class MyTableViewCell: UITableViewCell { }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM