В Objective-C можно указать класс, соответствующий протоколу, в качестве параметра метода. Например, у меня мог бы быть метод, который позволяет только a, UIViewController
который соответствует UITableViewDataSource
:
- (void)foo:(UIViewController<UITableViewDataSource> *)vc;
Я не могу найти способ сделать это в Swift (возможно, пока это невозможно). Вы можете указать несколько протоколов func foo(obj: protocol<P1, P2>)
, но как вы требуете, чтобы объект также принадлежал к определенному классу?
Ответы:
Вы можете определить
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) }
источник
protocol<>
предоставляет (ноprotocol<>
не может содержать типы, не относящиеся к протоколу).numberOfSectionsInTableView
потому что это обязательная функцияUITableViewDataSource
?numberOfSectionsInTableView:
необязательно - возможно, вы думаетеtableView:numberOfRowsInSection:
.func foo<T: UIViewController>(vc:T) where T:UITableViewDataSource { ... }
В Swift 4 этого можно добиться с помощью нового знака &:
let vc: UIViewController & UITableViewDataSource
источник
Документация по книге Swift предлагает вам использовать ограничения типа с предложением 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 3 вы можете делать следующее:
func foo(_ dataSource: UITableViewDataSource) { self.tableView.dataSource = dataSource } func foo(_ delegateAndDataSource: UITableViewDelegate & UITableViewDataSource) { //Whatever }
источник
Swift 5:
func foo(vc: UIViewController & UITableViewDataSource) { ... }
Таким образом , по существу , Jeroen ответ «S выше.
источник
А как насчет этого ?:
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 }
источник
Примечание от сентября 2015 года : это было наблюдение в первые дни Swift.
Это кажется невозможным. У 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
источник
var textDocumentProxy: UITextDocumentProxy! { get }
@protocol MyAwesomeCallbacks <NSObject>