您的位置:首页 > 理论基础 > 计算机网络

iPhone开发技巧之网络篇(1)— 解析XML

2012-01-02 00:58 381 查看
iPhone的XML库
XML解析与内存占用
libxml2vsNSXMLParser
NSXMLParser的例子
libxml2的例子
项目中添加libxml
libxml中的SAX解析器
使用DOM解析
GoogleDataAPIs
TouchXML
KissXML
iPhone开发技巧之网络篇(1)---解析XML
开发iPhone上的网络应用程序的时候时常需要解析XML文档,比如web应用中的SOAP,REST,RSS信息等都是以XML为基础的。掌握XML解析的技术是很重要的。这里我将为大家介绍一下iPhone下解析XML的几种方法,并比较其性能。
iPhone的XML库
iPhone中标准的XML解析库有两个,分贝是libxml2和NSXMLParser。
libxml2由Gnome项目开发、由于是MIT的开放协议,已经移植到许多的平台,在iPhone上也能使用。
libxml2的特点是比较快。另外作为最基本的XML解析器,提供SAX和DOM解析。并且它对应的XML标准最多,比如名称空间、XPath、XPointer、HTML、XInclude、XSLT、XMLSchema、RelaxNG等。另外它是用C语言写的,比较高速。
NSXMLParser是Cocoa中内含的XML解析器。它只提供了SAX解析的功能。因为是Cocoa的一部分、并且API是Objective-C的,所以与Mac系统兼容性强,使用也相对简单。
XML解析与内存占用
由于iPhone也是一种嵌入式设备,所以与其他的嵌入式设备一样,同样有内存,CPU等资源占用问题。所以在选择代码库的时候需要考虑性能与内存占用的问题。
一般XML的解析器有SAX解析和DOM解析两种方式、相比之下SAX比较小巧精干,耗费的内存小。这是因为其设计思想与DOM完全不一样,一边得到数据一边解析,由回调的方式通知得到的数据,没有了DOM树的概念。
现在的iPhone3G搭载的RAM是128MB(3GS是256MB)。其中有iPhoneOS本身使用的、还有根据用于使用情况不同,比如MP3,邮件,Safari等常驻程序等。基本上自己的程序可使用的内存大小是10MB左右的空间。
开发XML解析程序的时候,需要注意到XML文件一般都比较大,如果使用DOM的话,消费的内存量肯定很多。所以在iPhone中上面这两种解析器只能使用SAX的解析方式。DOM方式只能在模拟器上使用(比如NSXMLDocument类),放到实际设备上就不管用了。(不过,在下面的章节中我将介绍一种使用DOM的第三方方法,对于小的XML文档还是值得一用的。)
libxml2vsNSXMLParser
一般是使用libxml2的SAX解析器呢,还是使用NSXMLParser能,我们通过下面的SDK中附属的例子XMLPerformance来做个测试。
相同的XML文档由网络下载,然后解析,比较的结果如下:
下载用时解析用时合计
NSXMLParser1.419s5.525s7.134s
libxml22.520s2.247s2.646s
可以看到,libxml2比NSXMLParser快得多。这与它们处理的方式有些关系,NSXMLParser中调用SAXAPI的时候,参数是作为字符串传递的,需要先转换为NSString或者是NSDictionary对象,并且它不像libxml2那样是一边下载一边解析,需要整个文件下载完了才开始解析。所以说建议一般使用libxml2。
NSXMLParser的例子
解析的XML代码例子如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<users>
<username="hoge"age="20"/>
<username="fuga"age="30"/>
</users>
代码如下:
staticNSString*feedURLString=@"http://www.yifeiyang.net/test/test.xml";
-(void)parserDidStartDocument:(NSXMLParser*)parser
{
//解析开始时的处理
}
-(void)parseXMLFileAtURL:(NSURL*)URLparseError:(NSError**)error
{
NSXMLParser*parser=[[NSXMLParseralloc]initWithContentsOfURL:URL];
[parsersetDelegate:self];
[parsersetShouldProcessNamespaces:NO];
[parsersetShouldReportNamespacePrefixes:NO];
[parsersetShouldResolveExternalEntities:NO];
[parserparse];
NSError*parseError=[parserparserError];
if(parseError&&error){
*error=parseError;
}
[parserrelease];
}
-(void)parser:(NSXMLParser*)parserdidStartElement:(NSString*)elementNamenamespaceURI:(NSString*)namespaceURIqualifiedName:(NSString*)qNameattributes:(NSDictionary*)attributeDict
{
//元素开始句柄
if(qName){
elementName=qName;
}
if([elementNameisEqualToString:@"user"]){
//输出属性值
NSLog(@"Nameis%@,Ageis%@",[attributeDictobjectForKey:@"name"],[attributeDictobjectForKey:@"age"]);
}
}
-(void)parser:(NSXMLParser*)parserdidEndElement:(NSString*)elementNamenamespaceURI:(NSString*)namespaceURIqualifiedName:(NSString*)qName
{
//元素终了句柄
if(qName){
elementName=qName;
}
}
-(void)parser:(NSXMLParser*)parserfoundCharacters:(NSString*)string
{
//取得元素的text
}
NSError*parseError=nil;
[selfparseXMLFileAtURL:[NSURLURLWithString:feedURLString]parseError:&parseError];

