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

您描述的设计模式称为回调。您需要被通知在未来某个时间点发生的事件。在 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 的便捷类方法 sendSynchronousRequest 来执行同步请求,而不是异步创建和管理 NSURLConnection 实例。

因此,您可以执行以下操作,而不是您的 [[NSURLConnection alloc] init...] 行:

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

之后,您可以立即从 responseData 解析 JSON,而不是在 connection:didReceiveData 委托中进行解析。

编辑:刚刚看到 user698846 建议修改您的方法签名以获取完成块。如果您可以随意更改您的方法签名(即没有人要求您的函数同步返回),这也是解决您的问题的一种很好且可能更清洁的方法。无论哪种方式,sendSynchronousRequest 都可能是最简单的出路,而且没有什么可耻的,尤其是在的应用程序和用户在等待请求完成时无能为力的情况下。

于 2013-01-07T16:10:59.073 回答
0

这是一些代码:

NSURLResponse *response = nil;

NSError *error = nil;

NSData *responseData = [NSURLConnection sendSynchronousRequest:user_fetch_details returningResponse:&response error:&error];
于 2014-04-09T10:52:54.053 回答