【问题标题】:Swift array of UIView subclasses conforming to a protocol符合协议的 UIView 子类的 Swift 数组
【发布时间】:2016-11-19 00:32:45
【问题描述】:

镜像 Obj-C 的 @property (nonatomic) NSArray <SomeProtocol>* items; 的最佳方式是什么,其中项目是 UIView 子类?

在下面的示例中,我想存储一个 UIKit 组件数组(例如 UILabelUIButton 等),它们都符合协议,但这会产生错误 Protocol can only be used as a generic constraint because it has Self or associated type requirements

有哪些其他的建模方法?

示例游乐场:

import UIKit

/// Protocol representing a form field model
protocol FieldRepresentable {}

/// Protocol representing a form UI control
protocol FormControllable {
    associatedtype FieldRepresentable

    init(model: FieldRepresentable)

    var model: FieldRepresentable { get }
}

/// Example label model
class FormLabelElement: FieldRepresentable {}

/// Example label UI control
class FormLabel: UILabel, FormControllable {

    required init(model: FormLabelElement) {
        self.model = model

        super.init(frame: CGRect.zero)
    }

    let model: FormLabelElement

    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}

/// Example form
class Form: UIView {

    // Error here
    var fields: [FormControllable]?

}

【问题讨论】:

标签: ios swift generics swift3 protocols


【解决方案1】:

内特库克建议

一种简单的解决方法是从FormControllable 中删除关联类型并使其init 失效。每个符合的类型基本上都必须验证它知道如何处理传递的特定 FieldRepresentable 类型。我认为你会失去一点类型安全/表达式,但会获得拥有非均匀数组的能力

所以该方法的最终版本是:

import UIKit

/// Protocol representing a form field model that is used to instantiate a UI control
protocol FieldRepresentable: class {}

/// Protocol representing a form UI control
protocol FormControllable: class {
    init?(model: FieldRepresentable)
}

/// Example label model
class FormLabelElement: FieldRepresentable {}

/// Example label UI control
class FormLabel: UILabel, FormControllable {

    required init?(model: FieldRepresentable) {
        guard let model = model as? FormLabelElement else { return nil }
        self.model = model

        super.init(frame: CGRect.zero)
    }

    let model: FormLabelElement

    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}

/// Example form
class Form: UIView {
    var fields = [FormControllable]()
}

// Create a form
let form = Form()
let labelModel = FormLabelElement()
let labelField = FormLabel(model: labelModel)!
form.fields.append(labelField)
print(form.fields)

form.fields.forEach { (field) in
    if field is FormLabel {
        print("We have a label field")
    }
}

另外,如果您的模型协议足够通用,Soroush 建议

一个想法是将您的字段可表示类型变成一个枚举,因为表单字段元素的类型有一定数量

那么你只需要一个大开关,将枚举转换为表单元素

您可以获取一个字段数据案例数组并将它们映射到一个表单元素数组中

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-05
    相关资源
    最近更新 更多