Я пытаюсь понять, как определить функцию, которая принимает следующие два параметра:
- Протокол.
- Экземпляр класса (ссылочный тип), соответствующий этому протоколу.
Например, учитывая
protocol P { }
class C : P { } // Class, conforming to P
class D { } // Class, not conforming to P
struct E: P { } // Struct, conforming to P
это должно скомпилироваться:
register(proto: P.self, obj: C()) // (1)
но они не должны компилироваться:
register(proto: P.self, obj: D()) // (2) D does not conform to P
register(proto: P.self, obj: E()) // (3) E is not a class
Это легко, если мы отбросим условие, что второй параметр является экземпляром класса:
func register<T>(proto: T.Type, obj: T) {
// ...
}
но это также примет структуру (тип значения) в (3)
. Это выглядело многообещающим и компилируется
func register<T: AnyObject>(proto: T.Type, obj: T) {
// ...
}
но тогда ни один из (1)
, (2)
, (3)
больше не компилируется, например
register(proto: P.self, obj: C()) // (1)
// error: cannot invoke 'register' with an argument list of type '(P.Protocol, obj: C)'
Я предполагаю, что причина ошибки компилятора та же, что и в протоколе не соответствует себе?.
Еще одна неудачная попытка
func register<T>(proto: T.Type, obj: protocol<T, AnyObject>) { }
// error: non-protocol type 'T' cannot be used within 'protocol<...>'
Жизнеспособной альтернативой была бы функция, которая принимает в качестве параметров
- Протокол класса.
- Экземпляр типа, соответствующего этому протоколу.
Здесь проблема в том, как ограничить первый параметр так, чтобы принимались только протоколы классов.
История вопроса. Недавно я наткнулся на проект SwiftNotificationCenter, который реализует ориентированный на протокол , введите безопасный механизм уведомления. У него есть метод register
, который выглядит следующим образом:
public class NotificationCenter {
public static func register<T>(protocolType: T.Type, observer: T) {
guard let object = observer as? AnyObject else {
fatalError("expecting reference type but found value type: \(observer)")
}
// ...
}
// ...
}
Затем наблюдатели сохраняются как слабые ссылки, и поэтому они должны быть ссылочными типами, то есть экземплярами класса. Однако это проверяется только во время выполнения, и мне интересно, как сделать это проверкой во время компиляции.
Я упустил что-то простое / очевидное?
protocol X: class {}
более безопасным? - person sschale   schedule 08.06.2016T
будетP
, что не является конкретным типом. Я также заметил подобное поведение с типами, связанными с протоколом (как только вы ограничите их, они могут принимать только конкретные типы) - на самом деле существует сообщить об этом. - person Hamish   schedule 08.06.2016