Класс, соответствующий протоколу как параметр функции в 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
}