Swiftの関数パラメーターとしてプロトコルに準拠したクラス


91

Objective-Cでは、プロトコルに準拠したクラスをメソッドのパラメーターとして指定できます。たとえば、私はにUIViewController準拠するのみを許可するメソッドを持つことができますUITableViewDataSource

- (void)foo:(UIViewController<UITableViewDataSource> *)vc;

Swiftでこれを行う方法を見つけることができません(おそらくまだ可能ではありません)。を使用して複数のプロトコルを指定できますfunc foo(obj: protocol<P1, P2>)が、オブジェクトが特定のクラスでもあることをどのように要求しますか?


MyViewControllerClassなどのカスタムクラスを作成し、そのクラスが目的のプロトコルに準拠していることを確認できます。次に、そのカスタムクラスを受け入れる引数を宣言します。私はそれがすべての状況でうまくいくとは限らないことを理解していますが、それは方法です...しかしあなたの質問に対する答えではありません。回避策の詳細。
CommaToast

回答:


132

fooジェネリック関数として定義し、型制約を使用してクラスとプロトコルの両方を要求できます。

スウィフト4

func foo<T: UIViewController & UITableViewDataSource>(vc: T) {
    .....
}

Swift 3(Swift 4でも機能)

func foo<T: UIViewController>(vc:T) where T:UITableViewDataSource { 
    ....
}

スウィフト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)
}

3
これが必要なのは少し残念です。うまくいけば、将来的には、providesのように、より簡潔な構文になるでしょうprotocol<>(ただしprotocol<>、非プロトコル型を含めることはできません)。
jtbandes 2014

これは私をすごく悲しくします。
DCMaxxx 2015年

好奇心numberOfSectionsInTableViewから、それは必須関数なので明示的にアンラップできませんUITableViewDataSourceか?
rb612 2015

numberOfSectionsInTableView:はオプションですtableView:numberOfRowsInSection:
ネイト・クック

11
スウィフト3において、これはのために有利にXcodeの8ベータ6のように廃止されるように思われる:func foo<T: UIViewController>(vc:T) where T:UITableViewDataSource { ... }
LOP_Luke


17

Swiftブックのドキュメントでは、where句で型制約を使用することを推奨しています。

func someFunction<C1: SomeClass where C1:SomeProtocol>(inParam: C1) {}

これは、「inParam」が「SomeProtocol」にも準拠する条件で「SomeClass」タイプであることを保証します。コンマで区切られた複数のwhere句を指定することもできます。

func itemsMatch<C1: SomeProtocol, C2: SomeProtocol where C1.ItemType == C2.ItemType,    C1.ItemType: SomeOtherProtocol>(foo: C1, bar: C2) -> Bool { return true }

1
ドキュメンテーションへのリンクは、見ていて良かったでしょう。
ラジ

4

Swift 3では、次のことができます。

func foo(_ dataSource: UITableViewDataSource) {
    self.tableView.dataSource = dataSource
}

func foo(_ delegateAndDataSource: UITableViewDelegate & UITableViewDataSource) { 
    //Whatever
}

1
これは、SWIFT 3のプロトコル&クラス、プロトコルに適用されない
アルテムGoryaev

2

この方法はどうですか?:

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
}

2

スウィフト5:

func foo(vc: UIViewController & UITableViewDataSource) {
    ...
}

したがって、基本的に上記のJeroenの答えです。


0

2015年9月のメモ:これはSwiftの初期の頃の観察です。

それは不可能のようです。Appleは一部のAPIでもこの問題を抱えています。以下は、iOS 8で新しく導入されたクラス(ベータ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


1
これは自動生成されたようです。Swiftプロトコルはオブジェクトとして渡すことができます。理論的には、タイプするだけでよいvar textDocumentProxy: UITextDocumentProxy! { get }
atlex2

@ atlex2 UITextDocumentProxyプロトコルタイプを支持して、NSObjectクラスタイプを失いました。
チタニウム

@titaniumdecoyいいえ、あなたは間違っています。:UITextDocumentProxyは、ほとんどのプロトコルのようなもので宣言されている場合、あなたはまだNSObjectのを持っていない@protocol MyAwesomeCallbacks <NSObject>
CommaToast

@CommaToast Swiftにはありません。この質問についてです。
チタニウム

@titaniumdecoyええ、あなたはもともと正しかったです。私は混乱していた!あなたが間違っていたと言ってすみません。良い面は、この場合もNSObjectProtocolがあることですが、同じではないことがわかります。
CommaToast
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.