异步json请求目标C.

时间:2015-04-02 21:07:27

标签: objective-c json xcode asynchronous

我正在开发我的第一个iPhone应用程序,我正在调用一个API来返回一些JSON,它填充了我的UI的不同元素。目前我已在helper类中实现了一个同步方法,我在viewDidLoad方法中调用它。

-(NSDictionary*) dataRequest: (NSString*)url withMethod:(NSString*)method
{

NSError *e;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:method];
NSURLResponse *requestResponse;
NSData *requestHandler = [NSURLConnection sendSynchronousRequest:request returningResponse:&requestResponse error:nil];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData: requestHandler options: NSJSONReadingMutableContainers error: &e];
return json;

}

这里的问题是我锁定了我的UI,我尝试异步实现它,但是在代码尝试填充UI元素之后很久就返回了数据,这是实现异步调用和填充UI元素的最佳和最正确的方法有正确的数据吗?

2 个答案:

答案 0 :(得分:4)

预计在发出请求后很长时间内会返回数据(相对于发送请求后下一行代码的近乎即时执行)。诀窍是推迟UI的更新,直到请求完成。

// optionally update the UI to say 'busy', e.g. placeholders or activity
// indicators in parts that are incomplete until the response arrives
[NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
    // optionally update the UI to say 'done'
    if (!error) {
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData: requestHandler options: NSJSONReadingMutableContainers error: &e];
        // update the UI here (and only here to the extent it depends on the json)
    } else {
        // update the UI to indicate error
    }
}];

更抽象地 - 更准确地说 - 考虑所提取的数据可能是应用程序模型的一部分。从服务器获取只是模型更改的一个原因。当模型因任何原因(通过用户操作或此获取或其他事件)而更改时,视图控制器的工作就是观察它已更改,并告知视图更新。

答案 1 :(得分:0)

在某些情况下,使同步请求有意义,但在同步请求完成时视图控制器正在等待(阻塞主线程)。我发了一篇博文来帮助深入回答这个问题:http://jasoncross-ios-development.blogspot.com/2015/04/asynchronous-json-requests-in-objective.html。该文章还讨论了围绕从iOS服务器的Web服务器使用JSON的其他问题:在不同情况下要考虑的设计模式。

iOS开发中最常见的模式之一是显示源自Web服务并通过JSON传输的数据。本文讨论了数据的同步和异步提取,以及其他相关的设计模式。

同步和异步http请求之间有什么区别?在同步http请求中,当前正在执行的代码"阻止" (停止并等待)直到请求完成。如果此代码位于主线程上,则在进行网络调用时,应用程序将显示为冻结和损坏。这是一个坏主意,反对最佳实践,应该始终避免。

相反,异步http请求允许当前执行的代码在请求启动时和请求运行时继续。请求完成后,代码"报告"听众在NSURLConnection sendAsynchronousRequest:queue:completionHandler:的情况下,侦听器是方法的调用者,该方法作为方法参数传入块。在从主线程发出网络请求的情况下,用户界面不会锁定,应用程序继续响应用户手势,并且是公认的最佳实践。

简而言之,您需要知道的全部内容:使用异步方法。但这引出了一个问题:为什么同步方法即使永远不会被使用呢?答案是,在使同步请求有意义的情况下有很多场景。详细介绍其中一些场景包括博客文章的其余部分。

考虑使用"服务层"提出请求,如下:

模型类。这些通常镜像JSON对象 服务层。这些类了解API并进行网络调用以获取JSON。当网络调用完成时,JSON将转换为本机模型类(Objective-C对象)。 查看控制器。这些类处理用户交互并根据需要从服务层请求数据。

如果您的iOS应用程序只需要获取一次数据并且不关心更新,则服务层可以执行异步请求,并在请求完成时使用块更新调用者。呼叫者可以向服务层询问以下数据:

[serviceLayer fetchDataFromAPIWithResponseBlock:^(NSArray * arrayOfObjects, NSError *error) {

if (nil != error) {
    // deal with error appropriately
}
else if (nil != arrayOfObjects) {
    // update the user interface
}

}]; 

但是,如果您的应用程序涉及在服务器或客户端上发生更改的数据,那么您将需要一种方法来协调模型更改以及用户界面的更新。在这种情况下,您应该考虑使用委托设计模式或观察者设计模式。如果使用委托模式,则View Controller将成为服务层的委托。当模型数据发生变化时,服务层会通知代理人。在这种情况下,服务层可以使用同步请求,因为视图控制器在等待从服务层收听时未阻塞。实现委托模式的另一种方法是使用NSNotificationCenter在模型数据更改时通知View Controller。使用委托模式和通知之间最大的决定因素是当模型数据发生变化时需要通知多少个视图控制器。如果只有一个视图控制器,则可以将其设为委托。如果有多个视图控制器,则可以通过通知全部通知它们。

如果正在更改模型对象的各个属性(可能来自iOS应用程序中的其他位置),那么您应该考虑使用键值观察(KVO)在模型更改时更新视图。

更深入的讨论可以在上面提到的博客文章中找到。