9

私はShareKitでこのコードに出くわしましselfたが、クラスメソッドで使用して、ライターが何を考えていたのかわかりません。警告があります: 'Class' を parameter type に送信する互換性のないポインター型id<FBSessionDelegate>これらの警告をクリーンアップして、後で問題になる可能性のある警告を確認したいと考えています。これを壊さないために何ができる/すべきですか?

これはSHKFacebook.mというファイルで、クラス名はSHKFacebookです。

+ (void)logout
{
    FBSession *fbSession; 

    if(!SHKFacebookUseSessionProxy){
        fbSession = [FBSession sessionForApplication:SHKFacebookKey
                                                 secret:SHKFacebookSecret
                                               delegate:self];

    }else {
        fbSession = [FBSession sessionForApplication:SHKFacebookKey
                                        getSessionProxy:SHKFacebookSessionProxyURL
                                               delegate:self];
    }

    [fbSession logout];
}
4

1 に答える 1

14

selfポリモーフィック クラス インスタンスとしてクラス メソッドで使用できます。

したがって、クラス メソッドは次のnewように実装できます。

+ (id)new
{
  return [[self alloc] init];
}

メッセージが送信された Class インスタンスの正しい型を返します。

例:

NSArray * a = [NSArray new]; // << a is an NSArray

例 b:

NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray

以下の注を参照してください。

したがって、実際に直面しているのは、プロトコルにインスタンス メソッドのみが存在すること、および (クラス) 自己のメソッドがプロトコルのインスタンス メソッドを採用するようにマップすることです。

設計に関しては... まあ、私はこのように書かなかったとだけ言っておきましょう. シングルトンの方がより明確で正確だったでしょうが、私はシングルトンが好きではないので、そのルートをたどりませんでした。

Classインスタンス (渡されるもの) がパラメーターで@protocol指定されたを採用するため、警告が生成されdelegateます。Classインスタンスはクラスのインスタンスではありません。プロトコル宣言は、クラスのインスタンスに実際に適用されます。たとえば、 を採用NSLockingした場合、コンパイラは、プロトコルで宣言されたすべてのインスタンス メソッドに対してクラス メソッドも実装することを期待しますか? 答え: ありません。あなたが扱っている実装は、言語の誤用であるIMOの1つですが、たまたま機能します。

用語を明確にするには:

Classインスタンス」はselfクラスメソッドにあります:

+ (void)foo { self; }

「クラスのインスタンス」はselfインスタンス メソッドにあります。

- (void)foo { self; }

実際に-[NSObject conformsToProtocol:]は is+[NSObject conformsToProtocol:]+[NSObject class]just が返さselfれるため、実行時にエラーは発生しません。

コードがあなたが説明した基準を満たしている場合、なぜ警告が表示されるのかはまだわかりません。

私が説明した基準は実行に適用されますが、言語のセマンティクスから逸脱しています。したがって、コンパイラはこれについて完全に正しいです。

問題の解決策:採用宣言はclass のインスタンスに適用されるため、コンパイラに「My Class instance conforms to protocol 」と伝える方法はありません。

主なオプションは 2 つあります。

  1. クリーンで正しいアプローチ: クラスのインスタンスを使用し、プロトコルを定義どおりに実装します。

  2. または、クラス インスタンスをプロトコルに型キャストします。

    id デリゲート = (id)self; fbSession = [FBSession sessionForApplication:SHKFacebookKey getSessionProxy:SHKFacebookSessionProxyURL delegate:delegate];

#2 を選択した場合は、次のように、クラス メソッドを使用するようにプロトコルのインスタンス メソッドを定義すると役立つ場合があります。

+ (void)protocolMethod { /* do stuff */ }
- (void)protocolMethod { [self.class protocolMethod]; }

これは、インスタンスがまったく必要ないことも意味します。プロトコルが変更された場合に警告が追加されるため、役立ちます。規則に従うと、これらの警告がクラス メソッドにバブルアップします。

ノイズを減らすために、型キャストを 1 つの場所に減らすメソッドを作成することも検討してください。

+ (id<SomeProtocol>)sharedSomeProtocolDelegate
{
  return (id<SomeProtocol>)self;
}

- (id<SomeProtocol>)sharedSomeProtocolDelegate
{
  return [[self class] sharedSomeProtocolDelegate];
}

次に、次のように書くことができます。

fbSession = [FBSession sessionForApplication:SHKFacebookKey
                             getSessionProxy:SHKFacebookSessionProxyURL
                                    delegate:[self sharedSomeProtocolDelegate]];

(これらの型の実装は実際にはクラス クラスターであり、デバッガーで、または出力された場合に何か異なることが表示されることに注意してください)

于 2012-01-27T03:39:19.067 に答える