实际使用的时候除最后两行以外,所有的当如一个类中,最后两个是启动该类的代码。
libxml2的例子
项目中添加libxml
首先需要将libxml添加到你的工程项目中。
我们知道,当向项目中添加外部库的时候,如果是程序框架的,比如UIKit.framework,Foundation.framework等放在Sysytem/Library/Frameworks目录下。SDK放在/Developer/Platforms/iPhoneOS.platform/Developer/SDKs目录下。
但是由于libxml是UNIX的库、位于SDK文件夹的usr/lib下。头文件位于usr/include下。





在libxml目录下将libxml2.2.dylib(或更高版本)添加到项目中。将头文件路径usr/include/libxml2也添加到包含路径中。
以下是libxml2.2.dylib的路径
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${VER}sdk/usr/lib/libxml2.2.dylib
以下是头文件的路径
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${VER}.sdk/usr





libxml中的SAX解析器
用过SAX解析器的朋友都知道,SAX就是事先登录一些处理函数,当XML解析到属性或要素的时候,回调登录的处理函数。
以下是一个例子,DownloadOperation实现网络文件的下载,同时交给libxml2的SAX解析器处理:

//DownloadOperation.h
#import<Foundation/Foundation.h>
#import<libxml/tree.h>
@interfaceDownloadOperation:NSOperation
{
NSURLRequest*_request;
NSURLConnection*_connection;
xmlParserCtxtPtr_parserContext;
BOOL_isExecuting,_isFinished;
BOOL_isChannel,_isItem;
NSMutableDictionary*_channel;
NSMutableDictionary*_currentItem;
NSMutableString*_currentCharacters;
}
//Property
@property(readonly)NSDictionary*channel;
//Initialize
-(id)initWithRequest:(NSURLRequest*)request;
@end
首先、#import了libxml/tree.h头文件。然后声明了一个xmlParserCtxtPtr变量作为解析器的实例。

//DownloadOperation.m

