W Objective-C można określić klasę zgodną z protokołem jako parametr metody. Na przykład mógłbym mieć metodę, która zezwala tylko na to, UIViewController
co jest zgodne z UITableViewDataSource
:
- (void)foo:(UIViewController<UITableViewDataSource> *)vc;
Nie mogę znaleźć sposobu, aby to zrobić w Swift (być może nie jest to jeszcze możliwe). Możesz określić wiele protokołów przy użyciu func foo(obj: protocol<P1, P2>)
, ale jak chcesz, aby obiekt był również określonej klasy?
Odpowiedzi:
Możesz zdefiniować
foo
jako funkcję ogólną i użyć ograniczeń typu, aby wymagać zarówno klasy, jak i protokołu.Szybki 4
func foo<T: UIViewController & UITableViewDataSource>(vc: T) { ..... }
Swift 3 (działa również dla Swift 4)
func foo<T: UIViewController>(vc:T) where T:UITableViewDataSource { .... }
Szybki 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) }
źródło
protocol<>
zapewnia (aleprotocol<>
nie może zawierać typów innych niż protokoły).numberOfSectionsInTableView
ponieważ jest to wymagana funkcjaUITableViewDataSource
?numberOfSectionsInTableView:
jest opcjonalne - możesz o tym pomyślećtableView:numberOfRowsInSection:
.func foo<T: UIViewController>(vc:T) where T:UITableViewDataSource { ... }
W Swift 4 możesz to osiągnąć za pomocą nowego znaku &:
let vc: UIViewController & UITableViewDataSource
źródło
Dokumentacja książki Swift sugeruje, że używasz ograniczeń typu z klauzulą where:
func someFunction<C1: SomeClass where C1:SomeProtocol>(inParam: C1) {}
Gwarantuje to, że element „inParam” jest typu „SomeClass” z warunkiem, że jest również zgodny z „SomeProtocol”. Masz nawet możliwość określenia wielu, gdzie klauzule oddzielone przecinkami:
func itemsMatch<C1: SomeProtocol, C2: SomeProtocol where C1.ItemType == C2.ItemType, C1.ItemType: SomeOtherProtocol>(foo: C1, bar: C2) -> Bool { return true }
źródło
Dzięki Swift 3 możesz wykonać następujące czynności:
func foo(_ dataSource: UITableViewDataSource) { self.tableView.dataSource = dataSource } func foo(_ delegateAndDataSource: UITableViewDelegate & UITableViewDataSource) { //Whatever }
źródło
Swift 5:
func foo(vc: UIViewController & UITableViewDataSource) { ... }
Tak więc zasadniczo powyższa odpowiedź Jeroena .
źródło
A co w ten sposób ?:
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 }
źródło
Uwaga we wrześniu 2015 r . : To była obserwacja z wczesnych dni Swift.
Wydaje się to niemożliwe. Apple ma tę irytację również w niektórych swoich interfejsach API. Oto jeden przykład z nowo wprowadzonej klasy w iOS 8 (od wersji beta 5):
UIInputViewController
„stextDocumentProxy
nieruchomości:Zdefiniowany w celu C w następujący sposób:
@property(nonatomic, readonly) NSObject<UITextDocumentProxy> *textDocumentProxy;
iw Swift:
var textDocumentProxy: NSObject! { get }
Link do dokumentacji Apple: https://developer.apple.com/library/prerelease/iOS/documentation/UIKit/Reference/UIInputViewController_Class/index.html#//apple_ref/occ/instp/UIInputViewController/textDocumentProxy
źródło
var textDocumentProxy: UITextDocumentProxy! { get }
@protocol MyAwesomeCallbacks <NSObject>