2014-09-15 5 views
6

У меня все еще есть проблемы с пониманием некоторых тонкостей дженериков в Свифте. Я определяю следующие типы:Тип не соответствует протоколу

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

class ProtocolLabel : UILabel, SomeProtocol { 
    func setValue(value: Int) { 

    } 
} 

class ProtocolImageView : UIImageView, SomeProtocol { 
    func setValue(value: Int) { 
    } 
} 

viewForValue (2) Теперь я определил следующую функцию. Я ожидаю, что T будет UIView, который соответствует протоколу SomeProtocol.

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView { 
    var someView: T 
    if param > 0 { 
     someView = ProtocolLabel() as T 
    } else { 
     someView = ProtocolImageView() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

Однако я получаю следующую ошибку компиляции, когда я выполняю код:

viewForValue(2) // <-- Type 'UIView' does not conform to protocol 'SomeProtocol' 

Кажется, что в пункте где я не могу определить класс, который не реализует протокол , Почему это?

Заранее спасибо.

+1

Вы можете попробовать использовать это: Greg

ответ

4

viewForValue должен вернуть класс, который наследуется от UIView и реализует SomeProtocol. Вы определили 2 класса, не имеющие прямого отношения - они просто наследуют от UIView и реализуют SomeProtocol.

Когда функция должна определить тип возврата, прямой тип конкретного типа, наследуемый от обоих классов, равен UIView, так что возвращается viewForValue.

Для того, чтобы исправить эту проблему, вы должны создать прямую и конкретную связь между 2-х классов, путем создания 3-го класса, унаследованный от UIView и реализации SomeProtocol:

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

class SomeClass: UIView, SomeProtocol { 
    func setValue(value: Int) { 

    } 
} 

class SomeSubclass : SomeClass { 
} 

class SomeOtherSubclass : SomeClass { 
} 

func viewForValue<T where T: SomeProtocol, T: SomeClass>(param: Int) -> T { 
    var someView: T 
    if param > 0 { 
     someView = SomeSubclass() as T 
    } else { 
     someView = SomeOtherSubclass() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

viewForValue(2) 

Дополнение: чтение OP ниже, целью является динамическое создание существующих классов UIKit, наследующих от UIView. Поэтому предлагаемое решение не применяется.

Я думаю, что расширение UIView путем внедрения SomeProtocolдолжны работы:

protocol SomeProtocol { 
    func setValue(value: Int) 
} 

extension UIView : SomeProtocol { 
    func setValue(value: Int) { 
    } 
} 

func viewForValue<T where T: SomeProtocol, T: UIView>(param: Int) -> UIView { 
    var someView: T 
    if param > 0 { 
     someView = UILabel() as T 
    } else { 
     someView = UIImageView() as T 
    } 
    someView.setValue(2) 
    someView.frame = CGRectZero 
    return someView 
} 

, но похоже, что есть ошибка компилятора. Этот код на игровой площадке показывает сообщение о том, что:

Связь с службой на игровой площадке была неожиданно прервана. Служба игровой площадки «com.ap.dt.Xcode.Playground», возможно, создала журнал сбоев.

в то время как в прикладной компиляции IOS терпит неудачу из-за ошибки сегментации 11.

+0

Я пытался быть более общий характер с моим вопросом, но в моем случае участвующие классы представляют собой подклассы UIView': 'UILabel',' UIImageView', поэтому я не могу наследовать их из 'SomeClass'. Я буду редактировать, чтобы это отразить. – Kamchatka

+0

См. Дополнение к моему ответу - я думаю, что второе решение должно работать, но код заставляет компилятор сбой ... – Antonio

+0

Это полезно, спасибо! – Kamchatka

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