1

背景:BackendClientサーバーとの接続を表す オブジェクト (と呼びましょう) があります。そのメソッドは単一に生成され@protocol、それらはすべて同期的であるため、バックグラウンドでそれらを呼び出すプロキシ オブジェクトを作成したいと考えています。主な問題は戻り値です。これは明らかに非同期メソッドから返すことができないため、コールバックを渡す必要があります。「簡単な」方法は、すべてBackendClientのメソッドをコピーし、コールバック引数を追加することです。しかし、ObjectiveC の性質は動的ですが、それはその問題を解決するための非常に動的な方法ではありません。そこでperformSelector:登場です。問題は完全に解決されますが、プロキシ オブジェクトの透過性はほとんど失われます。

問題:NSProxy宣言されていないセレクターを、既に宣言されているかのようにプロキシ (のサブクラス) オブジェクト に送信できるようにしたいと考えています。たとえば、次の方法があります。

-(AuthResponse)authByRequest:(AuthRequest*)request

BackendClientプロトコルで。そして、プロキシ呼び出しは次のようになります。

[proxyClient authByRequest:myRequest withCallback:myCallback];

しかし、これはコンパイルされません。

「BackendClientProxy」の目に見える @interface がセレクター「authByRequest:withCallBack:」を宣言していません

わかった。コンパイラを少し落ち着かせましょう:

[(id)proxyClient authByRequest:myRequest withCallback:myCallback];

ああ。別のエラー:

セレクター 'authByRequest:withCallBack:' の既知のインスタンス メソッドはありません

私の頭に浮かぶ唯一のことは@protocol、実行時に必要なメソッドを使用して何らかの形で新しいものを構築することですが、その方法がわかりません。

結論:このコンパイル エラーを抑制する必要があります。それを行う方法はありますか?

4

2 に答える 2

1

私がそれを理解していれば、たとえばメインイベントループなどをブロックしないために非同期にしたい同期、非スレッド化APIがあります...

BackgroundClient にシリアル キューを追加します。

@property(strong) dispatch_queue_t serialQueue;

 ... somewhere in your -init ...
 _serialQueue = dispatch_queue_create(..., serial constant);

それで:

 - (void)dispatchOperation:(dispatch_block_t)anOperation
 {
      dispatch_async(_serialQueue, anOperation);
 }

次のように使用できます。

 [myClient dispatchOperation:^{
       [myClient doSynchronousA];
       id result = [myClient doSynchronousB];
       dispatch_async(dispatch_get_main_queue(), ^{
            [someone updateUIWithResult:result];
       }
 }];

これは、BackgroundClient を書き直したり大幅にリファクタリングしたりせずに非同期モデルに移行する最も簡単な方法です。

API を強化する場合は、クライアントのインスタンスとシリアル キューを保持する BackendClient のクラス ラッパーを作成します。上記のクラスがクライアントをインスタンス化し、コードの残りの部分がそのラッパーからインスタンスのみを取得するようにします。これにより、同じモデルを引き続き使用できますが、dispatchOperation:すべてのメソッドをミラーリングする必要はありません。


typedef void(^ AsyncBackendBlock(BackendClient* bc); @interface AsyncBackend +(instancetype)asyncBackendWithBackend:(BackendClient*)bc;

 @property .... serialQueue;

 - (void) dispatchAsync:(AsyncBackendBlock) backBlock;
 @end

.m:

 @interface AsyncBackend()
 @property... BackendClient *client;
 @end

 @implementation AsyncBackend

 - (void) dispatchAsync:(AsyncBackendBlock) backBlock
 {
     dispatch_async(_serialQueue, ^{
         backBlock(_client);
     });
 }
 @end

発信者:

 AsyncBackend *b = [AsyncBackend asyncBackendWithBackend:[BackendClient new]];
 [b dispatchAsync:^(BackendClient *bc) {
    [bc doSomething];
    id result = [bc retrieveSomething];
    dispatch_async(dispatch_get_main_queue(), ^{
         [uiThingy updateWithResult:result];
    }
 }];
 ....
于 2013-09-01T16:32:17.597 に答える
0

実行時にセレクターを検索するには、 を使用できますNSSelectorFromString()が、この場合は、宣言を取得するために必要なヘッダーをインポートするだけです。-authByRequest:

于 2013-08-31T23:56:15.990 に答える