UIView子类的Swift数组符合协议

时间:2016-11-19 00:32:45

标签: ios swift generics swift3 protocols

镜像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]?

}

1 个答案:

答案 0 :(得分:0)

Nate Cook建议

  

一种简单易行的方法是从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") } } 类型。我认为你会失去一点类型的安全/表达,但会获得拥有非均匀阵列的能力

因此该方法的最终版本最终成为:

$scope.$watch('data.sliderDelegate', function(newVal, oldVal) {
  if (newVal != null) {
    $scope.data.sliderDelegate.on('slideChangeEnd', function() {
      $scope.data.currentPage = $scope.data.sliderDelegate.activeIndex;
      if($scope.data.currentPage == $scope.data.lastSlide){
        $scope.data.sliderDelegate.lockSwipeToNext();
      }
      else{
        $scope.data.sliderDelegate.unlockSwipeToNext();
      }
      $scope.$apply();
    });
  }
});

或者,如果您的模型协议足够通用,Soroush建议

  

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

     

然后你只需要一个将枚举变成表单元素的大开关

     

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