在Swift中符合协议的类作为函数参数

在Objective-C中,可以指定符合协议的类作为方法参数。 例如,我可以有一个只允许符合UITableViewDataSourceUIViewController的方法:

 - (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):

UIInputViewControllertextDocumentProxy属性:

在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 }