1

文字列を受け取り、それをサイトに投稿してJSON応答を受け取るクラスメソッドを呼び出そうとしています(DataClassに保存した他の変数の中でも)。応答の形式でデータを返そうとして立ち往生しており、この時点で返されたデータを NSLog することさえできません。問題は、クラス メソッドを呼び出した後、クラス メソッドが HTTP POST からの応答を待ってデータを返すにはどうすればよいかということです。JSON を返したら、辞書に展開してそこから処理できます。助けていただければ幸いです:)

クラスメソッド:

//
//  APISample.m
//
//  Created by Sam on 1/6/13.
//  Copyright (c) 2013 Sam. All rights reserved.
//
#import "APISample.h"
#import "DataClass.h"
@implementation APISample

@synthesize first_name = _first_name;
@synthesize last_name = _last_name;
@synthesize profile_pic_url = _profile_pic_url;
@synthesize responseData;
-(id)init
{
    self = [super init];
    return self;
    NSLog(@"Loaded APISample and fetching");
}
+(id)getDataAboutUser:(NSString *)user_request_id;
{  
    DataClass *userdata=[DataClass getInstance];
NSLog(@"Loaded APISample and fetching %@", user_request_id);
NSMutableURLRequest *user_fetch_details = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://10.0.23.161/users/user_fetch_details.php"]];
    [user_fetch_details setHTTPMethod:@"POST"];
    NSMutableString *postString = [NSMutableString stringWithString:@"id=123"];
    [postString appendString:@"&userrequest_id="];
    [postString appendString:[userdata.str_userid copy]];
    [postString appendString:@"&user_id="];
[postString appendString:[userdata.str_userid copy]];
    [postString appendString:@"&identifier="];
[postString appendString:[userdata.str_identifier copy]];
    [user_fetch_details setValue:[NSString stringWithFormat:@"%d", [postString length]] forHTTPHeaderField:@"Content-length"];
    [user_fetch_details setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:user_fetch_details delegate:self];
NSMutableData *responseData=[NSMutableData data];
[responseData appendData:[NSURLConnection connection:didReceiveData];


if (connection) {
    // Create the NSMutableData that will hold
    // the received data
    // receivedData is declared as a method instance elsewhere
    NSMutableData *responseData=[NSMutableData data];
} else {
    // inform the user that the download could not be made
}


NSLog(@"Received Data %@", [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding]);
return [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
NSString *receivedDataString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    if ([receivedDataString isEqualToString: @"error"]) {
        UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                 message:@"An error has occured. The application will now exit. Unexpected Response!"
                                                                delegate:nil
                                                       cancelButtonTitle:@"Close"
                                                       otherButtonTitles:nil];
        [errorAlert show]; 
        exit(0);
    }else{
        NSError* error;
        NSDictionary* json = [NSJSONSerialization
                              JSONObjectWithData:responseData
                              options:kNilOptions
                              error:&error];
        NSString *firstnameResponse = [json objectForKey:@"first_name"];
        NSString *lastnameResponse = [json objectForKey:@"last_name"];
        NSString *profile_pic_urlResponse = [json objectForKey:@"profile_pic_url"];

        NSLog(@"didReceiveData %@ analysed " , firstnameResponse);
    }
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"connectionDidFinishLoading");
    NSLog(@"Succeeded! Received %d bytes of data",[self.responseData length]);
}
@end

「受信データ」の後にログにデータを受信せず、エラー メッセージも表示されません。ありがとうございます

4

3 に答える 3

3

あなたが説明している設計パターンは CallBack と呼ばれます。将来のある時点で発生するイベントについて通知する必要があります。Objective-C には、4 つの主な形式のコールバックがあります。

ターゲット アクション ペアリング (これは、ボタンなどで使用されるものです。「このボタンが押されると、ターゲットに通知し、このアクションを実行するように伝えます」)

委任 (上記のコードでは、NSURLConnection を使用して委任の形式を使用しています。「委任」という言葉が表示されたら、「ヘルパー オブジェクト」と考えてください。「NSURLConnection さん、重要なイベントが発生したときに、これらのイベントについてこのデリゲート (ヘルパー オブジェクト)に伝える必要があります)

通知 (これらは、モデル オブジェクトの変更を処理するときによく使用されます)

そして最後に...私があなたの目的のためにお勧めするもの...

ブロック。

ブロックは非常にクールな変数です。ほとんどの変数はデータを保持します。ブロックは、将来のある時点で実行されるコードを保持する変数です。したがって、あなたの状況では、メソッド getDataAboutUser:(NSString *)user_request_id とともに完了ブロックを渡すことができます。したがって、次のようになります。

getDataAboutUser:(NSString*)string withCompletion:(void(^)(NSData *finishedData))cBlock

その cBlock を instanceVar として保存します。次に、NSURLConnection がすべてのデータのダウンロードを終了したら、cBlock を実行し、終了したデータを引数として渡します。

ブロックを使用したことがない場合、ブロックはかなり複雑なものなので、20 分かけてこれを読むことをお勧めします。

于 2013-01-07T16:01:26.747 に答える
1

メソッドが応答を待ってから戻る必要があるため、NSURLConnection インスタンスを非同期的に作成および管理する代わりに、NSURLConnection の便利なクラス メソッド sendSynchronousRequest を使用して同期要求を実行できます。

[[NSURLConnection alloc] init...] 行の代わりに、次のようにできます。

NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:user_fetch_details returningResponse:&response error:&error];

これに続いて、connection:didReceiveData デリゲートで行う代わりに、responseData から JSON をすぐに解析できます。

編集:メソッド署名を変更して完了ブロックを取るというuser698846の提案を見たところです。これは、メソッド シグネチャを自由に変更できる場合 (つまり、誰も関数が同期的に戻ることを要求していない場合)、問題に対処するための適切で、おそらくクリーンな方法でもあります。いずれにせよ、 sendSynchronousRequest はおそらく最も簡単な方法であり、リクエストが完了するのを待っている間にアプリやユーザーができることが何もない場合は特に恥ずべきことではありません。

于 2013-01-07T16:10:59.073 に答える