2017-02-21 14 views
3

Вот мой случай:Расширение протокола соответствия для некоторых UIControls

Я хочу 2 или более UIControls, чтобы соответствовать общему протоколу: Например UISlider, UIStepper, MyCustomControl. Это то, что у них есть:

class UIStepper { 
    var value: Float 
} 

class UISlider { 
    var value: Double 
} 

class MyCustomControl { 
    var value: Int 
} 

Теперь, я хотел бы что-то похожее на протокол, как что:

protocol Valuable { 
    associatedtype T 
    var value: T 
} 

, а затем быть в состоянии использовать [Valuable]. Но я, конечно, попасть в знаменитую проблему похлопывает

протокола Ценные может быть использован только в качестве общего ограничения, поскольку он имеет Атман или связанные требования типа

Я видел методу type erasure и вещей аналогично онлайн. Но я чувствую, что это бесполезно для того, что я пытаюсь сделать. Я хочу иметь только массив элементов управления, обладающих свойством value, и это свойство может быть только примитивных типов. Конечно, я могу пойти и создать несколько массивов, например [IntValuable], [DoubleValuable], [FloatValuable], чтобы обойти его. Или, может быть, каким-то образом использовать NSNumber. или перечисление со связанными значениями. Или, может быть, есть что-то, чего я не вижу, и, следовательно, почему я размещаю здесь :) Небольшое руководство действительно оценено! Благодарю.

+0

Возможный дубликат [Как использовать общий протокол как тип переменной] (http://stackoverflow.com/questions/27725803/how-to-use-generic-protocol-as-a-variable-type) –

+0

@ MarcoSantarossa Да, я упомянул, что я читал о стирании стилей и тому подобное. Мне любопытно, есть ли другой способ справиться с этим, применительно к моим конкретным потребностям _simpler_. –

+0

Более простое решение будет зависеть от того, как вы планируете использовать свойство value для объектов в вашем [Ценное] массиве. Если он имеет тип, зависящий от класса, компилятор может не позволить вам многое сделать с помощью свойства value ваших элементов массива, если вы не выполняете много типов кастинга. Если вы в порядке с типом casting при использовании, вы можете также определить свойство value как Any. –

ответ

0

так, как я в конечном итоге делает его заключается в следующем:

protocol Valuable { 
    func set(value: NSNumber) 
} 

extension UIStepper: Valuable { 
    func set(value: NSNumber) { 
     self.value = value.doubleValue 
    } 
} 

extension UISlider: Valuable { 
    func set(value: NSNumber) { 
     self.value = value.floatValue 
    } 
} 

И тогда я могу сделать:

var valuables: [Valuable] = [UISlider(), UIStepper()] 

for valuable in valuables { 
    valuable.set(value: 5) 
} 

Таким образом, я могу легко добавьте дополнительные расширения для любых классов, даже если переменная в ней не называется value.

1

Мне непонятно, из вашего вопроса, каковы ваши потребности. Как насчет:

enum Numeric { 
    case int(Int) 
    case double(Double) 
    case float(Float) 

    init(_ int: Int) { 
     self = .int(int) 
    } 

    init(_ double: Double) { 
     self = .double(double) 
    } 

    init(_ float: Float) { 
     self = .float(float) 
    }   
} 

protocol Valuable { 
    var numericValue: Numeric { get set } 
} 

extension UISlider: Valuable { 
    var numericValue: Numeric { 
     get { return .double(value) } 
     set { value = newValue.value } 
    } 
} 

И т.д., для других элементов управления. Затем, чтобы назначить:

let slider: UISlider() 
slider.numericValue = Numeric(3.14159) 
+0

Хорошее предложение. Тем не менее, может потребоваться способность делать 'ценный.значение = 123', чтобы я мог изменить значение своих элементов управления, не зная, является ли это' UISlider' или 'UIStepper' –

+1

. Я обновил код, чтобы добавить методы' init' для типа «NumericValue». (Хотя я не уверен, правильно ли я получил синтаксис, потому что я набираю это на своем телефоне.) –