通用视图配置器

时间:2019-07-18 06:26:21

标签: swift

我正在尝试使用Swift中的泛型来解决某些问题,但是我做错了一些我似乎无法弄清的错误。我有2个具有相同ui组件的视图,但是它们在视觉上有所不同,但是内容相同。

因此,我想抽象化填充视图的方式,以便可以重用该代码。 (我将示例简化到最低限度。)

protocol ViewConfigurator {
    associatedtype View: UIView

    init(view: View)

    func configure()
}

protocol PersonView: UIView {
    var nameLabel: UILabel { get }
}

class BigPersonView: UIView, PersonView {
    var nameLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
}

class SmallPersonView: UIView, PersonView {
    var nameLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
}


class PersonViewConfigurator: ViewConfigurator {
    private let view: PersonView

    required init(view: PersonView) {
        self.view = view
    }

    func configure() {
        view.nameLabel.text = "Swift"
    }
}

但是我在操场上遇到的错误是:

  

操场执行失败:

     

错误:MyPlayground.playground:24:7:错误:类型'PersonViewConfigurator'不符合协议'ViewConfigurator'   类PersonViewConfigurator:ViewConfigurator {         ^

     

MyPlayground.playground:4:20:注意:无法为协议“ ViewConfigurator”推断关联的类型“ View”       关联类型视图:UIView                      ^

     

MyPlayground.playground:27:14:注意:候选人无法推断'View'='PersonView',因为'PersonView'不是类类型,因此不能从'UIView'继承       必需的init(view:PersonView){

(我认为)哪个是怪异的,因为PersonView是UIView吗?

1 个答案:

答案 0 :(得分:0)

我认为,如果您想要通用视图,可以执行以下操作:

protocol PersonView: UIView {
    static var nameLabel: UILabel {get}
}

class BigPersonView: UIView, PersonView {
    static var nameLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
}

class SmallPersonView: UIView, PersonView {
    static var nameLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
}

class PersonViewConfigurator<T: PersonView> {
    public let testView: UILabel!
    init() {
        testView = T.nameLabel
    }

    public func configure() {
        testView.text = "swift"
    }
}

func test() {
    let person = PersonViewConfigurator<BigPersonView>()
    person.configure()
    print(person.testView.text)
}

test()

此外,协议遵循严格的规则,不能与继承的类型一起使用。这意味着如果您要一个UIView,则必须为其提供一个UIView,如果您要一个PersonView,则必须为其提供一个PersonView。

这让我想知道为什么还有关联的类型?

这是我描述的代码:

protocol ViewConfigurator {
    init(view: PersonView)

    func configure()
}

protocol PersonView: UIView {
    var nameLabel: UILabel { get }
}

class BigPersonView: UIView, PersonView {
    var nameLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
}

class SmallPersonView: UIView, PersonView {
    var nameLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
}


class PersonViewConfigurator: ViewConfigurator {

    required init(view: PersonView) {
        self.view = view
    }

    func configure() {
        view.nameLabel.text = "swift"
    }

    private let view: PersonView
}