#import"DownloadOperation.h"
@interfaceDownloadOperation(private)
-(void)startElementLocalName:(constxmlChar*)localname
prefix:(constxmlChar*)prefix
URI:(constxmlChar*)URI
nb_namespaces:(int)nb_namespaces
namespaces:(constxmlChar**)namespaces
nb_attributes:(int)nb_attributes
nb_defaulted:(int)nb_defaulted
attributes:(constxmlChar**)attributes;
-(void)endElementLocalName:(constxmlChar*)localname
prefix:(constxmlChar*)prefixURI:(constxmlChar*)URI;
-(void)charactersFound:(constxmlChar*)ch
len:(int)len;
@end
staticvoidstartElementHandler(
void*ctx,
constxmlChar*localname,
constxmlChar*prefix,
constxmlChar*URI,
intnb_namespaces,
constxmlChar**namespaces,
intnb_attributes,
intnb_defaulted,
constxmlChar**attributes)
{
[(DownloadOperation*)ctx
startElementLocalName:localname
prefix:prefixURI:URI
nb_namespaces:nb_namespaces
namespaces:namespaces
nb_attributes:nb_attributes
nb_defaulted:nb_defaulted
attributes:attributes];
}
staticvoidendElementHandler(
void*ctx,
constxmlChar*localname,
constxmlChar*prefix,
constxmlChar*URI)
{
[(DownloadOperation*)ctx
endElementLocalName:localname
prefix:prefix
URI:URI];
}
staticvoidcharactersFoundHandler(
void*ctx,
constxmlChar*ch,
intlen)
{
[(DownloadOperation*)ctx
charactersFound:chlen:len];
}
staticxmlSAXHandler_saxHandlerStruct={
NULL,/*internalSubset*/
NULL,/*isStandalone*/
NULL,/*hasInternalSubset*/
NULL,/*hasExternalSubset*/
NULL,/*resolveEntity*/
NULL,/*getEntity*/
NULL,/*entityDecl*/
NULL,/*notationDecl*/
NULL,/*attributeDecl*/
NULL,/*elementDecl*/
NULL,/*unparsedEntityDecl*/
NULL,/*setDocumentLocator*/
NULL,/*startDocument*/
NULL,/*endDocument*/
NULL,/*startElement*/
NULL,/*endElement*/
NULL,/*reference*/
charactersFoundHandler,/*characters*/
NULL,/*ignorableWhitespace*/
NULL,/*processingInstruction*/
NULL,/*comment*/
NULL,/*warning*/
NULL,/*error*/
NULL,/*fatalError//:unusederror()getalltheerrors*/
NULL,/*getParameterEntity*/
NULL,/*cdataBlock*/
NULL,/*externalSubset*/
XML_SAX2_MAGIC,/*initialized*/
NULL,/*private*/
startElementHandler,/*startElementNs*/
endElementHandler,/*endElementNs*/
NULL,/*serror*/
};
@implementationDownloadOperation
//Property
@synthesizechannel=_channel;
//--------------------------------------------------------------//
#pragmamark--Initialize--
//--------------------------------------------------------------//

+(BOOL)automaticallyNotifiesObserversForKey:(NSString*)key
{
if([keyisEqualToString:@"isExecuting"]||
[keyisEqualToString:@"isFinished"])
{
returnYES;
}
return[superautomaticallyNotifiesObserversForKey:key];
}
-(id)initWithRequest:(NSURLRequest*)request
{
if(![superinit]){
returnnil;
}
//实例初始化
_request=[requestretain];
_isExecuting=NO;
_isFinished=NO;
_channel=[[NSMutableDictionarydictionary]retain];
[_channelsetObject:[NSMutableArrayarray]forKey:@"items"];
_currentItem=nil;
returnself;
}
-(void)dealloc
{
//内存释放
[_requestrelease],_request=nil;
[_connectioncancel];
[_connectionrelease],_connection=nil;
[_channelrelease],_channel=nil;
[_currentCharactersrelease],_currentCharacters=nil;
[superdealloc];
}
//--------------------------------------------------------------//
#pragmamark--Operating--
//--------------------------------------------------------------//

