5

私は同じを作る複数のビューを持っていますNSURLRequest/NSURLConnection request。理想的には、コードを再利用するために、(非同期の)要求/接続の作成/実行、すべてのデリゲートメソッドの設定などの基本的な作業をすべて実行するある種の「プロキシ」が必要です。 、したがってNSURLConnection、各ビューでこれらのデリゲートメソッドハンドラーをすべてコピーする必要はありません。まず第一に、この設計アプローチは合理的ですか?第二に、私はどのようにそのようなことをするのですか?

少し背景情報として、これを試して「機能」させましたが、非同期で実行されているようには見えません。NSURLConnectionさまざまなWebサービス呼び出しのインスタンスメソッドを含む(およびデリゲートメソッドも含む)Proxy.h/mファイルを作成しました。

@interface Proxy : NSObject {

    NSMutableData *responseData;
    id<WSResponseProtocol> delegate;
}

- (void)searchForSomethingAsync:(NSString *)searchString delegate:(id<WSResponseProtocol>)delegateObj;

@property (nonatomic, retain) NSMutableData *responseData;
@property (assign) id<WSResponseProtocol> delegate;

@end

WSResponseProtocolは次のように定義されています。

@protocol WSResponseProtocol <NSObject>

@optional
- (void)responseData:(NSData *)data;
- (void)didFailWithError:(NSError *)error;

@end

これを使用するには、View ControllerはWSResponseProtocol、応答をキャッチするために、プロトコルに準拠する必要があります。Webサービスの呼び出しは、次のように行われます。

Proxy *p = [[Proxy alloc] init];
[p searchForSomethingAsync:searchText delegate:self];
[p release];

より多くのコードを提供できますが、残りは想定できます。UIActivityIndicatorView電話をかける前に、スピナーを「startAnimating」します。しかし、スピナーは決して回転しません。NSURLConnectionデリゲートメソッドをViewControllerに直接配置すると、スピナーが回転します。したがって、私の実装は非同期で実行されていないと思います。ここに何か考え/アイデアはありますか?

4

2 に答える 2

22

あなたのアプローチは合理的ですが、なぜあなたがあなた自身のプロトコルを作成しているのかわかりません。これは必要ありません。これを実装するために必要なものはすべて、NSURLConnectionに関するAppleのドキュメントにあります。NSURLConnectionがインスタンス化されているページからコードを取得し、ローカル変数として作成するのではなく、接続をivarにすると、各コールバックメソッドの接続オブジェクトを比較し、それに応じて応答できます。たとえば、ドキュメントから次のコードを取得し、接続オブジェクトをivarに変更します。

// create the request
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com/"]
                        cachePolicy:NSURLRequestUseProtocolCachePolicy
                    timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
    // Create the NSMutableData that will hold
    // the received data
    // receivedData is declared as a method instance elsewhere
    receivedData=[[NSMutableData data] retain];
} else {
    // inform the user that the download could not be made
}

変数theConnectionは私たちのivarです。次に、次のように確認できます。

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    if (connection == theConnection)
    {
        // do something with the data object.
        [connectionSpecificDataObject appendData:data];
    }
}

提案どおりに独自のプロトコルを作成して実装し、プロトコルに準拠するデリゲートにコールバックすることもできますが、確認できる成功と失敗のセレクターを使用してオブジェクトをインスタンス化する方がよい場合があります。このようなもの:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    if (connection == theConnection)
    {
        if (delegate && [delegate respondsToSelector:successSelector])
            [delegate performSelector:successSelector 
                           withObject:connectionSpecificDataObject];
    }
    [connection release];
}

ここで、dataDidDownloadSelectorは、このコードがすべて含まれているダウンロードデリゲート(Proxyオブジェクト)を作成したときに設定したSELインスタンス変数です。このようなもの:

Proxy *p = [[Proxy alloc] init];
[p searchForSomethingAsync:searchText 
                  delegate:self 
           successSelector:@selector(didFinishWithData:) 
              failSelector:@selector(didFailWithError:)];

次のようにセレクターを実装します。

- (void)didFinishWithData:(NSData*)data;
{
    // Do something with data
}

- (void)didFailWithError:(NSError*)error
{
    // Do something with error
}

これは私が意図したよりも長い答えになりました。それが意味をなさない場合は私に知らせてください、そして私は明確にすることを試みることができます。

よろしくお願いします、

于 2009-12-24T18:36:20.280 に答える
1

あなたのコードはそのままでは何もしないと思います-初期化した直後にプロキシを解放するので、実行されることさえありません。

私が使用したいアプローチは、NSOperationQueueによって管理されるNSOperation内の同期NSURLConnection呼び出しです。オブジェクトをキューがシングルトンに存在するようにするので、どこからでもインスタンスにアクセスし、新しい接続を開始する必要があるときにそれを通知します。

于 2009-12-24T21:38:06.010 に答える