以下内容直接取自 Dan Grigsby 的教程 - http://mobileorchard.com/tutorial-json-over-http-on-the-iphone/ - 请注明,偷窃是恶业。
通过 HTTP 获取 JSON
我们将使用 Cocoa 的 NSURLConnection 发出 HTTP 请求并检索 JSON 数据。
Cocoa 为发出 HTTP 请求提供同步和异步选项。从应用程序的主运行循环运行的同步请求会导致应用程序在等待响应时停止。异步请求使用回调来避免阻塞并且易于使用。我们将使用异步请求。
我们需要做的第一件事是更新视图控制器的接口,以包含一个 NSMutableData 来保存响应数据。我们在接口中声明这一点(而不是在方法中),因为响应是以我们拼接在一起的片段连续返回的,而不是一个完整的单元。
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController {
IBOutlet UILabel *label;
NSMutableData *responseData;
}
为简单起见,我们将从 viewDidLoad 启动 HTTP 请求。
替换以下内容:
#import "JSON/JSON.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
responseData = [[NSMutableData data] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"XYZ.json"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
label.text = [NSString stringWithFormat:@"Connection failed: %@", [error description]];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
}
- (void)dealloc {
[super dealloc];
}
@end
这主要是样板代码初始化 responseData 变量以准备好保存数据并在 viewDidload 中启动连接;当它们进入 didReceiveData 时,它会收集碎片;并且空的 connectionDidFinishLoading 准备好对结果做一些事情。
使用 JSON 数据
接下来,我们将充实 connectionDidFinishLoading 方法,以利用在上一步中检索到的 JSON 数据。
更新connectionDidFinishLoading方法:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSArray *luckyNumbers = [responseString JSONValue];
NSMutableString *text = [NSMutableString stringWithString:@"Lucky numbers:\n"];
for (int i = 0; i < [luckyNumbers count]; i++)
[text appendFormat:@"%@\n", [luckyNumbers objectAtIndex:i]];
label.text = text;
}
它创建一个 NSArray。解析器非常灵活并返回对象——包括嵌套对象——将 JSON 数据类型与 Objective-C 数据类型适当匹配。
更好的错误处理
到目前为止,我们一直在使用方便的高级扩展 NSString 方法来解析 JSON。我们这样做是有充分理由的:将 JSONValue 消息简单地发送到字符串以访问解析的 JSON 值是很方便的。
不幸的是,使用这种方法会使有用的错误处理变得困难。如果 JSON 解析器由于任何原因失败,它只会返回一个 nil 值。但是,如果您在发生这种情况时查看控制台日志,您会看到准确描述导致解析器失败的原因的消息。
如果能够将这些错误详细信息传递给用户,那就太好了。为此,我们将切换到 JSON SDK 支持的第二种面向对象的方法。
更新connectionDidFinishLoading方法:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
NSArray *luckyNumbers = [json objectWithString:responseString error:&error];
[responseString release];
if (luckyNumbers == nil)
label.text = [NSString stringWithFormat:@"JSON parsing failed: %@", [error localizedDescription]];
else {
NSMutableString *text = [NSMutableString stringWithString:@"Lucky numbers:\n"];
for (int i = 0; i < [luckyNumbers count]; i++)
[text appendFormat:@"%@\n", [viewcontroller objectAtIndex:i]];
label.text = text;
}
}
使用此方法为我们提供了一个指向底层 JSON 解析器的错误对象的指针,我们可以将其用于更有用的错误处理。
结论:
JSON SDK 和 Cocoa 对 HTTP 的内置支持使得将 JSON Web 服务添加到 iPhone 应用程序变得简单。