-(BOOL)isConcurrent
{
returnYES;
}
-(BOOL)isExecuting
{
return_isExecuting;
}
-(BOOL)isFinished
{
return_isFinished;
}
-(void)start
{
//开始下载
if(![selfisCancelled]){
//创建XML解析器
_parserContext=xmlCreatePushParserCtxt(&_saxHandlerStruct,self,NULL,0,NULL);
//设定标志
[selfsetValue:[NSNumbernumberWithBool:YES]forKey:@"isExecuting"];
_isChannel=NO;
_isItem=NO;
//创建连接
[NSURLConnectionconnectionWithRequest:_requestdelegate:self];
}
}
-(void)cancel
{
//释放XML解析器
if(_parserContext){
xmlFreeParserCtxt(_parserContext),_parserContext=NULL;
}
[_connectioncancel],_connection=nil;
[selfsetValue:[NSNumbernumberWithBool:NO]forKey:@"isExecuting"];
[selfsetValue:[NSNumbernumberWithBool:YES]forKey:@"isFinished"];
[supercancel];
}
//--------------------------------------------------------------//
#pragmamark--NSURLConnectiondelegate--
//--------------------------------------------------------------//

-(void)connection:(NSURLConnection*)connection
didReceiveData:(NSData*)data
{
//添加解析数据
xmlParseChunk(_parserContext,(constchar*)[databytes],[datalength],0);
}
-(void)connectionDidFinishLoading:(NSURLConnection*)connection
{
//添加解析数据(结束)
xmlParseChunk(_parserContext,NULL,0,1);
//释放XML解析器
if(_parserContext){
xmlFreeParserCtxt(_parserContext),_parserContext=NULL;
}
//设定标志
_connection=nil;
[selfsetValue:[NSNumbernumberWithBool:NO]forKey:@"isExecuting"];
[selfsetValue:[NSNumbernumberWithBool:YES]forKey:@"isFinished"];
}
-(void)connection:(NSURLConnection*)connection
didFailWithError:(NSError*)error
{
//释放XML解析器
if(_parserContext){
xmlFreeParserCtxt(_parserContext),_parserContext=NULL;
}
//设定标志
_connection=nil;
[selfsetValue:[NSNumbernumberWithBool:NO]forKey:@"isExecuting"];
[selfsetValue:[NSNumbernumberWithBool:YES]forKey:@"isFinished"];
}
//--------------------------------------------------------------//
#pragmamark--libxmlhandler--
//--------------------------------------------------------------//

-(void)startElementLocalName:(constxmlChar*)localname
prefix:(constxmlChar*)prefix
URI:(constxmlChar*)URI
nb_namespaces:(int)nb_namespaces
namespaces:(constxmlChar**)namespaces
nb_attributes:(int)nb_attributes
nb_defaulted:(int)nb_defaulted
attributes:(constxmlChar**)attributes
{
//channel
if(strncmp((char*)localname,"channel",sizeof("channel"))==0){
_isChannel=YES;
return;
}
//item
if(strncmp((char*)localname,"item",sizeof("item"))==0){
_isItem=YES;
_currentItem=[NSMutableDictionarydictionary];
[[_channelobjectForKey:@"items"]addObject:_currentItem];
return;
}
//title,link,description
if(strncmp((char*)localname,"title",sizeof("title"))==0||
strncmp((char*)localname,"link",sizeof("link"))==0||
strncmp((char*)localname,"description",sizeof("description"))==0)
{
//创建字符串
[_currentCharactersrelease],_currentCharacters=nil;
_currentCharacters=[[NSMutableStringstring]retain];
}
}
-(void)endElementLocalName:(constxmlChar*)localname
prefix:(constxmlChar*)prefixURI:(constxmlChar*)URI
{
//channel
if(strncmp((char*)localname,"channel",sizeof("channel"))==0){
_isChannel=NO;
return;
}
//item
if(strncmp((char*)localname,"item",sizeof("item"))==0){
_isItem=NO;
_currentItem=nil;
return;
}
//title,link,description
if(strncmp((char*)localname,"title",sizeof("title"))==0||
strncmp((char*)localname,"link",sizeof("link"))==0||
strncmp((char*)localname,"description",sizeof("description"))==0)
{
NSString*key;
key=[NSStringstringWithCString:(char*)localnameencoding:NSUTF8StringEncoding];
NSMutableDictionary*dict=nil;
if(_isItem){
dict=_currentItem;
}
elseif(_isChannel){
dict=_channel;
}
[dictsetObject:_currentCharactersforKey:key];
[_currentCharactersrelease],_currentCharacters=nil;
}
}
-(void)charactersFound:(constxmlChar*)ch
len:(int)len
{
//添加解析到的字符串
if(_currentCharacters){
NSString*string;
string=[[NSStringalloc]initWithBytes:chlength:lenencoding:NSUTF8StringEncoding];
[_currentCharactersappendString:string];
[stringrelease];
}
}
@end
连接开始的时候(start函数)使用xmlCreatePushParserCtxt创建解析器实例,这里注意第二个参数,将DownloadOperation的实例传到解析器内,这个正是回调函数中的第一个参数—作为回调函数的句柄调用类成员函数(当然,不使用实例方法,将回调函数设置成类方法也是可行的。但是当你使用到DownloadOperation中的成员等会有些不便,所以从OO的角度出发,还是传递回调函数的对象实例为佳)。
开始下载的时候,因为数据是顺序得到的,所以一边下载,一边用xmlParseChunk传递给解析器。
libxml的SAX句柄函数在xmlSAXHandler结构中定义。这个构造体内有30多个句柄定义,一般我们只需要登录其中几个就够了。比如例子中的startElementNsSAX2Func、endElementNsSAX2Func、charactersSAXFunc等,他们的定义如下:
最后,因为用SAX解析,需要知道当前解析的位置,所以标记参数需要合理的使用。

