Класс, соответствующий протоколу как параметр функции в Swift
В Objective-C можно указать класс, соответствующий протоколу, как параметр метода. Например, у меня может быть метод, который позволяет только UIViewController
соответствовать UITableViewDataSource
:
- (void)foo:(UIViewController<UITableViewDataSource> *)vc;
Я не могу найти способ сделать это в Swift (возможно, это пока невозможно). Вы можете указать несколько протоколов с помощью func foo(obj: protocol<P1, P2>)
, но как вы требуете, чтобы объект был также и определенного класса?
Ответы
Ответ 1
Вы можете определить 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)
}
Ответ 2
Документация книги Swift предлагает использовать ограничения типа с предложением where:
func someFunction<C1: SomeClass where C1:SomeProtocol>(inParam: C1) {}
Это гарантирует, что "inParam" имеет тип "SomeClass" с условием, что он также придерживается "SomeProtocol". У вас даже есть возможность указывать несколько разделов, разделенных запятой:
func itemsMatch<C1: SomeProtocol, C2: SomeProtocol where C1.ItemType == C2.ItemType, C1.ItemType: SomeOtherProtocol>(foo: C1, bar: C2) -> Bool { return true }
Ответ 3
В Swift 4 вы можете добиться этого с помощью нового и знака:
let vc: UIViewController & UITableViewDataSource
Ответ 4
С помощью Swift 3 вы можете сделать следующее:
func foo(_ dataSource: UITableViewDataSource) {
self.tableView.dataSource = dataSource
}
func foo(_ delegateAndDataSource: UITableViewDelegate & UITableViewDataSource) {
//Whatever
}
Ответ 5
Примечание в сентябре 2015 года. Это было наблюдение в первые дни Свифта.
Это кажется невозможным. Apple также испытывает раздражение в некоторых своих API. Вот один пример из недавно введенного класса в iOS 8 (начиная с бета-версии 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
Ответ 6
Как насчет этого?:
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
}