在 iPhone 应用程序中消费 RESTful 服务 (bit.ly)






4.50/5 (5投票s)
如何在 iPhone 应用程序中消费 RESTful 服务 (bit.ly)
引言
近来,由于 iPhone 的巨大成功,许多为 Windows/Linux 开发的程序员已经转向了 iPhone。在苹果应用商店最成功的应用中,首先是游戏。其次是像 Tweetie 这样消费 Web 服务(REST 或其他)的应用。如果你不是游戏程序员,开始开发游戏是相当困难的。然而,开发消费 Web 服务的 iPhone 应用程序则相当容易。在本文中,我将演示如何编写一个消费 Web 服务的 iPhone 应用程序。我将以 bit.ly 的 REST 服务为例,在文章末尾,我们将开发一个不错的 Objective-C 版 “bit.ly” 封装库。对于不熟悉 REST 的读者,它代表表述性状态转移(Representational State Transfer)。请前往维基百科的这个页面了解更多详情。本文分为两部分,第一部分关注 XML,第二部分关注 JSON。在第二部分末尾,你可以下载附带的源代码。
Bit.ly 文档
众所周知,Bit.ly 是一个 URL 缩短服务。当 Twitter 开始使用 bit.ly 作为其默认的 URL 缩短服务,取代 tinyurl.com 后,它突然间变得流行起来。bit.ly 的 REST 文档可以在 Google Code 的这个页面找到。
在动手写真正的代码之前的一些基础知识
认证类型
bit.ly(以及许多类似的服务)使用一种称为“基本认证”的 HTTP 认证方式。在基本认证中,客户端输入的用户名和密码会用一个 : 连接起来,然后将得到的字符串
转换为 “base64
” 编码。这个字符串
会随着 HTTP 请求头一起传递,通常在每次需要登录才能执行的 API 调用中都会发送。还有一种认证类型是 oAuth,即开放认证(Open Authentication)。目前,bit.ly 尚未使用 oAuth。解释 oAuth 本身就需要一整篇文章,超出了本文的范围。
HTTP 请求类型
当你访问一个 RESTful 服务时,你要么是请求数据,要么是提交数据。在大多数情况下,你的 HTTP 请求类型是“GET
”或“POST
”。还有两种请求类型,即“PUT
”和“DELETE
”。何时使用哪种类型取决于 RESTful 服务的设计者。作为消费者,你只需遵循文档即可。在我们的例子中,bit.ly 只会使用“GET
”方法。
真正的代码
你可能会感到惊讶,访问一个 RESTful 服务以获取数据,其实只需要 10 行代码。
NSString *longURL = @"http://mugunthkumar.com"
NSString *baseURLString =
@"http://api.bit.ly/shorten?version=2.0.1&" +
@"longUrl=%@&login=bitlyapidemo&apiKey=yourapikeyhere";
NSString *urlString = [[NSString alloc] initWithFormat:@"%@%@",
baseURLString, longURL];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSString *result = [[NSString alloc] initWithContentsOfURL:url];yourapikeyhere
查看结果
NSLog(result);
结果
[url release];
[urlString release];
[result release];
解析结果
我们用“NSLogged
”输出的结果可以是 XML 或 JSON 格式。在我们的例子中,bit.ly 默认发送的是 JSON 格式的数据,这也是目前最常用的格式。对于传输相同量的数据,JSON 比 XML 更轻量。关于哪种格式更适合数据传输,一直存在很多争论。我个人更喜欢 JSON。近来,随着 JSON 解析器的出现,JSON 正在逐渐超越 XML。Objective C 有一个非常强大的 JSON 解析器,叫做 json-framework。我们将在本文的下一部分讨论它。另一种数据格式,即 XML,只有当你在 URL 中传递
format=xml
作为附加参数时,bit.ly 才会返回。对于解析 XML,有两个解析器。一个是 NSXMLParser
,另一个是更快的 libxml2
。虽然 libxml2
更快,但只有在你需要解析超过 10 MB 的 XML 数据时,才建议在你的 iPhone 应用中使用它。当你的 XML 数据很小(就像我们的情况),NSXMLParser
和 libxml2
之间的性能差距非常微小。就 bit.ly 而言,缩短网址的 API 返回的数据小于 1 KB。大多数 RESTful 服务返回的数据量都非常小(通常在几百 KB 级别)。我更喜欢 NSXMLParser
的一个原因是,你的代码会比使用 libxml2
时更整洁。在本文中,我将带你了解这两种处理数据的方式。
解析XML
[parser initWithContentsOfURL: url];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
[parser release];
使用 NSXMLParser
解析 XML 数据再简单不过了。你只需创建一个 NSXMLParser
类型的对象(解析器),初始化它,然后调用 parse
方法。
注意事项
然而,有几点需要注意。
- 你可以用
NSURL
或NSData
来初始化解析器对象。两种方法效果一样好。 - 你必须将代理(delegate)设置为 self。否则,
NSXMLParser
无法通知你相关事件。 - 接下来的三行是可选的。如果你想收到这些事件的通知,通常将它们设置为
YES
。 - 对
[parser parse]
的调用是阻塞式的。这意味着,在整个内容解析完成之前,它不会返回。因此,你可以在下一行释放任何相关的内存。
来自 NSXMLParser 的回调
NSXMLParser
大约有 14 个回调方法。但通常你只需实现其中的三个就足够了。它们是:
parser:didStartElement:namespaceURI:qualifiedName:attributes:
parser:didEndElement:namespaceURI:qualifiedName:
parser:foundCharacters:
当 XMLParser
遇到一个 XML 开始标签时,didStartElement
方法会被调用。你通常在这个函数中初始化临时变量并读取属性(如果有的话)。在 bit.ly 的例子中,你只需要读取“shortUrl
”元素。只处理这一个元素就够了。
声明以下变量:NSStrings
类型的 currentShortURL
、actualShortURL
和 currentElement
。将以下代码写入 didStartElement
代码块中:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:
(NSString *)qName attributes:(NSDictionary *)attributeDict
{
currentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:@"shortUrl"]) {
currentShortURLString = [[NSString alloc] init];
}
现在,在 foundCharacters
代码块中,写入以下代码:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:@"shortURL"]) {
[currentShortURLString appendString:string];
}
在 didEndElement
代码块中,写入:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"shortURL"]) {
actualURLString = currentURLString;
}
现在,当解析结束时,在 [parser release]
函数之后,actualShortURLString
将包含缩短后的 URL。
到此为止。如果你没能跟上这篇博文中的代码,你随时可以下载附带的源代码(在下一部分中)。要获取有关使用 NSXMLParser
进行解析的更详细信息,请阅读这篇文章。
解析 JSON
解析 JSON 比解析 XML 简单得多。事实上,我甚至不愿称之为“解析”,因为你根本不需要编写解析器!!!通过使用适用于 iPhone 的开源 json-framework 工具包,你可以轻松地将一个 JSON 字符串
“转换”成一个 NSDictionary
。现在我们来看看代码。
JSON 解析代码
JSON 解析远比 XML 简单。实际上,下面附带的代码使用的就是 JSON。
解析 bitly 信息就像写这三行代码一样简单:
SBJSON *jsonParser = [SBJSON new];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *dict = (NSDictionary*)[jsonParser objectWithString:jsonString];
返回的字符串
是一个键值对的字典
。要读取一个值,你可以调用 NSDictionary
中的 objectForKey
函数。
在大多数情况下,包括 bit.ly,JSON 返回的字符串
总是包含嵌套在其中的其他字典。要读取一个字典
中的值,只需像这样嵌套你的调用:
NSString *shortURL = [[[dict objectForKey:@"results"]
objectForKey:f_longURL]
objectForKey:@"shortUrl"];
源代码和文档
源代码
- 在此下载源代码
文档
只需三行代码,你就可以使用这个封装库来缩短你的 URL。
用你的登录名
和 apikey
初始化这个辅助类。
bitlyHelper = [[MKBitlyHelper alloc] init]; [bitlyHelper initWithLoginName:@"yourlogin" andAPIKey:@"yourapi"];
在你的应用程序中,你可以提供特定于应用程序的 API,也可以提供用户提供的 API。登录 bit.ly API 有助于跟踪点击量和来源。这些类本身不提供登录名
或 APIKey
。
现在,缩短或展开 URL 就像调用这些函数一样简单:
NSString *shortURL = [bitlyHelper shortenURL:@"http://mugunthkumar.com"]; NSString *longURL = [bitlyHelper expandURL:shortURL];
免责声明和其他废话...
请注意,代码中可能存在错误。正如高德纳(Donald Knuth)所说:
“请当心上面代码中的 bug;我只证明了它是正确的,但没有运行过它。”
欢迎随意使用和重新分发此代码。源代码的任何衍生作品都必须保留版权声明和我的署名。
你可以在你的应用程序中选择性地署名我,尽管这不是强制性的。如果你这么做,我会很高兴。;-)