使用DOM解析

上面我们已经介绍了,iPhone中的XML解析器都是SAX的,如果仅仅对于比较小的XML文档,或者说想得到DOM树结构的XML文档来说,使用DOM解析还是有一定价值的(比如针对简单的SOAP,REST文档解析等)。

GoogleDataAPIs

这里介绍一种使用第三方类库的方法,具体见这里。其实说是第三方类库,其实还是使用了libxml2,所以前期库文件和头文件的设置与上面libxml2是一致的。并将-lxml2加到link的设置中。
使用的时候,先从这里下载并解冻GoogleDataAPIsObjective-CClientLibrary,然后将下面解开的文件拷贝到项目中去。

GDataXMLNode.h
GDataXMLNode.m
GDataDefines.h
GDataTargetNamespace.h
解析的例子如下:

<users>
<userid="0">
<name>azalea</name>
<email>azalea@azalea.net</email>
<addresscountry="Japan">Hokkaido</address>
</user>
<userid="1">
<name>Baka.K.El.Doglla</name>
<email>unknown@unknown.net</email>
<addresscountry="Doglla">Doglla</address>
</user>
</users>
下面就是使用方法了,DOM的API使用起来还是感觉便利些:

#import"GDataXMLNode.h"
-(void)applicationDidFinishLaunching:(UIApplication*)application{
//loadxmlfileastext
NSString*path=[[NSBundlemainBundle]pathForResource:@"sample"ofType:@"xml"];
NSString*fileText=[NSStringstringWithContentsOfFile:pathencoding:NSUTF8StringEncodingerror:nil];
NSLog(@"path:%d,fileText:%d",[pathretainCount],[fileTextretainCount]);
//parsetextasxml
NSError*error;
GDataXMLDocument*document=[[GDataXMLDocumentalloc]initWithXMLString:fileTextoptions:0error:&error];
GDataXMLElement*rootNode=[documentrootElement];
//getusernamesbyxpath
intcount=0;
NSArray*userList=[rootNodenodesForXPath:@"//users/user/name"error:&error];
for(GDataXMLNode*nodeinuserList){
NSLog([nodestringValue]);
}
//Configureandshowthewindow
[windowaddSubview:[navigationControllerview]];
[windowmakeKeyAndVisible];
[documentrelease];
}

TouchXML

