【问题标题】:Generic UITableViewCell with different type of data具有不同类型数据的通用 UITableViewCell
【发布时间】:2019-08-02 20:02:00
【问题描述】:

不同类型的数据键会发生变化,我只想将这个 tableview 单元格用于不同的类型。我不想为每种类型创建新的 tableview 单元格。可能吗?我想我应该使用泛型,但我该如何解决这个问题?

我有一个自定义 UITableViewCell,其中包括

@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var departmentLabel: UILabel!
@IBOutlet weak var genderLabel: UILabel!

{ "data": [ { "type": "employee", "data": { "name": "Michael", "department": "HR", "gender": "Male" } }, { "type": "employer", "data": { "name": "Julia", "division": "Finance", "sex": "Female" } } ] }

【问题讨论】:

  • 有可能。将data(内部data)解码为[String:String],或者——更复杂——将data声明为具有关联类型的枚举。

标签: swift uitableview generics


【解决方案1】:

如果我理解您的问题,您希望采用不同形式但在同一数组中返回的数据可以在单个表格视图单元格中表示。这绝对是可行的,挑战是将可变 JSON 响应解析为一致的内容,您可以将其发送到要显示的单元格。

使用Codable 的自定义实现可以实现这种情况。需要注意的是,您需要知道这些数据可能会出现什么样的选项(即性别总是“性”还是“性别”?)

一个例子是:

struct CompanyPersonContainer: Decodable {
    var data: [CompanyRelatedPerson]

    enum CodingKeys: String, CodingKey {
        case data
    }

    public init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        data = []

        if var dataContainer = try? values.nestedUnkeyedContainer(forKey: CodingKeys.data) {
            while !(dataContainer.isAtEnd) {
                let companyPerson: CompanyRelatedPerson

                if let employee = try dataContainer.decodeIfPresent(Employee.self) {
                    companyPerson = employee
                } else if let employer = try dataContainer.decodeIfPresent(Employer.self) {
                    companyPerson = employer
                } else {
                    fatalError() // You need to know the total possible values you'll be decoding
                }

                data.append(companyPerson)
            }
        }
    }
}

protocol CompanyRelatedPerson: Codable  {
    var name: String { get set }
    var department: String { get set }
    var gender: String { get set }
}

struct Employee: Codable, CompanyRelatedPerson {
    var name: String
    var department: String
    var gender: String
}

struct Employer: Codable, CompanyRelatedPerson {
    var name: String
    var department: String
    var gender: String

    enum CodingKeys: String, CodingKey {
        case name
        case department = "division"
        case gender = "sex"
    }
}

【讨论】:

    【解决方案2】:

    我认为您可以创建一个协议ViewModel,然后创建继承该协议的不同视图模型。

    protocol ViewModel {
        var name: String { get set }
        var department: String { get set }
        var gender: String { get set }
    }
    
    struct EmployeeViewModel: ViewModel {
       var name: String
       var department: String
       var gender: String
    
       // Suppose you already have this data model from data.
       init(employee: Employee) {
          self.name = employee.name
          self.department = employee.department
          self.gender = employee.gender
       }
    }
    
    struct Employer: ViewModel {
       var name: String
       var department: String
       var gender: String
    
       init(employer: Employer) {
           self.name = employer.name
           self.department = employer.division
           self.gender = employer.sex
       }
    }
    

    然后,在您的表格视图单元格中创建一个函数以将值分配给您的属性。

    // In your table view cell
    func setViewModel(_ viewModel: ViewModel) {
        self.nameLabel.text = vm.name
        // do the same for the rest of labels...
    }
    

    对我来说,使用协议视图模型的优点是您可以将从协议继承的任何视图模型传递给您的视图以分配值,从而避免在视图中暴露您的数据(在这种情况下为表格视图单元格)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-09
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多