クラスのインスタンスをObjective-Cの@protocolにキャストする


102

私が定義したプロトコルに準拠する場合としない場合があるオブジェクト(UIViewController)があります。

オブジェクトがプロトコルに準拠しているかどうかを確認し、安全にメソッドを呼び出すことができることはわかっています。

if([self.myViewController conformsToProtocol:@protocol(MyProtocol)]) {
    [self.myViewController protocolMethod]; // <-- warning here
}

ただし、XCodeは警告を表示します。

warning 'UIViewController' may not respond to '-protocolMethod'

この警告を防ぐ正しい方法は何ですか?クラスself.myViewControllerとしてキャストできないようですMyProtocol

回答:


171

これを行う正しい方法は、次のことです。

if ([self.myViewController conformsToProtocol:@protocol(MyProtocol)])
{
        UIViewController <MyProtocol> *vc = (UIViewController <MyProtocol> *) self.myViewController;
        [vc protocolMethod];
}

UIViewController <MyProtocol> *タイプキャストは、に変換用い、一方、「VC MyProtocolに準拠していることのUIViewControllerオブジェクトである」id <MyProtocol>に変換する「VCはMyProtocolに準拠している未知のクラスのオブジェクトです」。

このようにして、コンパイラーは適切な型チェックを提供します。コンパイラーは、vc宣言されていないメソッドUIViewControllerまたは<MyProtocol>呼び出されたメソッドがある場合にのみ警告を表示します。idキャストされるオブジェクトのクラス/タイプがわからない場合にのみ使用してください。


2
プロトコルを使用するときは、オブジェクトタイプを気にする必要はありません。プロトコルの重要な点は、任意のオブジェクトタイプがそれを採用し、特定のオブジェクトにキャストしなくても使用できることです。したがって、上記の代わりに、プロトコルにキャストしている任意の場所で@andyによる回答を使用することをお勧めします。id<MyProtocol> p = (id<MyProtocol>)self.myViewController;この回答と@andysはどちらも正しいですが、彼の方が正しいです。
memmons 2013年

2
@Answerbotあなたのコメントは間違っており、私の回答の最後の段落で述べたポイントを逃しています。オブジェクトの種類を気にするかどうかは、状況によって異なります。何があなたがメッセージを送信する場合に宣言起こるUIViewControllervc私の答えの例では、それは次のように宣言されていますかid <MyProtocol>
Nick Forge

私のコメントに関して何が間違っているのかわかりませんか?いずれにせよ、オブジェクトがプロトコルに準拠しているかどうかを確認している場合、プロトコルに関係のない他のメソッドを呼び出すのはなぜですか。私がこれを行う必要があることや、これを私がレビューしたコードで見たことを思い出すことはできません。コードの匂いがするようです。
memmons 2013

あなたがそれを見ていない/使用していないからといって、それがコードのにおいであるという意味ではありません。次のコードスニペットidは、タイプ情報を使用して破棄
Nick Forge

60

次のようにキャストできます。

if([self.myViewController conformsToProtocol:@protocol(MyProtocol)])
{
    id<MyProtocol> p = (id<MyProtocol>)self.myViewController;
    [p protocolMethod];
}

これも私を少し驚かせました。Objective-Cでは、プロトコルはタイプ自体ではないため、必要なプロトコルとともにid(またはなどの他のタイプNSObject)を指定する必要があります。


ああ、クール、ありがとう。私はそれをチェックして、それが(id)うまくいくことを確認しました。それは悪い形ですか?
フォード

1
id <MyProtocol>としてキャストすると、そのプロトコルで定義されていないメソッドを使用するとコンパイラーから警告が出されます。
dreamlax 2009年

1
@dreamlax-これは、コンパイラがプロトコルに対して型チェックを行う方法です。詳細については、developer.apple.com / documentation / Cocoa / Conceptual / ObjectiveC /…を参照てください。
アンディ

1
@Ford-プロトコルを具体的に使用することをお勧めします。これにより、コンパイラーが何らかのタイプチェックを実行できるようになります。
アンディ

1
@ Andy、 'id'は既にポインターなので、 '*'は必要ないと思います。したがって:id <MyProtocol> p =(id <MyProtocol>)self.myViewController; [p protocolMethod]; または単に:[(id <MyProtocol>)self.myViewController protocolMethod];
フォード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.