TouchXML与上面的GoogleData的XML解析器类似,也是基于libxml2的一款第三方DOM解析器。设置是一样的。
下面开一个例子(从网上摘抄的):

#pragmamark-
#pragmamarkNewCateBooksViewController
//将xml字符串中的某些元素解析到一个数组中
+(NSMutableArray*)parseBooks:(NSString*)xmlString/*NewCateBooksViewController*/
{
if(0==[xmlStringlength])
returnnil;
NSMutableArray*items=[[[NSMutableArrayalloc]init]autorelease];
CXMLDocument*doc=[[CXMLDocumentalloc]initWithXMLString:xmlStringoptions:0error:nil];
NSArray*resultNodes=nil;
resultNodes=[docnodesForXPath:@"//booklist"error:nil];//根结点
if([resultNodescount])
{
CXMLElement*rootElement=[resultNodeslastObject];
if(rootElement)
{
NSArray*_bookElements=[rootElementelementsForName:@"book"];
for(CXMLElement*_bookElementin_bookElements)
{
RecomendBookListBean*bean=[[RecomendBookListBeanalloc]init];
//if([_cateElementscount])
//bean.b_cate_name=[[_cateElementslastObject]stringValue];
//bean.b_id=[_bookElementelementsForName:@"id"];

NSArray*idElements=[_bookElementelementsForName:@"id"];
if([idElements_count])
bean.book_id=[[idElements_lastObject]stringValue];
NSArray*nameElements=[_bookElementelementsForName:@"name"];
if([nameElementscount])
bean.book_name=[[nameElementslastObject]stringValue];
NSArray*authorElements=[_bookElementelementsForName:@"author"];
if([authorElementscount])
bean.book_author=[[authorElementslastObject]stringValue];
NSArray*urlElements=[_bookElementelementsForName:@"bookcoverurl"];
if([urlElementscount])
bean.book_pic_url=[[urlElementslastObject]stringValue];
NSArray*descripElements=[_bookElementelementsForName:@"description"];
if([descripElementscount])
bean.book_description=[[descripElementslastObject]stringValue];
NSArray*sizeElements=[_bookElementelementsForName:@"size"];
if([sizeElementscount])
bean.book_size=[[sizeElementslastObject]stringValue];
[itemsaddObject:bean];
[beanrelease];
}
}
}
[docrelease];
returnitems;
}
#pragmamark-
-(void)updateArray:(NSString*)Url
{
NSError*error;
NSURLResponse*response;
NSData*dataReply;
NSString*stringReply;
NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:[NSURLURLWithString:Url]];
[requestsetHTTPMethod:@"GET"];
dataReply=[NSURLConnectionsendSynchronousRequest:requestreturningResponse:&responseerror:&error];
if(dataReply==nil&&error!=nil)
{
return;
}
else
{
stringReply=[[NSStringalloc]initWithData:dataReplyencoding:NSUTF8StringEncoding];
[bookArrayaddObjectsFromArray:[xmlTryparseBooks:stringReply]];//调用解析函数
[stringReplyrelease];//remembertorelease

}
}

KissXML

KissXML据说速度比TouchXML快些,暂时还没有试过,用兴趣的朋友可以试试。例子如下:

