2016-11-19 5 views
0

Каков наилучший способ зеркального отображения объектов @property (nonatomic) NSArray <SomeProtocol>* items; Obj-C, где находятся подклассы UIView?Swift массив подклассов UIView, соответствующих протоколу

В приведенном ниже примере, я хотел бы хранить массив UIKit компонентов (например, UILabel, UIButton и т.д.), что все соответствует протоколу, однако это дает ошибку 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]? 

} 
+0

Возможно, эта статья может помочь: https://milen.me/writings/swift-generic-protocols/ – nebs

+0

Вам необходимо объявить свой протокол как ': class', чтобы указать, что он будет применяться только к классу объекты, а не структуры – Paulw11

ответ

0

Nate Кук предложил

Один простой иш способ подхода, который должен был бы удалить соответствующий тип из FormControllable и сделать его init failable. Каждому соответствующему типу в основном нужно было бы подтвердить, что он знает, что делать с указанным типом 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 предложил

Одна идеи состоит в том, чтобы сделать ваше поле представимых типа в перечисление, так как Theres заданного числа типов элементов полой формы

Тогда вам просто нужен большой переключатель, который включает перечисление в форме элемент

И вы можете принять массив случаев полевых данных и сопоставить их в массив элементов формы

Смежные вопросы