导航

Iphone dev -json-1- Transfer json data by Http

Posted on 2010-12-08 15:42  山姆蜀黍  阅读(1303)  评论(1编辑  收藏  举报

本教程创建了一个简单示例“幸运数字”,它有一个标签,其内容是通过建立于HTTP web service之上的JSON更新的。

源代码/Github

本教程的 源代码 存储于GitHub上。请运行下列命令获取代码:

  1. 打开终端程序,改变目录到你希望存储源代码的目录下
  2. 输入 git clone git://github.com/dcgrigsby/luckynumbers.git 获取源代码


iPhone JSON 库



本教程使用了Stig Brautasetd的JSON library (version 2.2),它提供了解析和生成JSON的功能。在本教程中没有使用生成JSON的功能。


此JSON库提供两种方法解析JSON:(1) 通过category对NSString进行扩展以实现JSON解析 (2) 较为底层一点的基于目标的解析器。本教程从简单方案开始,即方案(1);在本教程介绍时将介绍方案(2)。

  1. 下载 磁盘映像



在稍后的步骤中我们将介绍磁盘映像的使用。

创建项目



启动Xcode 并创建一个新的 View-Based iPhone 程序,命名为 LuckyNumbers:

  1. 在Xcode菜单中使用 File > New Project… 创建一个新项目
  2. 在 iPhone OS > Application 中点取View-Based Application,按下Choose…
  3. 将此项目命名为 LuckyNumbers 并按下 Save


为此项目增添JSON支持



要使用JSON功能,我们需要将JSON库加入到项目中:

  1. 在项目的 Groups & Files 面板上展开 LuckyNumbers 项目。
  2. 使用Finder,找到你先前下载的 JSON_2.2.dmg 文件,双击加载磁盘映像。带有此DMG内容的另一个新的Finder窗口将打开
  3. 将此DMG内容中的 JSON 目录拖入到Xcode Groups & Files 面板中LuckyNumbers 项目图标下的Classes 文件夹中



为测试JSON库是否正确设置,我们将解析一个JSON字典字符串,并在console中输出其结果NSDictionary。此功能是在viewDidLoad中完成。


在 LuckyNumbersViewController.m 中加入如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import "LuckyNumbersViewController.h"
#import "JSON/JSON.h"

@implementation LuckyNumbersViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *jsonString = [NSString stringWithString:@"{\"foo\": \"bar\"}"];
    NSDictionary *dictionary = [jsonString JSONValue];
    NSLog(@"Dictionary value for \"foo\" is \"%@\"", [dictionary objectForKey:@"foo"]);
}

- (void)dealloc {
    [super dealloc];
}

@end



运行项目。如果 JSON SDK 设置正确的话,你应该将在console中见到如下信息:“ Dictionary value for “foo” is “bar” ”.

简单UI设置



我们最终成品是使用 UILabel 来显示通过HTTP 和 JSON 获取的幸运数字。


在 LuckyNumbersViewController.h 使用如下代码:

1
2
3
4
5
6
7
#import <UIKit/UIKit.h>

@interface LuckyNumbersViewController : UIViewController {
    IBOutlet UILabel *label;
}

@end



IBOutlet 是一个宏,它通知编译器将变量与通过Interface Builder 的WYSIWYG添加的UILabel元件联系起来。下一步我们将添加元件并将这两部分连接起来。


在Interface Builder中编辑 LuckyNumbersViewController.xib 文件:

  1. Groups & Files中展开LuckyNumbers下的 Resources 文件夹。
  2. 双击 LuckyNumbersViewController.xib 文件。



确保 Library, Inspector 和 View 窗口都打开/可见。如果没有的话:

  1. 在菜单中使用 Tools > Library 显示 Library 窗口
  2. 在菜单中使用 Tools > Inspector 显示 Inspector 窗口
  3. 在 LuckyNumbersViewController.xib 窗口中点击 View 图标



添加一个label:

  1. Library 窗口中找到 Label 元件并拖入view
  2. 在 View 窗口中将 label 放大到整个view的一半
  3. 在 Inspector 窗口中的 View Attributes下 , 将 label 的行数设为0。



将 label 行数设为0表示lable的尺寸在其指定的边界内动态可变。


连接 Interface Builder 中的 label 到代码 label。 仍然在 Interface Builder 中:

  1. Control + 点击LuckyNumbersViewController.xib 窗口中的 File’s Owner 图标
  2. 在弹出菜单中,点击并按住Outlets 部分 lable 行右方的圆圈
  3. 拖动鼠标到View中的 Label 上。 将出现一条蓝线连接这两个部分。



这两个部分连接后,弹出菜单将如图所示。





如果一切正常的话,保存并关闭Interface Builder。

通过HTTP获取 JSON 数据



我们将使用 Cocoa 中的 NSURLConnection 来发送一个 HTTP 请求从而获取 JSON 数据。


Cocoa 在进行HTTP请求时有两种选项:同步和异步。同步请求中程序的主runloop中运行,使得在请求的过程中,程序停止运行。而异步请求使用回调来避免程序锁住而且简单易用。因此我们使用异步请求。


首先我们需要修改视图控制器接口,创建一个NSMutableData变量来保存响应数据。我们在接口(.h)中而不是在方法中定义此变量是因为响应数据是逐步的而不是一次性返回的,我们需要将所有数据组合在一起。


修改 LuckNumbersViewController.h。改变如下黑体所示:

#import <UIKit/UIKit.h>
@interface LuckyNumbersViewController : UIViewController {
IBOutlet UILabel *label;
NSMutableData *responseData;
}



简单起见,我们在 viewDidLoad中进行HTTP请求。


修改 LuckyNumbersViewController.m :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#import "LuckyNumbersViewController.h"
#import "JSON/JSON.h"

@implementation LuckyNumbersViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    responseData = [[NSMutableData data] retain];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.unpossible.com/misc/lucky_numbers.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中进行HTTP连接;  didReceiveData用来收集返回的数据; 空白的 connectionDidFinishLoading 表示数据响应结束。

使用 JSON 数据



下面我们将展示怎样在 connectionDidFinishLoading 中对获取的 JSON 数据的进行处理。


修改LuckyNumbersViewController.m中的 connectionDidFinishLoading 方法。使用下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (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 &lt; [luckyNumbers count]; i++)
        [text appendFormat:@"%@\n", [luckyNumbers objectAtIndex:i]];

    label.text =  text;
}



本文最开始的示例代码中使用了 NSDictionary。而现在我们使用 NSArray。 解析器非常灵活,其返回对象 – 包括嵌套对象 – 将 JSON数据类型与Objective-C的数据类型很好地匹配起来。

更好的错误处理



至此我们使用了NSString扩展的方法对JSON数据进行了解析。这样做是非常简单的。


但不幸的是,使用此方法是错误处理变得很困难。如果JSON解析器因为某种原因失败的话,它仅仅返回一个nil值。但是如果错误发生时你观察console,你就会发现一些信息描述了引擎解析器失败的原因。


如果我们能将详细错误信息传递给用户,那将更加用户友好。要达到这个目的,我们将切换到JSON SDK支持的第二种面向对象的方法。


修改LuckyNumbersViewController.m中connectionDidFinishLoading 方法。使用下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (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", [luckyNumbers objectAtIndex:i]];

        label.text =  text;
    }
}



使用此方法可以帮助我们在JSON解析器发生错误时指出错误所在以便进行更好的错误处理。

结论

JSON SDK 和 Cocoa 固有的 HTTP功能使得在iPhone应用程序中运用JSON web service变得非常容易。