DDXMLDocument*doc=[[[DDXMLDocumentalloc]initWithData:dataoptions:0error:&error]autorelease];
DDXMLElement*root=[docrootElement];
[rootaddNamespace:[DDXMLNodenamespaceWithName:@"idx"stringValue:@"urn:atom-extension:indexing"]];
[rootaddNamespace:[DDXMLNodenamespaceWithName:@"gr"stringValue:@"http://www.google.com/schemas/reader/atom/"]];
[rootaddNamespace:[DDXMLNodenamespaceWithName:@"media"stringValue:@"http://search.yahoo.com/mrss/"]];
[rootaddNamespace:[DDXMLNodenamespaceWithName:@"foo"stringValue:@"http://www.w3.org/2005/Atom"]];
NSArray*titles=[rootnodesForXPath:@"//foo:feed/foo:title"error:&error];
NSArray*feedTitles=[rootnodesForXPath:@"//foo:source/foo:title"error:&error];
NSArray*feedIds=[rootnodesForXPath:@"//foo:source/foo:id"error:&error];
NSArray*entryTitles=[rootnodesForXPath:@"//foo:entry/foo:title"error:&error];
NSArray*contents=[rootnodesForXPath:@"//foo:entry/foo:content"error:&error];
NSArray*publisheds=[rootnodesForXPath:@"//foo:entry/foo:published"error:&error];
for(NSUIntegeri=0;i<[feedTitlescount];i++){
NSMutableDictionary*result=[[[NSMutableDictionaryalloc]init]autorelease];
[resultsetObject:[[feedIdsobjectAtIndex:i]stringValue]forKey:@"feed_id"];
[resultsetObject:[[feedTitlesobjectAtIndex:i]stringValue]forKey:@"feed_title"];
[resultsetObject:[[entryTitlesobjectAtIndex:i]stringValue]forKey:@"entry_title"];
[resultsetObject:[[contentsobjectAtIndex:i]stringValue]forKey:@"content"];
[resultsetObject:[[publishedsobjectAtIndex:i]stringValue]forKey:@"published"];
[self.objectsaddObject:result];
}
说到XML不得不提WEB应用中最常见的几种通讯规范:SOAP,XML-RPC,WSDL等,他们都是基于XML协定的。在下一节中我将介绍几种处理web应用的程序库。

相关文章

iPhone开发技巧之发布篇(6)---不需Developper认证的真机调试方法-(2011-12-25)
iPhone开发技巧之环境篇(11)---让Xcode对应多个版本的iOSSDK-(2011-12-03)
iPhone开发技巧之发布篇(5)---在程序中添加广告-(2011-11-20)
iPhone开发技巧之环境篇(10)---在控制台调试iPhone应用程序-(2011-11-13)
iPhone开发技巧之调试篇(3)---程序Crash后的调试技巧-(2011-11-06)
iPhone开发技巧之环境篇(9)---Xcode中的注释-(2011-01-12)
iPhone开发技巧之数据篇(2)---iPhone程序中的加密处理-(2011-01-10)
iPhone开发技巧之发布篇(4)---使用AdHoc发布自己的应用程序-(2010-07-22)
iPhone开发技巧之发布篇(3)---你的程序被拒了吗?-(2010-07-19)
iPhone开发技巧之发布篇(2)---税务相关手续-(2010-07-16)
iPhone开发技巧之发布篇(1)---登录银行信息-(2010-07-12)
iPhone开发技巧之工具篇(4)---使用afconvert转换WAV文件-(2010-06-24)
iPhone开发技巧之私有API(8)---UIApplication-(2010-06-18)
iPhone开发技巧之私有API(7)---用UIWebView访问BASIC认证的页面-(2010-06-16)
iPhone开发技巧之私有API(6)---设置UIWebView中的User-Agent-(2010-06-14)
iPhone开发技巧之私有API(5)---UISegmentedControl-(2010-06-11)
iPhone开发技巧之私有API(4)---UIBarButtonItem-(2010-06-09)
iPhone开发技巧之私有API(3)---UIButton-(2010-06-07)
iPhone开发技巧之数据篇(1)---使用正则表达式-(2010-06-04)
iPhone开发技巧之私有API(2)---UITableView-(2010-06-01)
iPhone开发技巧之私有API(1)---设备相关信息-(2010-05-28)
iPhone开发技巧之网络篇(5)---使用libcurl连接https服务器-(2010-05-17)
iPhone开发技巧之网络篇(4)---确认网络环境3G/WIFI-(2010-05-14)
iPhone开发技巧之网络篇(3)---使用NSOperation建立多任务网络连接-(2010-05-12)
iPhone开发技巧之网络篇(2)---Web服务-(2010-04-20)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: