Intereting Posts
didReceiveApplicationContext не вызывается Изменение UITableViewCell, где разместить этот код? Смутно о шаблонах проектирования не разрешать жестов нажатия на UIImageView, когда другой палец уже находится на другом UIImageView Строка состояния ios 7 не наследует цветной строки Как реализовать механизм состояния, основанный на событиях, где события генерируются самостоятельно? Обновить заголовокLabel UIButton новостное приложение iphone, которое читает из онлайн-базы данных Случаи Мне не нужно разворачивать Swift по желанию? Когда вызываются методы UITableViewDataSource? iOS: изображение запуска становится морщинистым в центре во время сеанса вызова / записи / горячей точки Изменить цвет UINavigationbar для вкладки «Дополнительно»? доступ к объектам UIView в массиве Можно ли отключить сглаживание в SceneKit, чтобы сделать пиксельные изображения искусства острыми? Установить язык доступности по умолчанию на iOS на испанский Как я могу отобразить UIDatePicker с HH: MM: SS

Использование общей функции в базовом классе

То, что я пытаюсь сделать …

В моем приложении у меня есть много полей форм, которые похожи друг на друга с кучей пользовательских функций (изменение цвета на ect).

Я хочу создать класс классов-оболочек, который будет абстрагировать весь этот код, а затем наследовать от него для реализации моих разных типов ввода, таких как ввод данных и ввод текста.

Унаследованным классам просто нужно будет настроить правильное управление ввода для своего типа.

Что я пробовал

Это больше похоже на псевдокод. Я пытался часами, но я просто не понимаю, как добиться того, что мне нужно

Я думаю, что я начинаю с базового класса, для этого нужно определить ссылку на элемент управления ввода и несколько методов, которые каждый из них переопределит, например, возможность установить или получить текущее значение

class BaseInput<T>: UIView { let label = UILabel() let control: T ... A bunch of methods for layout and stuff ... func setControlValue(_ value: U) { print("I'm not a real input yet, so i can't do that") } } 

Затем я создаю унаследованный класс для ввода даты. Это использует базовую метку для элемента управления и внутренне использует UIDatePicker для установки значения

 class DateInput: BaseInput<UILabel> { override init() { self.control = UILabel() } override func setControlValue(_ value: Date) { MyGlobalDateFormatter.string(format:value) } } 

и другой для поля ввода текста

 class TextInput: BaseInput<UITextField> { override init() { self.control = UITextField() } override func setControlValue(_ value: String) { control.textLabel!.text = value } } 

То, что я в конечном счете ищу, это возможность инициализировать входной компонент, а для свойства MyInput.control – правильный класс для этого конкретного ввода, а метод setControlValue – принимать правильный тип данных (т. setControlValue , Int или Date в зависимости от типа управления)

Я считаю, что это можно решить с помощью generic, но я действительно пытаюсь понять, как это сделать. Если кто-то может указать мне в правильном направлении, это было бы здорово.

Примечание. Я не ожидаю и не хочу, чтобы кто-либо написал весь код для меня. Псевдокода было бы достаточно, чтобы позволить мне полностью разобраться.

