Класс, соответствующий протоколу как параметр функции в Swift
в Objective-C в качестве параметра метода можно указать класс, соответствующий протоколу. Например, у меня может быть метод, который позволяет только UIViewController
, что соответствует UITableViewDataSource
:
- (void)foo:(UIViewController<UITableViewDataSource> *)vc;
Я не могу найти способ сделать это в Swift (возможно, это не возможно, пока). Вы можете указать несколько протоколов с помощью func foo(obj: protocol<P1, P2>)
, но как вы требуете, чтобы объект также принадлежал к определенному классу?
6 ответов:
вы можете определить
foo
как универсальная функция и использовать ограничения типа, чтобы требовать как класс, так и протокол.Swift 4
func foo<T: UIViewController & UITableViewDataSource>(vc: T) { ..... }
Swift 3 (работает также для Swift 4)
func foo<T: UIViewController>(vc:T) where T:UITableViewDataSource { .... }
Swift 2
func foo<T: UIViewController where T: UITableViewDataSource>(vc: T) { // access UIViewController property let view = vc.view // call UITableViewDataSource method let sections = vc.numberOfSectionsInTableView?(tableView) }
в документации Swift book предлагается использовать ограничения типа с предложением where:
func someFunction<C1: SomeClass where C1:SomeProtocol>(inParam: C1) {}
это гарантирует, что" inParam "имеет тип" SomeClass "с условием, что он также придерживается"SomeProtocol". У вас даже есть возможность указать несколько предложений where, разделенных запятой:
func itemsMatch<C1: SomeProtocol, C2: SomeProtocol where C1.ItemType == C2.ItemType, C1.ItemType: SomeOtherProtocol>(foo: C1, bar: C2) -> Bool { return true }
в Swift 4 Вы можете достичь этого с помощью нового знака&:
let vc: UIViewController & UITableViewDataSource
С Swift 3, Вы можете сделать следующее:
func foo(_ dataSource: UITableViewDataSource) { self.tableView.dataSource = dataSource } func foo(_ delegateAndDataSource: UITableViewDelegate & UITableViewDataSource) { //Whatever }
Примечание в сентябре 2015 года: это было наблюдение в первые дни Свифт.
Это, кажется, невозможно. Apple также имеет это раздражение в некоторых своих API. Вот один пример из недавно введенного класса в iOS 8 (начиная с бета-версии 5):
UIInputViewController
' stextDocumentProxy
свойства:определены в Objective-C следующим образом:
@property(nonatomic, readonly) NSObject<UITextDocumentProxy> *textDocumentProxy;
и в Swift:
var textDocumentProxy: NSObject! { get }
ссылка на Apple' документация: https://developer.apple.com/library/prerelease/iOS/documentation/UIKit/Reference/UIInputViewController_Class/index.html#//apple_ref/occ/instp/UIInputViewController/textDocumentProxy
Как насчет этого пути?:
protocol MyProtocol { func getTableViewDataSource() -> UITableViewDataSource func getViewController() -> UIViewController } class MyVC : UIViewController, UITableViewDataSource, MyProtocol { // ... func getTableViewDataSource() -> UITableViewDataSource { return self } func getViewController() -> UIViewController { return self } } func foo(_ vc:MyProtocol) { vc.getTableViewDataSource() // working with UITableViewDataSource stuff vc.getViewController() // working with UIViewController stuff }