在Swift中符合协议的类作为函数参数
在Objective-C中,可以指定符合协议的类作为方法参数。 例如,我可以有一个只允许符合UITableViewDataSource
的UIViewController
的方法:
- (void)foo:(UIViewController<UITableViewDataSource> *)vc;
我找不到在Swift中这样做的方法(可能还不行)。 你可以使用func foo(obj: protocol<P1, P2>)
来指定多个协议,但是如何要求该对象也是一个特定的类?
您可以将foo
定义为通用函数,并使用types约束来要求类和协议。
斯威夫特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书的文档build议你用where子句使用types约束:
func someFunction<C1: SomeClass where C1:SomeProtocol>(inParam: C1) {}
这保证“inParam”的types是“SomeClass”,条件是它也遵守“SomeProtocol”。 你甚至可以指定多个由逗号分隔的子句:
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年9月注意 :这是斯威夫特早期的观察。
这似乎是不可能的。 苹果在他们的一些API中也有这个烦恼。 以下是iOS 8中新引入的类的一个示例(截至testing版5):
UIInputViewController
的textDocumentProxy
属性:
在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 }