Как я могу динамически объявить тип переменной, а затем использовать его в качестве аргумента при создании пользовательского представления в SwiftUI? - PullRequest
0 голосов
/ 09 апреля 2020

Что я делаю:

Я делаю многоразовый tableView и почти закончил, но я не могу ссылаться на свойства в моей модели представления, потому что я объявил мой тип модели как AnyObject внутри структуры табличного представления.

Я хочу динамически объявить тип переменной при создании экземпляра tableView.

Например, это как я использую свое собственное табличное представление:

struct MyView: View {
    @EnvironmentObject var myViewModel: MyViewModel

    var body: some View {

        return

          CustomTableView(model: myViewModel as MyViewModel)
    }
}

Как вы можете видеть, я должен объявить тип в моем представлении, потому что я использую тип AnyObject в своей структуре табличного представления. Это связано с тем, что модель будет отличаться в зависимости от того, где я использую настраиваемое табличное представление, и поэтому мне нужна гибкость.

Это мое табличное представление Структура:

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 распознает аргумент в виде строки.

Какой самый чистый способ сделать это?

Заранее спасибо.

1 Ответ

0 голосов
/ 09 апреля 2020

Возможный подход состоит в том, чтобы использовать дженерики (соответствующие также любому пользовательскому протоколу, если / когда это необходимо), поэтому вам не нужно приводить типы и использовать его как

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 { }
...