4

メイン UI スレッドでの問題を回避するために、非同期で HTTP ポスト リクエストを行う次のクラスがあります。

@implementation DataFeeder

-(void) doLookup:(NSString *)inputValue
{
    NSString *myRequestString = [NSString stringWithFormat:@"val=%@", inputValue];
    NSMutableData *myRequestData = [ NSMutableData dataWithBytes: [ myRequestString UTF8String ] length: [ myRequestString length ] ];

    NSURL * myUrl = [NSURL URLWithString: @"http://mywebsite/results.php"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myUrl]; 
    [request setHTTPMethod: @"POST"];
    [request setHTTPBody: myRequestData];
    [request setTimeoutInterval:10.0];

    [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    responseData = [[NSMutableData alloc] init];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [responseData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    // Show error message
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // Use responseData
    // Got all my response data here, so build up an object ready to send back
}

@end

ViewController次のコード行を使用して、上記を呼び出しています。

MyObject * myObj = [feeder doLookup:@"SomeStaticStringForNow"];

だから、これは私がそれを理解する方法です:

  1. doLookup、非同期接続で要求を実行します。
  2. データが完全にロードされると、呼び出されますconnectionDidFinishLoading
  3. データの読み込みが完了したら、応答データからオブジェクトを構築し、呼び出し元のコントローラーに送り返します。

呼び出し元のコントローラーにこれをリッスンさせるにはどうすればよいですか? 呼び出しをリッスンし、スピナーを停止して、の内容に基づいて UI を更新する独自のコールバック メソッドを ViewController に実装する必要がありmyObjますか?

私が見落としていた本当に簡単な方法があることを願っています...

ありがとう

4

3 に答える 3

6

デリゲート パターンを使用してコールバックを実装する必要があります。私の意見では、これが最も簡単で標準的な方法です。他の回答でわかるように、他の方法もあります。

あなたのDataFeeder.hファイルで:

@protocol DataFeederDelegate
 - (void)dataReady:(NSData*)data;
@end

@interface DataFeeder : NSObject {
 id delegate_;
}
- (id)initWithDelegate:(id<DataFeederDelegate>)delegate;
@end

あなたのDataFeeder.m

@implementation DataFeeder
- (id)initWithDelegate:(id<DataFeederDelegate>)delegate {
  self = [super init];
  if(self) {
    delegate_ = delegate;
  }
  return self;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
 [delegate_ dataReady:responseData];
}
@end

次のように DataFeeder オブジェクトをインスタンス化します。

DataFeeder *dataFeeder = [[DataFeeder alloc] initWithDelegate:self];

もちろん、呼び出し元のビュー コントローラーは DataFeederDelegate メソッドを実装する必要があります。

于 2012-05-31T15:00:33.793 に答える
4

ViewControllerデータが存在するときに通知を受け取るには、いくつかの方法があります。

  1. ViewControllerとの間でデリゲートプロトコルを定義DataFeederし、後者が前者にメッセージを送信するようにしconnectionDidFinishLoading:ます。

  2. soを使用NSNotificationCenterして分離DataFeederし、ViewControllerViewControllerデフォルトの通知センターにオブザーバーとして自分自身を追加します。

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataIsThere:) name:kMyNetworkNotificationDataIsThere object:nil];
    

DataFeeder適切なタイミングで通知を送信している間:

     [[NSNotificationCenter defaultCenter] postNotificationName:kMyNetworkNotificationDataIsThere object:self];
  1. ViewController応答自体のデリゲートメソッドを実装して処理します(これには、コンストラクターNSURLConnectionにパラメーターとして渡す必要があります)。DataFeeder
于 2012-05-31T15:04:02.397 に答える
2

これを行う良い方法は、ブロックを使用することです。メソッドdoLookup:はブロック オブジェクトを受け入れることができ、接続が終了したときにそれを呼び出すことができます。

おそらく異なる完了ブロックで複数のルックアップを実行できるようにしたいので、渡されたブロックを適切な NSURLConnection に関連付ける必要があります。

これを行うには、プロパティNSURLConnectionを持つサブクラスを使用するか、Objective-C に関連付けられたオブジェクトを (および関数を使用して) 使用して、ブロックを接続オブジェクトにアタッチします。completionBlockobjc_setAssociatedObjectobjc_getAssociatedObject

メソッドですべての準備が整いconnectionDidFinishLoading:、最終的な応答オブジェクトを準備したら、NSURLConnectionオブジェクトからブロックを取得して呼び出し、最終的なデータを渡します。

したがって、クライアント コードは最終的に次のようになります。

[feeder doLookup:@"Something" completionBlock:(FetchedData *data, NSError *error) {
    if (error) {
        // ...
        return;
    }

    // access the returned data
}];

これがあなたにとって十分な詳細であったことを願っています。

于 2012-05-31T15:07:00.633 に答える