Di Objective-C, dimungkinkan untuk menentukan kelas yang sesuai dengan protokol sebagai parameter metode. Misalnya, saya dapat memiliki metode yang hanya mengizinkan a UIViewController
yang sesuai dengan UITableViewDataSource
:
- (void)foo:(UIViewController<UITableViewDataSource> *)vc;
Saya tidak dapat menemukan cara untuk melakukan ini di Swift (mungkin belum memungkinkan). Anda dapat menentukan beberapa protokol menggunakan func foo(obj: protocol<P1, P2>)
, tetapi bagaimana Anda meminta objek dari kelas tertentu juga?
Jawaban:
Anda dapat mendefinisikan
foo
sebagai fungsi generik dan menggunakan batasan tipe untuk membutuhkan kelas dan protokol.Cepat 4
func foo<T: UIViewController & UITableViewDataSource>(vc: T) { ..... }
Swift 3 (juga berfungsi untuk Swift 4)
func foo<T: UIViewController>(vc:T) where T:UITableViewDataSource { .... }
Cepat 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) }
sumber
protocol<>
sediakan (tapiprotocol<>
tidak bisa berisi tipe non-protokol).numberOfSectionsInTableView
karena ini adalah fungsi yang diwajibkanUITableViewDataSource
?numberOfSectionsInTableView:
adalah opsional — Anda mungkin memikirkantableView:numberOfRowsInSection:
.func foo<T: UIViewController>(vc:T) where T:UITableViewDataSource { ... }
Di Swift 4 Anda dapat mencapai ini dengan & tanda baru:
let vc: UIViewController & UITableViewDataSource
sumber
Dokumentasi buku Swift menyarankan agar Anda menggunakan batasan tipe dengan klausa where:
func someFunction<C1: SomeClass where C1:SomeProtocol>(inParam: C1) {}
Ini menjamin bahwa "inParam" adalah jenis "SomeClass" dengan syarat bahwa ia juga mematuhi "SomeProtocol". Anda bahkan memiliki kekuatan untuk menentukan beberapa klausa yang dipisahkan oleh koma:
func itemsMatch<C1: SomeProtocol, C2: SomeProtocol where C1.ItemType == C2.ItemType, C1.ItemType: SomeOtherProtocol>(foo: C1, bar: C2) -> Bool { return true }
sumber
Dengan Swift 3, Anda dapat melakukan hal berikut:
func foo(_ dataSource: UITableViewDataSource) { self.tableView.dataSource = dataSource } func foo(_ delegateAndDataSource: UITableViewDelegate & UITableViewDataSource) { //Whatever }
sumber
Cepat 5:
func foo(vc: UIViewController & UITableViewDataSource) { ... }
Jadi intinya jawaban Jeroen di atas.
sumber
Bagaimana dengan cara ini ?:
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 }
sumber
Catatan pada September 2015 : Ini adalah pengamatan di hari-hari awal Swift.
Sepertinya tidak mungkin. Apple juga mengalami gangguan ini di beberapa API mereka. Berikut adalah salah satu contoh dari kelas yang baru diperkenalkan di iOS 8 (mulai beta 5):
UIInputViewController
'stextDocumentProxy
properti:Didefinisikan dalam Objective-C sebagai berikut:
@property(nonatomic, readonly) NSObject<UITextDocumentProxy> *textDocumentProxy;
dan di Swift:
var textDocumentProxy: NSObject! { get }
Tautan ke dokumentasi Apple: https://developer.apple.com/library/prerelease/iOS/documentation/UIKit/Reference/UIInputViewController_Class/index.html#//apple_ref/occ/instp/UIInputViewController/textDocumentProxy
sumber
var textDocumentProxy: UITextDocumentProxy! { get }
@protocol MyAwesomeCallbacks <NSObject>