Попытка 1:

 protocol CustomControl { associatedtype Control associatedtype Value var control : Control { get } var label : UILabel { get } func setControlValue(_ value: Value) } class AbstractInputField: UIView { // This class contains all the setup // for the label and wrapping UI View } class TextInputField: AbstractInputField, CustomControl { typealias Control = UITextField typealias Value = String let control = UITextField() func setControlValue(_ value: String) { control.text = value } } class DateInputField: AbstractInputField, CustomControl { typealias Control = UILabel typealias Value = String let control = UILabel() private let picker = UIDatePicker() func setControlValue(_ value: Date) { control.text = GlobalDateFormatter.string(from: value) } .. Also in this class it's a bunch of date picker methods .. } 

В другом месте, если я это сделаю:

 override func viewDidLoad() { let firstInput = makeControl("text") firstInput.label.text = "First name" firstInput.setControlValue(myUser.first_name) let dobInput = makeControl("date") dobInput.label.text = "Date of birth" dobInput.setControlValue(myUser.dob) } func makeControl(controlType: String) -> CustomControl { // Im using strings just for testing, i'd probably make this an enum or something if controlType == "text" { return TextInputField() } else { return DateInputField() } } 

Я получаю сообщение об ошибке: «Протокол« CustomControl »может использоваться только в качестве общего ограничения, поскольку он имеет собственные или связанные требования типа

То, что я в конечном счете пытаюсь достичь, – это очень простой API для моих входов, где я могу установить текст ярлыка и установить входное значение. Остальное приложение не волнует, есть ли текстовое поле, текстовое представление или полный пользовательский тип ввода. Мое приложение хочет работать с протоколом (или базовым классом), который говорит, что у него есть эти методы и свойства.

Может быть, я глуп.

Я бы предложил использовать протоколы.

 protocol CustomControl { associatedtype Control associatedtype Value var control: Control { get } func setControlValue(_ value: Value) } 

а затем создать пользовательские классы, соответствующие этому protcol

 class CustomTextField: CustomControl { typealias Control = UITextField typealias Value = String let control: UITextField init() { self.control = UITextField() } func setControlValue(_ value: String) { control.text = value } } 

Отредактировано:

 class CustomLabel: CustomControl { typealias Control = UILabel typealias Value = String let control: UILabel init() { self.control = UILabel() } func setControlValue(_ value: String) { control.text = value } } 

Редактировать 2: Альтернативный подход

 protocol HasSettableValue: class { associatedtype Value var customValue: Value { get set } } protocol IsInitializable { init() } extension UITextField: IsInitializable {} extension UITextField: HasSettableValue { typealias Value = String? var customValue: String? { get { return text } set { text = newValue } } } class BaseClass<T> where T: HasSettableValue, T: IsInitializable { let control: T init() { self.control = T() } func setControlValue(_ value: T.Value) { control.customValue = value } } class CustomTextField: BaseClass<UITextField> { } let customTextField = CustomTextField() customTextField.setControlValue("foo") print(customTextField.control) // prints <UITextField: 0x...; frame = (0 0; 0 0); text = 'foo'; opaque = NO; layer = <CALayer: 0x...>> 

Окончательное обновление:

Проблема с протоколами, имеющими связанные типы, вы не можете использовать их для объявления переменных. Вам всегда нужно указать конкретную реализацию.

Думаю, я нашел решение, соответствующее вашим потребностям:

 enum ControlType { case textField, datePicker } enum ControlValueType { case text(text: String) case date(date: Date) var string: String { switch self { case .text(text: let text): return text case .date(date: let date): // apply custom format return "\(date)" } } var date: Date { switch self { case .date(date: let date): return date default: preconditionFailure("`date` can be only used with `.date` value type") } } } protocol Control: class { var controlValue: ControlValueType { get set } } class TextInputField: Control { private let textField = UITextField() var controlValue: ControlValueType { get { return .text(text: textField.text ?? "") } set { textField.text = newValue.string } } } class DateInputField: Control { private let picker = UIDatePicker() var controlValue: ControlValueType { get { return .date(date: picker.date) } set { picker.date = newValue.date } } } func createControl(ofType type: ControlType) -> Control { switch type { case .textField: return TextInputField() case .datePicker: return DateInputField() } } let customDatePicker = createControl(ofType: .datePicker) customDatePicker.controlValue = .date(date: Date()) print(customDatePicker.controlValue.string) // prints 2017-09-06 10:47:22 +0000 let customTextFiled = createControl(ofType: .textField) customTextFiled.controlValue = .text(text: "Awesome text") print(customTextFiled.controlValue.string) // prints Awesome text 

Надеюсь, это поможет.

PS: То, что вы пытаетесь достичь, не очень распространено в iOS, насколько я знаю.