- 浏览: 659583 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
lizaochengwen:
网络请求碰到的中文乱码使用encodeURL吧- (NSStr ...
iPhone开发/iPad开发 中文乱码问题 -
hhb19900618:
还是没弄懂怎么解决了中文乱码? 正确代码能重写贴出吗
iPhone开发/iPad开发 中文乱码问题 -
zhengjj_2009:
我的理解是讲ipa文件解压缩之后再重新打包,已经破坏了签名,所 ...
xcodebuild和xcrun实现自动打包iOS应用程序 -
zhengjj_2009:
我参考你的“ 从ipa格式的母包生成其它渠道包的shell脚本 ...
xcodebuild和xcrun实现自动打包iOS应用程序 -
同一片天空:
问题果然解决了
iOS 搭建 XMPP实现环境
项目需求
写一个iPhone应用程序,要求可以输入名字,点击按钮后,会显示一段文字向输入的名字打招呼,例如输入“宝玉”,显示“你好,宝玉!”
需求分析
这是一个很简单的应用程序,包含一个文本输入框,一个文本显示框,一个按钮。输入名字到文本输入框,再点击按钮,这时文本显示框的文字就会变成“你好,<名字>!”。但是要注意,如果用户输入为空,要有警告提示用户重新输入;如果用户输入文字太长,超过16个字符,要自动截断。
产品设计
根据项目需求,画出相应的产品原型图:
初始状态
初始时,文本输入框为空,但是显示水印,提醒用户可以输入姓名。文本显示框文字为空。
输入名字并点击按钮后
输入名字,并点击按钮后,屏幕中间显示文字:“您好,<名字>!”。
没有输入名字的警告提示
如果没有输入名字,点击按钮后弹出警告窗口,提醒用户输入名字。
系统分析
这是一个非常简单的应用程序,实现思路不不算复杂:
一个文本输入框,用来输入文字,需要限制最大字符长度为16个字符,输入框没有内容时,显示水印文字。UITextField控件正好可以满足需求。
一个文本显示框,用来显示最终生成的文字。使用UILabel控件即可满足需求。
一个按钮,点击后,获取文本输入框文字内容,生成“你好,<名字>!”文字,并显示在文本显示框中。如果点击时文本输入框文字为空,弹出警告提示框。
同时,这个应用程序在开发过程中,需要应用到iPhone开发中一些常用的设计模式:
委托(Delegate)
模型 视图 控制器(MVC)
目标 - 动作(Target-Action)
委托(Delegate)
委托模式是一个对象周期性地向被指定为其委托的另一个对象发送消息,向其请求输入或者通知某件事情正在发生。该模式可替换类继承来对可复用对象的功能进行扩展。
在本项目中,应用程序对象会向其委托发送消息,通知它主要的启动例程已经完成并且定制的配置可开始执行。为了建立并管理视图,委托会创建一个控制器实例。另外,当用户点击Return按键后,文本字段也会通知它的委托(即所创建的控制器对象)
委托方法通常会集中在一起形成一份协议。 一份协议基本上就是一个方法的列表。如果一个类遵循某个协议,则它要保证实现协议所要求的方法(有些方法可选择实现与否)。委托协议规定了一个对象可以发送给委托的所有消息。例如常见的有:UITextFieldDelegate, UIApplicationDelegate, UIScrollViewDelegate, UITableViewDelegate, UIWebViewDelegate。
模型 视图 控制器(MVC)
MVC模式将应用程序中的对象设定为三种角色:模型角色(Model)、视图角色(View)和控制器角色(Controller)。
模型对象(Model)表示数据。例如,在iPhone自带的通讯录应用中,联系人是模型对象,在一个绘画应用中,圆形、矩形是模型对象。
本项目的应用程序用到的数据非常简单——字符串,并且该字符串只有在按钮点击的方法中用到。其实换一种角度来说,字符串也是一种最简单的模型对象,在其他的应用程序中,模型对象将会更加复杂,并且模型对象在程序中无处不在,可以在多个地方进行访问。
视图对象(View)负责显示数据,比如UILabel可以显示文本、UIImageView可以显示图片,也会支持用户对数据的编辑操作,例如UITextField可以支持用户输入。
在我们接下来要创建的项目中,需要一个主视图来包含其它几个视图——首先是一个文本输入框,它用于捕获用户输入信息;然后是一个文本显示框,它用于显示文本,而文本内容则是基于用户的输入;另外还需要一个按键,让用户可以点击它,点击后通知文本字段更新。
控制器对象(Controller)介于模型和视图之间。
在我们接下来要创建的项目中,当用户点击按钮后,触发更新操作,控制器对象将会从文本输入框中获取输入的文字内容,并把文字存放在一个字符串中,然后再把文本显示框的内容更新成格式化好的内容。
结合MVC模式,对于本项目的主要流程,整个如图所示:
目标 - 动作(Target - Action)
目标-动作机制,允许一个控件对象(例如按键或滑动条) 向另外一个对象发送一条消息(即动作),以之作为对某个用户事件(例如一个点击事件)的响应。接收到消息的对象则可以对消息进行响应,并针对业务要求做出处理。
在本项目中,当点击按钮时,它会通知控制器去获取文本输入框内容,并根据输入内容更新文本显示框。
开发
创建项目
我们将开始使用Xcode来创建项目,启动Xcode(缺省情况下,Xcode位于 /Developer/Applications 里面),然后选择File > New > New Project,这样就可以创建一个新的工程。应该可以看到一个新的窗口,如下图所示:
选中 Window-Based Application 并点击 Next 按钮,输入Product Name(项目名):SayHello,在Company Identifier那,可以输入公司名唯一标识。
点击Next,选择项目存储位置,最后点击Create按钮。
完成上述步骤后,将看到如下的新项目窗口:
在进行下一步工作之前,可以先编译运行一下程序,这样就可以通过模拟器看到程序运行后的样子。在Xcode的菜单中选择 Product > Run 或者点击左上角工具栏上的 Run 按钮,iPhone模拟器应该会自动启动。当应用程序启动后,可以看到一个白色屏幕。
应用程序启动过程解析
通过Xcode的模板创建项目时,模板已经帮助设置好了应用程序基本程序环境,它会帮助创建一个应用程序对象,将应用程序和窗口连接起来,建立一个运行环境。整个启动过程从UIApplicationMain函数开始,如下图所示:
main.m文件中的main函数会调用UIApplicationMain函数:
int retVal = UIApplicationMain(argc, argv, nil, nil);
该函数将会创建一个UIApplicaion类的实例。同时它会搜索应用程序的Info.plist属性列表文件。 Info.plist文件是一部字典,它主要包含诸如应用程序名称、图标这样的信息,它也包含应用程序对象应该加载的nib 文件(虽然该文件的扩展名为“xib”,但是我们习惯称之为“nib 文件”)的名称。Nib文件主要有用户界面的信息。本项目的Info.plist文件具有下面的内容:
术语: 虽然Interface Builder文档的扩展名可能是“.xib” ,但历史上,其扩展名是“.nib”(“NextStep Interface Builder”的首字母缩写),因此人们就俗称其为“Nib文件”。
这表明应用程序启动时将会加载MainWindow nib文件。在Xcode中可以单击MainWindow.xib进行查看(注意在Xcode4中已经不需要通过Interface Builder来打开nib文件,可以直接在Xcode对nib文件进行查看和编辑):
MainWindow Nib文档包含4个对象:
File's Owner,文件拥有者代理对象,在这里MainWindow的拥有者对象时UIApplication实例
First Responder,第一响应者代理对象,在本项目中,没有使用到
Say Hello App Delegate,SayHelloAppDelegate的实例,也就是应用程序的委托
Window,一个窗口对象。它默认是白色背景,程序启动时看到的就是它
应用程序对象在完成启动后,会向委托发送applicationDidFinishLaunching:消息,通知程序已经启动成功了,这样我们可以在收到这个消息后根据需要进行一些操作。下图是一个简化的iPhone应用程序生命周期图,简要展示了发生在应用程序启动到退出的过程。
这样,我们基本了解了如何创建一个项目,以及一个应用程序的启动过程,接下来,我们需要创建一个视图控制器(UIViewController)实例,用来实现项目功能。
添加视图控制器(UIViewController)
添加视图控制器文件
在iPhone应用程序中,视图控制器(UIViewController)起着核心作用。顾名思义,视图控制器负责管理控制视图。在iPhone上,它们也帮助进行导航和内存管理。
选中Xcode项目管理器里的项目(即SayHello项目,位于Groups and Files列表的顶部)或者选中SayHello文件夹——新文件在添加时会被加入到当前选择的位置。 选中后,在Xcode菜单中选择 File > New > New File,也可以在选中的文件夹上面点右键,选择 New File。
在New File窗口中,请选择Cocoa Touch,然后选择UIViewController subclass。
点击 Next 按钮,在Options窗口,请勾选 “With XIB for user interface”复选框。选中 “With XIB for user interface”后,Xcode在创建视图控制器的同时,会为其创建一份nib文件,并将该文件添加到项目中。
点击Next按钮,在其后出现的保存文件窗口中,为文件起个名字,例如RootTimelineViewController,并选择文件存储的位置,如下所示:
点击 Save,文件会被添加到项目中。接下来,我们将创建控制器类的实例。
创建视图控制器实例
现在,我们有了视图控制器的类和nib文件,但要在应用程序代理中使用它,还必须创建类的实例,并且将实例存储在变量中,以便操作它。
在应用程序委托类的头文件(即SayHelloAppDelegate.h)中执行下述操作:
在一个类中访问另一个类,首先需要引用被访问类的头文件。所以我们先在应用程序委托头文件(SayHelloAppDelegate.h)的接口声明前面-即SayHelloAppDelegate声明前面引用视图控制器(RootViewController)的头文件:
#import "RootViewController.h"
然后在头文件大括号之间添加下面的代码,这是为了向应用程序委托添加一个实例变量:
RootViewController *viewController;
在大括号之后 @end之前添加下面的属性声明:
@property (nonatomic, retain) RootViewController *viewController;
在头文件中添加完相应变量和属性申明后,需要在对应的实现文件中,合成属性的存取方法,在dealloc方法中释放视图控制器的实例。
在应用程序委托类的实现文件(即SayHelloAppDelegate.m)中执行下述操作:
在类的 @implementation代码块中通知编译器为视图控制器合成存取方法:
@synthesize viewController;
在dealloc方法起始处释放视图控制器:
[viewController release];
我们已经把视图控制器属性添加到应用程序的委托,现在需要实际创建一个视图控制器实例,并将其设置为属性的值。
在应用程序委托类实现文件(即SayHelloWorldAppDelegate.m文件)中的applicationDidFinishLaunching: 方法开头添加如下代码,这些代码用于创建一个RootViewController实例:
RootViewController *controller = [[RootViewController alloc]initWithNibName:@"RootViewController" bundle:nil];
self.viewController = controller;
[controller release];
这段代码的作用如下:
创建RootViewController这个视图控制器的实例。使用alloc方法创建一个视图控制器,然后用initWithNibName:bundle:方法对其进行初始化。init方法先指定控制器应加载的nib文件,然后指定在哪个程序包中可找到该文件。程序包是文件系统某个位置的抽象,该位置存放了应用程序将会用到的代码和资源。
使用属性的存取方法,将创建好的视图控制器实例设置为viewController属性变量的值
根据内存管理规则释放视图控制器
视图控制器用来配置和管理在应用程序中看到的视图,每一个视图也对应有一个视图控制器来管理。窗体(window)有一个根视图控制器——这个视图控制器负责配置当窗体显示时最先显示的视图。要让你的视图控制器的内容显示在窗体中,需要去设置窗体的根视图控制器为你的视图控制器。
所以我们的项目中,在上面创建视图控制器实例代码后面再添加一行代码,来设置窗体的根视图控制器为我们新添加的视图控制器:
self.window.rootViewController = controller;
最后一行来自于Xcode提供的模板自动生成的代码:
[self.window makeKeyAndVisible];
这行代码会让包含了视图控制器视图的Window窗口显示在屏幕上。
本章完整代码,SayHelloAppDelegate.h文件:
#import <UIKit/UIKit.h>
#import "RootViewController.h"
@interface SayHelloAppDelegate : NSObject <UIApplicationDelegate> {
RootViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) RootViewController *viewController;
@end
SayHelloAppDelegate.m文件:
#import "SayHelloAppDelegate.h"
@implementation SayHelloAppDelegate
@synthesize window=_window;
@synthesize viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RootViewController *controller = [[RootViewController alloc]initWithNibName:@"RootViewController" bundle:nil];
self.viewController = controller;
[controller release];
self.window.rootViewController = controller;
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc
{
[_window release];
[viewController release];
[super dealloc];
}
@end
测试运行
在Xcode的菜单中选择 Product > Run 或者点击左上角工具栏上的 Run 按钮,iPhone模拟器应该会自动启动。当应用程序启动后,还是看到一个白色屏幕,不过第一次看到的白色屏幕,是应用程序代理中的Window,而这次看到的白色屏幕,是视图控制器RootViewController中的视图。
下一步,我们将开始对界面进行编辑。
编辑Nib文件
在iPhone开发中,一般都会用NIB文件来来负责界面显示,也就是MVC模型里面的视图对象,而NIB文件只包含用户界面元素,不包含任何源码,那么怎么让视图对象和视图控制器关联起来呢?这就需要用到两个非常重要的概念:插座变量(outlet)和文件拥有者代理对象(File's Owner)。
视图控制器的视图和Nib文件
视图控制器主要的职责就是配置和管理应用程序中所有的视图,一般来说,视图控制器的视图是放在一个Nib文件中,当然也可以不需要Nib文件,通过程序创建视图,典型的如UITableViewController这样的视图控制器,就可以不需要Nib文件。在创建视图控制器实例时,其中一个主要的构造函数 initWithNibName:bundle: 的第一个参数就是视图控制器对应的Nib文件的名字。视图控制器在其 loadView 方法中加载它的Nib文件。如果是使用 initWithNibName:bundle: 构造函数生成的实例,并且你想在视图加载完成后进行额外的设置,只要重写视图控制器的 viewDidLoad 方法就好了。
在Xcode中点击打开视图控制器的Nib文件(即RootViewController.xib文件),在Xcode中即可直接查看和编辑。文件包含三个对象,文件拥有者代理(File's Owner),第一响应者代理(First Responder)以及一个视图(View)。视图(View)是视图控制器的主视图,在主视图中还可以添加若干子视图。文件拥有者代理(File's Owner)代表Nib文件对应的视图控制器类。理解文件所有者代理的角色,以及如何建立文件所有者和Nib文件中界面元素之间的连接,是非常重要的。
小贴士: 在Xcode中编辑Nib文件时,可以通过点击右上角工具栏按钮 显示隐藏相应面板,方便对界面编辑和属性设置。
文件拥有者(File's Owner)
在一个Nib文件中,文件拥有者对象是其中最重要的对象之一,因为正是通过它,来建立起应用程序代码和Nib界面文件中对象之间的连接,具体来说,它就是对应Nib文件的视图控制器对象。以本项目为例,RootViewController.xib这个Nib文件的文件拥有者对象就是RootViewController类的实例。
一般来说,在使用模板同时创建UIViewController文件和对应的Nib文件时,它默认会设置Nib文件对应的文件拥有者为创建的UIViewController类。如果要修改或者设置Nib文件对应的文件拥有者,可以使用 Identity Inspector 面板进行设置。
如上图所示, 本项目的RootViewController.xib文件对应的文件所有者,在Identity Inspector 面板中,Custom Class部分的Class项,可以看到对应的值是RootViewController,这表示文件拥有者就是RootViewController类的实例,就可以在Xcode中访问文件拥有者类里面标志为IBOutlet的属性和IBAction的方法,和Nib文件中的界面元素建立关联。
视图插座变量
在Xcode中,使用 Inspector 面板,或者在连接面板,可以查看、创建、删除对象之间的连接。要查看视图控制器的连接,可以通过以下步骤:
在Xcode的界面中,从左侧的文件组选中要查看的视图控制器的Xib文件
在视图编辑界面,点击选中 File's Owner
在 Inspector 面板,选中 Connection inspector,这里会显示文件所有者所有的插座连接
在视图编辑界面,按住Control键点击 File's Owner 或者在 File's Owner上点击右键,弹出一个黑色半透明的面板显示文件所有者的所有连接
在上面第三步,右侧面板显示的连接面板和右键点击File's Owner弹出的半透明连接面板,显示的信息和作用都是一样的,可以根据个人习惯灵活使用。到目前为止唯一的连接是视图控制器的 view 插座变量。一个插座变量就对应视图控制器类的一个属性(有时候也可以是一个实例变量),只不过这个属性和nib文件中的某个界面元素连接在一起。此处的view的连接,表明当nib文件 RootViewController.xib 被加载,并且UIView的实例解档之后,视图控制器的view实例变量会被设置为指向nib文件中的视图。
中间测试
在项目开发中,尤其在对开发工具和语言不熟悉的时候,需要经常性的对新增的功能进行测试,以确保当前功能运行是正常的。比如我们新增了RootViewController这个自定义视图控制器,需要去测试一下它是不是已经成功添加。要测试视图控制器工作正常,简单的办法修改视图控制器的视图的背景色,例如修改为粉红色背景,然后重新运行,看看是不是界面变成了红色背景。
要设置视图控制器的视图的背景色,步骤如下:
在Xcode的界面中,从左侧的文件组选中视图控制器的Xib文件(RootViewController.xib)
在右侧的功能区域,选择属性面板(Attributes inspector)
在编辑区域,选择视图
在视图的属性面板,点击背景色(Background)对应的颜色下拉框,会弹出颜色选择面板
在颜色选择面板,选择一个合适的颜色,例如粉红色
保存nib文件
点击左上角工具栏的Run按钮,编译运行项目
正常情况下,编译应该不会出现任何错误,运行后会弹出模拟器,结果如下图所示:
确认没有问题后,再将应用的背景色还原。还原的话,将视图的背景色设置为白色就好了。
配置视图
Xcode提供了一套对象库,可以直接添加到Nib文件中。其中一部分示界面元素,例如按钮和文本输入框;其他一部分是控制器对象,例如视图控制器。我们当前项目的nib文件已经包含了视图,现在只要添加按钮和文本输入框就好了。从对象库中将用户界面元素拖动到视图中,基本步骤如下:
在Xcode的界面中,从左侧的文件组选中视图控制器的Xib文件(RootViewController.xib)
在右侧的功能区域,显示对象库(object library)
添加一个按钮(UIButton),一个文本输入框(UITextField),两个文本标签(UILabel)到视图中。可以从对象库里面拖动并将它们放到视图
参考前面的原型设计,对界面元素的尺寸和布局进行调整
将右侧功能区域切换到属性面板(Attributes inspector)
选中文本输入框(Text Field),设置Placehold属性为“请输入姓名”
选中左上侧的文本标签(UILabel),设置Text属性为“姓名”
选中下面的文本标签(UILabel),设置Text属性为空,Alignment属性设置为居中对齐
选中按钮(UIButton),设置Title属性为“招呼”
设置好的界面如下所示:
如果我们想让用户在输入时有一些更好的体验,比如用户输入英文名时,默认会首字母大写;比如键盘会显示完成(Done)按键,点击后完成输入隐藏键盘。要支持这样的输入细节,通过设置文本框属性就可以完成:
在Capitalization下拉列表,选择Words,以支持首字母大写
在Return Key下拉列表,选择Done,以支持键盘上显示完成(Done)按键
保存文件后,编译运行程序,可以看到运行的界面效果和我们在Xcode中摆放的效果是一样的。点击按钮,按钮会高亮,在文本输入框中点击,会弹出输入键盘,键盘里可以看到完成(Done)按钮。但是还不能根据输入的内容去显示文字,还不能隐藏键盘,因为目前我们还仅仅完成了视图部分的工作,还需要让视图中的对象和视图控制器的对象之间建立连接,并添加相应的逻辑,才能实现。
实现视图控制器
实现视图控制器需要完成以下几件事:
定义插座变量和动作方法,和Nib文件的视图中的界面元素进行关联
实现点击按钮后的相关逻辑——根据输入的名字显示相应的招呼语,判断输入的名字是不是为空是不是超长
用户点击键盘上的完成(Done)按键后,键盘会消失
建立连接
从业务角度来看,我们需要和界面的几个元素建立关联:
文本输入框,获取它的输入文字
文本标签,让它显示特定文字
按钮,响应它的点击事件
在Xcode4之前,Interface Builder和Xcode是分开的,一般是先在Xcode中定义好插座变量和动作方法,然后再在InterfaceBuilder中去建立界面元素和视图控制器之间的连接,到Xcode4之后,Interface Builder和Xcode已经统一合并在了一起,所以这部分也有一些变化,Xcode4让这部分工作变的更加容易一些,可以直接从视图编辑界面拖动连接到代码文件。
在我们正在开发的SayHello项目中,现在我们需要添加一个动作方法到视图控制器,当界面上的按钮被点击时,它会发送一个sayHello:消息到视图控制器,所以接下来要为按钮创建一个sayHello:动作方法:
在Xcode中,选择视图控制器对应的Nib文件(RootViewController.xib)
显示Assistant editor
让Assistant显示视图控制器的头文件(RootViewController.h)
按住Control键,从Nib文件中的按钮拖动到头文件的方法声明代码区域
在弹出的面板中,将按钮和视图控制器之间的连接设置为动作(Action)
设置 Connection 为 Action
设置 Name 为 sayHello:
设置 Type 为 id
设置 Event 为 Touch Up Inside,也就是用户在点击按钮,然后释放后触发
设置 Arguments 为 Sender
点击Connect建立连接
通过上面的为按钮添加动作的操作,完成了两件事
添加了相应的代码到视图控制器的类中
头文件中增加了如下代码:
- (IBAction)sayHello:(id)sender;
并且实现文件中增加了相应的实现方法:
- (IBAction)sayHello:(id)sender {
}
IBAction 是一个特殊的关键字,它唯一的作用是告诉Interface Builder将某个方法当成目标/动作关联中的动作。它被定义为void。
建立了按钮到视图控制器之间的连接。建立连接的意义,等同于在按钮上调用 addTarget:action:forControlEvents: ,并且 target 是文件拥有者(File's Owner)也就是视图控制器,action 是 sayHello: 方法,对应的事件是 UIControlEventTouchUpInside。
接下来要建立文本输入框和文本标签之间的连接:
在Xcode中,选择视图控制器对应的Nib文件(RootViewController.xib)
显示Assistant editor
让Assistant显示视图控制器的头文件(RootViewController.h)
按住Control键,从Nib文件中的文本输入框拖动到头文件的方法声明代码区域
在弹出的面板中,将文本输入框和视图控制器之间的连接设置为插座(Outlet)
设置 Connection 为 Outlet
设置 Name 为 nameTextField
设置 Type 为 UITextField
点击Connect建立连接
通过上面的为文本输入框添加插座变量的操作,完成了两件事
添加了相应的代码到视图控制器的类中
头文件中增加了如下代码:
@property (nonatomic, retain) IBOutlet UITextField *nameTextField;
并且实现文件中增加了相应的实现方法:
在顶部增加了:
@synthesize nameTextField;
在 dealloc 方法中添加了
[nameTextField release];
在 viewDidUnload 方法中添加了:
[self setNameTextField:nil];
IBOutlet是一个特殊的关键字,它唯一的作用是通知Interface Builder将某个实例变量或者属性当成插座变量。实际上,这个关键字被定义为空白,因此在编译的时候它没有任何作用。
建立了文本输入框到视图控制器之间的连接。建立连接的意义,等同于在视图控制器上调用 setNameTextFiled: 方法,将文本输入框作为参数传入。
按照上面创建文本输入框插座变量相同的方法,再建立用来显示问候语的文本标签的插座变量,并且将插座变量命名为 greetingLabel,类型为 UILabel。
实现逻辑代码
点击视图中的按钮,它会向视图控制器发送 sayHello: 消息,之后,视图控制器会取得文本输入框文字内容,根据内容来更新用来显示问候语的文本标签的内容。以下是RootViewController.m文件中 sayHello: 方法代码的实现:
- (IBAction)sayHello:(id)sender {
// 获取文本输入框内容,并存储到变量中
NSString *nameString = nameTextField.text;
// 检查输入的名字是否为空,如果为空,弹出提示信息
if (nameString.length == 0) {
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"名字不能为空" message:@"请输入名字后,重新点击按钮。" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alertView show];
[alertView release];
greetingLabel.text = @"";
return;
}
// 检查名字是不是超过16个字符,超过16个字符自动截断
if (nameString.length > 16) {
nameString = [nameString substringToIndex:16];
}
// 根据输入的名字,生成问候语
NSString *greeting = [NSString stringWithFormat:@"你好,%@!", nameString];
// 显示问候语
greetingLabel.text = greeting;
}
对于这个方法有几点补充说明:
UIAlertView是专门用来显示消息提示对话框
stringWithFormat:方法符串按照格式化字符串所指定的格式创建一个新字符串。%@表明此处应该使用一个字符串对象来代替。
隐藏键盘
编译并运行应用程序。在文本框中输入“Jim”,点击按键后,标签显示“你好, Jim!” 。但是选择文本字段进行输入,您会发现您没有办法表示已完成输入,也没有办法消除键盘。在iPhone应用程序中,当一个允许文本输入的元素变成第一响应者时,键盘就会自动显示出来,而当该元素不再处于第一响应者状态,键盘就会消失。我们不能直接向键盘发送消息,但是可以切换文本输入元素的第一响应者状态,利用该操作的附加效果来显示或消除键盘。在应用程序中,当用户点击文本字段时,该控件就会变成第一响应者,因此键盘就会显示出来。而当用户点击键盘中的Done按键时,希望键盘消失。
UITextFieldDelegate协议包含一个textFieldShouldReturn:方法,一旦用户点击Return按键,文本字段就会调用该方法(和按键的标题无关)。但将视图控制器设置成文本输入框(UITextField)的委托(Delegate),才可以实现该方法,在方法中向文本字段发送resignFirstResponder消息,这个消息的附加效果会让键盘消失。
通过以下步骤设置文本输入框的委托(delegate)连接:
在Xcode中,选择视图控制器对应的Nib文件(RootViewController.xib)
按住Control键,点击文本输入框
在弹出的半透明面板中,选中 delegate 后面的圆点,并拖动到 File's Owner
接下来,来实现将RootViewController作为文本输入框nameTextField的委托(delegate)
在视图控制器的头文件(RootViewController.h)中,在UIViewController后面添加<UITextFieldDelegate>:
@interface RootViewController : UIViewController<UITextFieldDelegate> {
这个申明表示视图控制器RootViewController将支持UITextFieldDelegate协议
在视图控制器的实现文件(RootViewController.m),实现 textFieldShouldReturn: 方法:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (nameTextField == textField) {
[nameTextField resignFirstResponder];
}
return YES;
}
因为这个应用程序只有一个文本输入框,所以其实不需要包含nameTextField == textField检查。不过有些时候,对象可能会被设置成多个相同类型的对象的委托,这时候就需要来区分这些对象。
至此我们已经开发完成了整个应用程序。接下来将对它进行测试。
测试
这个应用程序相对简单,我们设计几个测试场景:
输入正常的名字,例如“宝玉”,然后点击按钮,看看是不是会显示“你好,宝玉!”
不输入任何名字,点击按钮,看看是不是会有提示信息,要求输入名字。
分别输入16个、17个、20个字符的名字,看看名字是不是最多只能显示前16个字符
点击文本输入框,显示键盘,点击键盘上的Done按钮,看键盘是不是会隐藏
针对这个测试场景,逐一做一下功能的测试,看起来结果和我们预期的完全一样。
小结
通过这样一个简单的项目,了解以下知识点:
iOS开发常用的一些设计模式
iPhone程序的启动过程
视图控制器和Nib文件如何建立连接
这些知识对于iPhone开发和iOS开发来说,都是会经常用到的知识。
posted @ 2011-06-09 08:08 宝玉 阅读(7213) 评论(37) 编辑
2011年5月12日
基于Xcode4开发第一个iPhone程序:“Hello World”
项目要求
写一个iPhone程序,在屏幕正中显示文字“Hello Word”,粗体,字体大小26磅,字体颜色红色,有黑色阴影,阴影光源为左上角,偏移1像素,支持设备旋转。
需求分析
在开始之前,我们首先来分析一下项目需求,这是一个非常简单的项目,只要在屏幕上显示一段“Hello World”的文字,当然还有一些附加条件:
对字体、字体颜色、字体大小有要求,有阴影效果
要求文字显示在屏幕正中
支持设备旋转,并且无论设备如何旋转,文字都还是显示在屏幕正中
根据这些需求,我们将从简单到复杂,逐步来实现,分成2步来实现:
在屏幕上显示文字,设置字体和字体大小,让文字显示在屏幕正中心
支持设备旋转,并且保证旋转后文字还是居中状态
产品设计
iPhone4之前的屏幕是320x480,到iPhone4的时候,支持了高清屏,屏幕分辨率变成了640x960。iPhone支持四个方向的旋转的,横屏和竖屏表现略有差异,因为项目需求要求支持屏幕旋转,所以针对横屏和竖屏,界面表现有所差异,简单画一下原型设计图如下:
系统分析和设计
如果我们还没iOS下的开发经验,那么首先需要去查阅一些相关资料,让我们知道如何来开发一个iphone程序。苹果为iOS的开发者提供了一个非常详细和全面的网站:“iOS Developer Center”,网址:http://developer.apple.com/ios。在iOS Dev Center,有所有iOS SDK的类文档、入门文档、各种开发指南、示例代码库等,开发iOS平台的项目,免不了要经常上来查阅一些相关资料。不过比较遗憾的是,目前iOS Dev Center的文档和资料还是英文为主,中文资料较少,对于英文阅读不好的同学是一个考验。
现在,我们从技术角度来分析一下如何实现项目需求。同样一个项目,无疑是有很多种技术方案来实现的,所以我们有必要定一个原则,来帮助我们选择合适的方案,这个原则就是简单实用原则:“我们尽可能采用简单并且实用的技术方案,避免使用复杂的技术方案,把时间和精力浪费在一些华而不实的技巧上面”,本着这个原则,我们来开始对项目需求进行技术方案的选择:
在屏幕上显示特定字体和大小的文字
要在屏幕上显示特定字体和大小的文字,我们需要先看看iOS SDK中是否已经提供了简单实用的方式来显示文字,在iOS Dev Center中,有一篇文章“iOS Human Interface Guidelines”,专门讲解了iOS中用户界面相关的知识,从中我们可以系统的了解iOS的界面构成,各种基本界面元素,并且根据其中的说明,可以找到UILabel控件是最适合我们项目需求的控件,当然也有复杂的技术方案,就是采用在界面上自画的方式,根据简单实用原则,我们就使用UILabel这种iOS自带控件就可以了。
在开始使用UILabel之前,我们需要先来学习了解一下UILabel控件,想要了解UILabel控件的功能,在iOS Dev Center中,找到“UILabel Class Reference”,从中我们可以看到UILabel的介绍和所有属性、方法等详细的说明文档。
文档相当全面,不过对于我们来说,关键还是要去获取项目相关的资料,从文档中,我们可以逐一找到我们显示文字需要的相关属性:
text: Label显示的文字,类型为NSString类,也就是本项目需求中要显示的“Hello World”。
textAlignment: 文字在Label内的对其方式,类型为UITextAlignment枚举,在本项目需求中,要求文字在屏幕正中显示,对应的属性值为UITextAlignmentCenter。
font: 文字的字体和大小,类型为UIFont类,也就是本项目需求中要求的:“字体为粗体,字体大小26磅”,对应代码为:[UIFont boldSystemFontOfSize:26]。
textColor: 文字的颜色,类型为UIColor类,也就是本项目需求中要求的:“字体颜色红色”,对应代码为:[UIColor redColor]。
shadowColor: Label文字的阴影颜色,类型为UIColor类,也就是本项目需求中要求的:“有黑色阴影”,对应代码为:[UIColor blackColor]。
shadowOffset: Label文字阴影的偏移方向和偏移量,类型为CGSize,也就是本项目需求中要求的:“阴影光源为左上角,偏移1像素”,对应代码为:[CGSizeMake(1, 1)]。
让文字显示在屏幕正中心
要让文字显示在屏幕正中心,我们要优先考虑设置UILabel相关属性达到目的的方式,如果没有UILabel相关属性支持,那么我们就必须根据UILabel占的大小和屏幕大小来计算它应该摆放的坐标,从而实现让文字显示在屏幕正中心。在UILabel的文档中,没有发现有属性设置它的坐标,也没有设置对其的属性,这是不是代表UILabel不支持呢?不要忽略一个问题,iOS所用的编程语言是Objective-C,这个一个类似于C语言的很好的支持面向对象特性的语言,面向对象有个很重要的特性叫继承,同样对于UILabel类来说,它是有父类的,也就是UILabel父类支持的属性,UILabel都是支持的,在UILabel文档的首页,我们可以看到UILabel是从UIView继承的,所以我们可以链接到“UIView Class Reference”文档。
从文档中,我们可以找到2个重要属性,用来实现文字显示在屏幕正中:
frame: Label的位置和尺寸属性,类型为CGRect,在本项目需求中,要求显示在屏幕正中,就需要通过Label控件的frame属性的size值,结合主界面的尺寸,计算出x,y坐标值,以保证Label显示在屏幕正中。
autoresizingMask: 这个属性表示控件在其父容器尺寸发生变化时,它是怎么自动调整其尺寸或上下左右各个方向边距的。
支持屏幕旋转
iPhone程序默认不支持屏幕旋转,那么如何让界面支持旋转呢?在iOS Dev Center中,可以找到“View Controller Programming Guide for iOS”,在其中的“Custom View Controllers”一章中专门有一节“Managing a View Controller's Interface Orientation”,说明了如何让你的iOS界面支持设备旋转:
重写对应的View Controller的“shouldAutorotateToInterfaceOrientation:”方法,在方法中申明支持的方向。
配置对应的View Controller中的View的autoresizingMask属性,以适应因为界面旋转导致的布局变化。在本项目中,项目需求中要求设备在旋转也保证文字居中,利用这个属性,可以实现在界面旋转后,窗体宽度和高度发生变化时,UILabel还能继续居中。
项目开发
熟悉Xcode 4
经过前期的准备工作后,现在可以开始基于Xcode4进行实际的项目开发。对于Xcode4,在iOS Dev Center中,找到“Xcode 4 User Guide”,这是一个专门针对Xcode 4的说明和使用指南,非常详细。
在Xcode 4中,整合了原来专门用来编辑Mac或iOS项目界面的Interface Builder软件,“Xcode 4 User Guide”中专门有一章“Designing User Interfaces in Xcode”来讲述如何在Xcode 4中编辑界面。
创建新项目
启动Xcode4后,首先会有一个欢迎窗口,通过它,点击“Create a new Xcode project”,可以直接开始创建项目
当然也可以通过菜单或者快捷方式来开始创建新项目
选择新项目模板
为方便生成项目,Xcode4默认提供了几种项目模板:
Navigation-based Application: 该模板适用与需要界面导航的应用,基于该模板生成的应用程序,带一个导航,显示一个列表项
OpenGL ES Application: 该模板适用于基于OpenGL ES的应用程序,例如游戏类程序。基于该模板生成的应用程序,带一个用来输出OpenGL ES场景的视图和一个支持动画的视图
Splite View-based Application: 该模板适用于需要用到左右分栏视图的iPad程序,基于该模板生成的应用程序,提供了一个左右分栏的界面控件
Tab Bar Application: 该模板适用于适用采用标签页的应用程序,基于该模板生成的应用程序,默认带有标签页
Utility Application: 该模板适用与有一个主界面和一个信息页的应用,基于该模板生成的应用程序,主界面上有一个信息按钮,点击后,有一个翻转动画,切换到另一个信息界面
View-based Application: 该模板适用于单一界面的应用,基于该模板生成的应用程序,只有一个空白界面视图
Window-based Application: 该模板适用于空白的应用程序,基于该模板生成的应用程序,只有一个窗体,没有任何视图,需要手动添加
对于我们的Hello World项目来说,最适合的项目模板是“View-based Application”,我们只要基于它创建一个单一带有空白视图的应用,然后再将UILabel拖到上面就可以实现基本功能。
项目基本选项
点击下一步,进入“Choose options for your new project”界面,在这里,可以选择设置项目的基本选项,其中:
Product Name: 指产品名称,在这里项目中,我们直接命名为“Hello World”
Company Identifier: 公司标识符,一般命名规则为 “com.公司名”
Bundle Identifier: 指包标识符,用于唯一标识应用程序,默认会根据公司标识符和产品名来组合生成
Device Family: 指该应用支持的设备类型,共三个选项:iPhone、iPad、Universal(即iPhone、iPad通用)
Include Unite Tests: 是否包含单元测试代码模板,如果勾选,Xcode会帮助生成单元测试代码模板
选择存储路径
点击Next按钮后,进入选择文件存储路径界面,在这里,可以选择要存储项目的目录。
项目创建完成
点击“Create”按钮,项目创建完成,弹出项目窗口。
试运行项目
经过上面的步骤,我们已经基于模板创建了一个项目,在开始开发前,我们可以尝试先试运行一下项目,看看效果。点击Xcode左上角的“Run”按钮,Xcode即开始对项目进行编译,编译完成后,会弹出iPhone模拟器,在模拟器中运行项目,当然我们的项目现在运行起来还只能看到一个空白的界面。
点Xcode左上角的“Stop”按钮,停止运行项目。
编辑界面文件
一般创建一个新项目,在项目中会包含一个或多个界面文件,这些界面文件一般称之为“nib文件”,扩展名为nib或xib。或者通过向导创建一个新的View Controller的时候,Xcode会包含一个对应的nib文件,一个头文件和一个实现文件。在我们刚刚以View-based Application为模板创建的Hello World项目中,“Hello_WorldViewController.xib”就是主界面的nib文件。
在Xcode左侧选中“Hello_WorldViewController.xib”文件,并点击工具栏的“Hide or show the Navigator”和“Hide or show the Utilities ”按钮,隐藏左侧Navigator区域,显示Utility区域,这样我们就可以开始在Xcode 4中来编辑界面。
添加Label到界面中
从对象库中,找到我们所需要的Label控件对象,拖动到主界面中,即完成Label控件的添加
设置Label控件属性
选中新添加的Label控件,点击Inspector selector bar区域的“Show the Attributes inspector”按钮,切换到属性编辑界面,分别设置以下属性:
Text: 输入“Hello World”
Alignment: 选择居中对齐
Font: 选择“Helvetical Bold 26.0”
Text Color: 选择红色
Shadow: 选择黑色(Black Color)
Shadow Offset: Horizontal和Vertical的值分别输入1
设置Label控件的大小和位置
在上面的步骤中设置好Label的相关属性后,发现文字特别小,而且显示不完整,并非我们所选择的字体大小,这是由于UILabel有一个属性“adjustsFontSizeToFitWidth”,默认值是“YES”,如果这个属性的值为YES,并且Label的numberOfLines属性值是1,它会根据Label的宽度来自动调整字体大小,通过Xcode新添加的Label,默认宽度比较小,按照正常的26磅大小的字体,无法完整显示,所以就字体大小就被自动调整了,导致显示的和我们期望的不一样。解决这个问题很简单,就是我们重新设置一下Label的宽度,以让其可以完整显示文字。
选中新添加的Label控件,点击Inspector selector bar区域的“Show the Size inspector”按钮,切换到尺寸和位置设置界面,对宽度进行调整,这里我们给Label设置一个足够的宽度和高度:200x40,以保证字体不会被缩小。
接下来,就是要调整Label的位置,让它显示在屏幕的正中间。在Xcode中,用鼠标拖动Label,拖动过程中Xcode有辅助线来帮助定位,很容易就可以找到正中心的位置。当然也可以通过简单的计算得到Label如果要显示在正中心,坐标应该为:x = (屏幕宽度 - Label宽度) / 2 = (320 - 200) / 2 = 60; y = (屏幕高度 - 状态栏高度 - Label高度) / 2 = (480 - 20 - 40) / 2 = 210;
对修改过的xib文件保存,运行项目,看看效果
就这样,我们已经完成了第一步:在屏幕上显示文字,设置字体和字体大小,让文字显示在屏幕正中心。下一步,我们要让它支持旋转,并且旋转后,文字还是显示在屏幕正中。
支持设备旋转
前面我们已经学习了解过,要支持设备宣传,要做如下工作:
重写对应的View Controller的“shouldAutorotateToInterfaceOrientation:”方法,在方法中申明支持的方向。也就是首先要重写“Hello_WorldViewController.m”中的“shouldAutorotateToInterfaceOrientation:”方法
配置对应的View Controller中的View的autoresizingMask属性,以适应因为界面旋转导致的布局变化。也就是要设置好Label控件的autoresizingMask属性。
还是在界面文件中,选中Label,在尺寸和位置设置界面,通过点击Autosizing中的红色线条,设置Label对上下左右四个方向以及宽度和高度都自动调整,这样就可以保证在设备旋转后,界面的宽度和高度发生改变后,控件对上下左右四个方向的位置以及长度和宽度也会随着一起调整,由于已经设置了文字在Label内部是居中对齐的,就可以保证文字显示在界面居中的位置。
点击工具栏的“Hide or show the Navigator”和“Hide or show the Utilities ”按钮,显示左侧Navigator区域,隐藏Utility区域,在左侧Navigator区域,选中“Hello_WorldViewController.m”文件,找到“shouldAutorotateToInterfaceOrientation:”方法,对其进行重写,重写后代码如下
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
对所做的修改进行保存,然后运行项目,弹出模拟器,通过调用模拟器的设备旋转菜单,让iPhone模拟器变成横屏,你将看到文字会自动调整位置,还是显示在屏幕正中的位置。
至此,我们就实现了项目的全部需求。
项目总结
通过Hello World这个简单项目,我们学习了如何基于Xcode 4分析和开发iOS项目,学习了如何通过iOS Dev Center获取需要的资料。
源码下载:https://github.com/JimLiu/The-practice-of-iPhone-application-development/tree/master/Hello%20World
posted @ 2011-05-12 02:42 宝玉 阅读(13065) 评论(42) 编辑
2011年5月11日
iOS平台XML解析类库对比和安装说明
在iPhone开发中,XML的解析有很多选择,iOS SDK提供了NSXMLParser和libxml2两个类库,另外还有很多第三方类库可选,例如TBXML、TouchXML、KissXML、TinyXML和GDataXML。问题是应该选择哪一个呢?
解析 XML 通常有两种方式,DOM 和 SAX:
DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过遍历树结构可以检索任意XML节点,读取它的属性和值。而且通常情况下,可以借助XPath,直接查询XML节点。
SAX解析XML,是基于事件通知的模式,一边读取XML文档一边处理,不必等整个文档加载完之后才采取操作,当在读取解析过程中遇到需要处理的对象,会发出通知对其进行处理。
一般在iOS平台下,比较常用的XML解析类库有如下几种:
NSXMLParser,http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/Reference/Reference.html ,这是一个SAX方式解析XML的类库,默认包含在iOS SDK中,使用也比较简单。
libxml2,http://xmlsoft.org/,是一套默认包含在iOS SDK中的开源类库,它是基于C语言的API,所以使用起来可能不如NSXML方便。这套类库同时支持DOM和SAX解析,libxml2的SAX解析方式还是非常酷的,因为它可以边读取边解析,尤其是在从网上下载一个很大的XML文件,就可以一边下载一边对已经下载好的内容进行解析,极大的提高解析效率。
TBXML,http://www.tbxml.co.uk/TBXML/TBXML_Free.html,这是一套轻量级的DOM方式的XML解析类库,有很好的性能和低内存占用,不过它不对XML格式进行校验,不支持XPath,并且只支持解析,不支持对XML进行修改。
TouchXML,https://github.com/TouchCode/TouchXML,这也是一套DOM方式的XML解析类库,支持XPath,不支持XML的修改。
KissXML,http://code.google.com/p/kissxml/,这是一套基于TouchXML的XML解析类库,和TouchXML相比,支持了XML的修改。
TinyXML,http://www.grinninglizard.com/tinyxml/,这是一套小巧的基于C语言的DOM方式进行XML解析的类库,支持对XML的读取和修改,不直接支持XPath,需要借助另一个相关的类库TinyXPath才可以支持XPath。
GDataXML,http://code.google.com/p/gdata-objectivec-client/source/browse/trunk/Source/XMLSupport/,这是一套Google开发的DOM方式XML解析类库,支持读取和修改XML文档,支持XPath方式查询。
那么对于如何在项目中选择合适的XML解析类库呢?网上已经有人对这几款XML类库做过分析和对比,可参考《How To Choose The Best XML Parser for Your iPhone Project》http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project 一文,基本比较准确和客观,文中建议:
如果是读取很小的XML文档,性能基本上没有什么差别,不过从调用的方便性来说,建议使用TouchXML、KissXML或GDataXML
如果是需要读取和修改XML文档,建议使用KissXML或GDataXML
如果需要读取非常大的XML文档,则建议使用libxml2或TBXML
如果你不想去调用第三方类库,那么使用NSXML也可以
安装说明
GDataXML
1. 从http://code.google.com/p/gdata-objectivec-client/downloads/list下载“gdata-objective-c client library.”
2. 解压缩文件,找到Source\XMLSupport,并且将其中的GDataXMLNode.h 和 GDataXMLNode.m文件拖到项目中
3. 选中项目,选中“Build Settings”标签页
4. 将Build Settings页中,顶部的“Basic”标签切换到“All”
5. 找到“Paths\Header Search Paths”项,并添加“/usr/include/libxml2”到列表中
6. 找到“Linking\Other Linker Flags”项,并添加“-lxml2”到列表中
在需要调用GDataXML的代码文件头部,加入:
#import “GDataXMLNode.h”
TouchXML
1. 从https://github.com/TouchCode/TouchXML下载最新TouchXML源码
2. 解压后,将其中的Sources目录下的文件和目录都拖到项目中
3. 选中项目,选中“Build Settings”标签页
4. 将Build Settings页中,顶部的“Basic”标签切换到“All”
5. 找到“Paths\Header Search Paths”项,并添加“/usr/include/libxml2”到列表中
6. 找到“Linking\Other Linker Flags”项,并添加“-lxml2”到列表中
在需要调用TouchXML的代码文件头部,加入:
#import “TouchXML.h”
TBXML
1. 从http://www.tbxml.co.uk/TBXML/TBXML_Free.html下载最新TBXML源码
2. 解压后,将其中的TBXML.h, TBXML.m, NSDataAdditions.h和NSDataAddtions.m四个文件拖到项目中
3. 添加对libz.dylib类库的应用
在需要调用TBXML的代码文件头部,加入:
#import “TBXML.h”
使用说明
GDataXML
读取XML文件,并解析成为DOM文档对象示例:
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"xml"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (doc == nil) { return nil; }
NSLog(@"%@", doc.rootElement);
[doc release];
[xmlData release];
posted @ 2011-05-11 09:14 宝玉 阅读(2630) 评论(4) 编辑
2011年5月10日
ASIHTTPRequest类库简介和使用说明
官方网站: http://allseeing-i.com/ASIHTTPRequest/ 。可以从上面下载到最新源码,以及获取到相关的资料。
使用iOS SDK中的HTTP网络请求API,相当的复杂,调用很繁琐,ASIHTTPRequest就是一个对CFNetwork API进行了封装,并且使用起来非常简单的一套API,用Objective-C编写,可以很好的应用在Mac OS X系统和iOS平台的应用程序中。ASIHTTPRequest适用于基本的HTTP请求,和基于REST的服务之间的交互。
ASIHTTPRequest功能很强大,主要特色如下:
l 通过简单的接口,即可完成向服务端提交数据和从服务端获取数据的工作
l 下载的数据,可存储到内存中或直接存储到磁盘中
l 能上传本地文件到服务端
l 可以方便的访问和操作请求和返回的Http头信息
l 可以获取到上传或下载的进度信息,为应用程序提供更好的体验
l 支持上传或下载队列,并且可获取队列的进度信息
l 支持基本、摘要和NTLM身份认证,在同一会话中授权凭证会自动维持,并且可以存储在Keychain(Mac和iOS操作系统的密码管理系统)中
l 支持Cookie
l 当应用(iOS 4+)在后台运行时,请求可以继续运行
l 支持GZIP压缩数据
l 内置的ASIDownloadCache类,可以缓存请求返回的数据,这样即使没有网络也可以返回已经缓存的数据结果
l ASIWebPageRequest –可以下载完整的网页,包括包含的网页、样式表、脚本等资源文件,并显示在UIWebView /WebView中。任意大小的页面都可以无限期缓存,这样即使没有网络也可以离线浏览
l 支持客户端证书
l 支持通过代理发起Http请求
l 支持带宽限制。在iOS平台,可以根据当前网络情况来自动决定是否限制带宽,例如当使用WWAN(GPRS/Edge/3G)网络时限制,而当使用WIFI时不做任何限制
l 支持断点续传
l 支持同步和异步请求
2.1.1安装说明
如果想在iOS项目中使用ASIHTTPRequest,需要在项目中进行简单的配置,步骤如下:
1) 添加文件
往一个Xcode项目中添加第三方类库文件,有两种方式:
1. 第一种方式,在Finder中打开需要添加到文件或文件夹,在Xcode中打开要添加文件的项目,然后选中要添加的文件或文件夹,将它从Finder中拖到Xcode中,然后释放。在弹出的对话框中,如果文件已经拷贝到了项目文件目录中,则不需要选中“Copy items”的复选框;如果文件没有拷贝到项目文件目录,就需要选中“Copy items”的复选框,这样Xcode会自动把文件复制到项目文件目录下。如下图所示:
2. 第二种方式,在Xcode中,在要添加文件的分组下点右键,选中“Add Files to “My Project”…”菜单,在弹出的文件浏览对话框中选中要添加到文件或文件夹。如果要添加文件已经拷贝到了项目文件目录中,则不需要选中“Copy items”的复选框;如果文件没有拷贝到项目文件目录,就需要选中“Copy items”的复选框,这样Xcode会自动把文件复制到项目文件目录下。如下图所示:
根据上面的说明,添加ASIHTTPRequest相关文件到Xcode项目中,所需文件列表如下:
ASIHTTPRequestConfig.h
ASIHTTPRequestDelegate.h
ASIProgressDelegate.h
ASICacheDelegate.h
ASIHTTPRequest.h
ASIHTTPRequest.m
ASIDataCompressor.h
ASIDataCompressor.m
ASIDataDecompressor.h
ASIDataDecompressor.m
ASIFormDataRequest.h
ASIInputStream.h
ASIInputStream.m
ASIFormDataRequest.m
ASINetworkQueue.h
ASINetworkQueue.m
ASIDownloadCache.h
ASIDownloadCache.m
ASIAuthenticationDialog.h
ASIAuthenticationDialog.m
Reachability.h (在源码的 External/Reachability 目录下)
Reachability.m (在源码的 External/Reachability 目录下)
2) 链接相关类库
1. 选中项目
2. 选中目标
3. 跳转到“Build Phases”标签
4. 展开“Link Binary With Libraries”分组
5. 点击“+”添加类库
如下图所示:
6. 从列表中选择CFNetwork.framework,然后点击“Add”按钮。
7. 按照上一步相同的方法添加:SystemConfiguration.framework, MobileCoreServices.framework,CoreGraphics.framework和libz.1.2.3.dylib这几个类库。
8. 添加完后,可以将添加好的一起类库拖到Xcode项目的Frameworks目录下
2.1.2使用说明
ASIHTTPRequest有很多功能,所有功能说明都可以在其官方网站的相关文档中查到,限于篇幅,本章仅简单介绍一下如何使用ASIHTTPRequest来进行同步Http请求和异步Http请求。在后面的章节中,我们还会用到它的一些其他功能。
在使用ASIHTTPRequest之前,请确认已经正确安装,然后在需要应用它的代码文件头部,加入:
#import “ASIHTTPRequest.h”
这样就可以在代码中使用ASIHTTPRequest相关的类。
创建一个同步请求
这是ASIHTTPRequest最简单的一种使用模式,发送startSynchronous消息后即开始在同一线程中执行HTTP请求,线程将一直等待直到请求结束(请求成功或者失败)。通过检查error属性可以判断请求是否成功或者有错误发生。
要获取返回的文本信息,调用responseString方法。如果下载的是二进制文件,例如图片、MP3,则调用responseData方法,可以得到一个NSData对象。
- (IBAction)grabURL:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
}
}
一般情况下,应该优先使用异步请求代替同步请求,当在主线程中使用ASIHTTPRequest同步请求,应用程序的界面会锁定,无法进行任何操作,直到请求完成。
创建一个异步请求
上例中的同步请求,如果换成异步方式来调用,请求是在后台线程中运行,当请求执行完后再通知调用的线程。这样不会导致主线程进行网络请求时,界面被锁定等情况。
- (IBAction)grabURLInBackground:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// 当以文本形式读取返回内容时用这个方法
NSString *responseString = [request responseString];
// 当以二进制形式读取返回内容时用这个方法
NSData *responseData = [request responseData];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
}
写一个iPhone应用程序,要求可以输入名字,点击按钮后,会显示一段文字向输入的名字打招呼,例如输入“宝玉”,显示“你好,宝玉!”
需求分析
这是一个很简单的应用程序,包含一个文本输入框,一个文本显示框,一个按钮。输入名字到文本输入框,再点击按钮,这时文本显示框的文字就会变成“你好,<名字>!”。但是要注意,如果用户输入为空,要有警告提示用户重新输入;如果用户输入文字太长,超过16个字符,要自动截断。
产品设计
根据项目需求,画出相应的产品原型图:
初始状态
初始时,文本输入框为空,但是显示水印,提醒用户可以输入姓名。文本显示框文字为空。
输入名字并点击按钮后
输入名字,并点击按钮后,屏幕中间显示文字:“您好,<名字>!”。
没有输入名字的警告提示
如果没有输入名字,点击按钮后弹出警告窗口,提醒用户输入名字。
系统分析
这是一个非常简单的应用程序,实现思路不不算复杂:
一个文本输入框,用来输入文字,需要限制最大字符长度为16个字符,输入框没有内容时,显示水印文字。UITextField控件正好可以满足需求。
一个文本显示框,用来显示最终生成的文字。使用UILabel控件即可满足需求。
一个按钮,点击后,获取文本输入框文字内容,生成“你好,<名字>!”文字,并显示在文本显示框中。如果点击时文本输入框文字为空,弹出警告提示框。
同时,这个应用程序在开发过程中,需要应用到iPhone开发中一些常用的设计模式:
委托(Delegate)
模型 视图 控制器(MVC)
目标 - 动作(Target-Action)
委托(Delegate)
委托模式是一个对象周期性地向被指定为其委托的另一个对象发送消息,向其请求输入或者通知某件事情正在发生。该模式可替换类继承来对可复用对象的功能进行扩展。
在本项目中,应用程序对象会向其委托发送消息,通知它主要的启动例程已经完成并且定制的配置可开始执行。为了建立并管理视图,委托会创建一个控制器实例。另外,当用户点击Return按键后,文本字段也会通知它的委托(即所创建的控制器对象)
委托方法通常会集中在一起形成一份协议。 一份协议基本上就是一个方法的列表。如果一个类遵循某个协议,则它要保证实现协议所要求的方法(有些方法可选择实现与否)。委托协议规定了一个对象可以发送给委托的所有消息。例如常见的有:UITextFieldDelegate, UIApplicationDelegate, UIScrollViewDelegate, UITableViewDelegate, UIWebViewDelegate。
模型 视图 控制器(MVC)
MVC模式将应用程序中的对象设定为三种角色:模型角色(Model)、视图角色(View)和控制器角色(Controller)。
模型对象(Model)表示数据。例如,在iPhone自带的通讯录应用中,联系人是模型对象,在一个绘画应用中,圆形、矩形是模型对象。
本项目的应用程序用到的数据非常简单——字符串,并且该字符串只有在按钮点击的方法中用到。其实换一种角度来说,字符串也是一种最简单的模型对象,在其他的应用程序中,模型对象将会更加复杂,并且模型对象在程序中无处不在,可以在多个地方进行访问。
视图对象(View)负责显示数据,比如UILabel可以显示文本、UIImageView可以显示图片,也会支持用户对数据的编辑操作,例如UITextField可以支持用户输入。
在我们接下来要创建的项目中,需要一个主视图来包含其它几个视图——首先是一个文本输入框,它用于捕获用户输入信息;然后是一个文本显示框,它用于显示文本,而文本内容则是基于用户的输入;另外还需要一个按键,让用户可以点击它,点击后通知文本字段更新。
控制器对象(Controller)介于模型和视图之间。
在我们接下来要创建的项目中,当用户点击按钮后,触发更新操作,控制器对象将会从文本输入框中获取输入的文字内容,并把文字存放在一个字符串中,然后再把文本显示框的内容更新成格式化好的内容。
结合MVC模式,对于本项目的主要流程,整个如图所示:
目标 - 动作(Target - Action)
目标-动作机制,允许一个控件对象(例如按键或滑动条) 向另外一个对象发送一条消息(即动作),以之作为对某个用户事件(例如一个点击事件)的响应。接收到消息的对象则可以对消息进行响应,并针对业务要求做出处理。
在本项目中,当点击按钮时,它会通知控制器去获取文本输入框内容,并根据输入内容更新文本显示框。
开发
创建项目
我们将开始使用Xcode来创建项目,启动Xcode(缺省情况下,Xcode位于 /Developer/Applications 里面),然后选择File > New > New Project,这样就可以创建一个新的工程。应该可以看到一个新的窗口,如下图所示:
选中 Window-Based Application 并点击 Next 按钮,输入Product Name(项目名):SayHello,在Company Identifier那,可以输入公司名唯一标识。
点击Next,选择项目存储位置,最后点击Create按钮。
完成上述步骤后,将看到如下的新项目窗口:
在进行下一步工作之前,可以先编译运行一下程序,这样就可以通过模拟器看到程序运行后的样子。在Xcode的菜单中选择 Product > Run 或者点击左上角工具栏上的 Run 按钮,iPhone模拟器应该会自动启动。当应用程序启动后,可以看到一个白色屏幕。
应用程序启动过程解析
通过Xcode的模板创建项目时,模板已经帮助设置好了应用程序基本程序环境,它会帮助创建一个应用程序对象,将应用程序和窗口连接起来,建立一个运行环境。整个启动过程从UIApplicationMain函数开始,如下图所示:
main.m文件中的main函数会调用UIApplicationMain函数:
int retVal = UIApplicationMain(argc, argv, nil, nil);
该函数将会创建一个UIApplicaion类的实例。同时它会搜索应用程序的Info.plist属性列表文件。 Info.plist文件是一部字典,它主要包含诸如应用程序名称、图标这样的信息,它也包含应用程序对象应该加载的nib 文件(虽然该文件的扩展名为“xib”,但是我们习惯称之为“nib 文件”)的名称。Nib文件主要有用户界面的信息。本项目的Info.plist文件具有下面的内容:
术语: 虽然Interface Builder文档的扩展名可能是“.xib” ,但历史上,其扩展名是“.nib”(“NextStep Interface Builder”的首字母缩写),因此人们就俗称其为“Nib文件”。
这表明应用程序启动时将会加载MainWindow nib文件。在Xcode中可以单击MainWindow.xib进行查看(注意在Xcode4中已经不需要通过Interface Builder来打开nib文件,可以直接在Xcode对nib文件进行查看和编辑):
MainWindow Nib文档包含4个对象:
File's Owner,文件拥有者代理对象,在这里MainWindow的拥有者对象时UIApplication实例
First Responder,第一响应者代理对象,在本项目中,没有使用到
Say Hello App Delegate,SayHelloAppDelegate的实例,也就是应用程序的委托
Window,一个窗口对象。它默认是白色背景,程序启动时看到的就是它
应用程序对象在完成启动后,会向委托发送applicationDidFinishLaunching:消息,通知程序已经启动成功了,这样我们可以在收到这个消息后根据需要进行一些操作。下图是一个简化的iPhone应用程序生命周期图,简要展示了发生在应用程序启动到退出的过程。
这样,我们基本了解了如何创建一个项目,以及一个应用程序的启动过程,接下来,我们需要创建一个视图控制器(UIViewController)实例,用来实现项目功能。
添加视图控制器(UIViewController)
添加视图控制器文件
在iPhone应用程序中,视图控制器(UIViewController)起着核心作用。顾名思义,视图控制器负责管理控制视图。在iPhone上,它们也帮助进行导航和内存管理。
选中Xcode项目管理器里的项目(即SayHello项目,位于Groups and Files列表的顶部)或者选中SayHello文件夹——新文件在添加时会被加入到当前选择的位置。 选中后,在Xcode菜单中选择 File > New > New File,也可以在选中的文件夹上面点右键,选择 New File。
在New File窗口中,请选择Cocoa Touch,然后选择UIViewController subclass。
点击 Next 按钮,在Options窗口,请勾选 “With XIB for user interface”复选框。选中 “With XIB for user interface”后,Xcode在创建视图控制器的同时,会为其创建一份nib文件,并将该文件添加到项目中。
点击Next按钮,在其后出现的保存文件窗口中,为文件起个名字,例如RootTimelineViewController,并选择文件存储的位置,如下所示:
点击 Save,文件会被添加到项目中。接下来,我们将创建控制器类的实例。
创建视图控制器实例
现在,我们有了视图控制器的类和nib文件,但要在应用程序代理中使用它,还必须创建类的实例,并且将实例存储在变量中,以便操作它。
在应用程序委托类的头文件(即SayHelloAppDelegate.h)中执行下述操作:
在一个类中访问另一个类,首先需要引用被访问类的头文件。所以我们先在应用程序委托头文件(SayHelloAppDelegate.h)的接口声明前面-即SayHelloAppDelegate声明前面引用视图控制器(RootViewController)的头文件:
#import "RootViewController.h"
然后在头文件大括号之间添加下面的代码,这是为了向应用程序委托添加一个实例变量:
RootViewController *viewController;
在大括号之后 @end之前添加下面的属性声明:
@property (nonatomic, retain) RootViewController *viewController;
在头文件中添加完相应变量和属性申明后,需要在对应的实现文件中,合成属性的存取方法,在dealloc方法中释放视图控制器的实例。
在应用程序委托类的实现文件(即SayHelloAppDelegate.m)中执行下述操作:
在类的 @implementation代码块中通知编译器为视图控制器合成存取方法:
@synthesize viewController;
在dealloc方法起始处释放视图控制器:
[viewController release];
我们已经把视图控制器属性添加到应用程序的委托,现在需要实际创建一个视图控制器实例,并将其设置为属性的值。
在应用程序委托类实现文件(即SayHelloWorldAppDelegate.m文件)中的applicationDidFinishLaunching: 方法开头添加如下代码,这些代码用于创建一个RootViewController实例:
RootViewController *controller = [[RootViewController alloc]initWithNibName:@"RootViewController" bundle:nil];
self.viewController = controller;
[controller release];
这段代码的作用如下:
创建RootViewController这个视图控制器的实例。使用alloc方法创建一个视图控制器,然后用initWithNibName:bundle:方法对其进行初始化。init方法先指定控制器应加载的nib文件,然后指定在哪个程序包中可找到该文件。程序包是文件系统某个位置的抽象,该位置存放了应用程序将会用到的代码和资源。
使用属性的存取方法,将创建好的视图控制器实例设置为viewController属性变量的值
根据内存管理规则释放视图控制器
视图控制器用来配置和管理在应用程序中看到的视图,每一个视图也对应有一个视图控制器来管理。窗体(window)有一个根视图控制器——这个视图控制器负责配置当窗体显示时最先显示的视图。要让你的视图控制器的内容显示在窗体中,需要去设置窗体的根视图控制器为你的视图控制器。
所以我们的项目中,在上面创建视图控制器实例代码后面再添加一行代码,来设置窗体的根视图控制器为我们新添加的视图控制器:
self.window.rootViewController = controller;
最后一行来自于Xcode提供的模板自动生成的代码:
[self.window makeKeyAndVisible];
这行代码会让包含了视图控制器视图的Window窗口显示在屏幕上。
本章完整代码,SayHelloAppDelegate.h文件:
#import <UIKit/UIKit.h>
#import "RootViewController.h"
@interface SayHelloAppDelegate : NSObject <UIApplicationDelegate> {
RootViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) RootViewController *viewController;
@end
SayHelloAppDelegate.m文件:
#import "SayHelloAppDelegate.h"
@implementation SayHelloAppDelegate
@synthesize window=_window;
@synthesize viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RootViewController *controller = [[RootViewController alloc]initWithNibName:@"RootViewController" bundle:nil];
self.viewController = controller;
[controller release];
self.window.rootViewController = controller;
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc
{
[_window release];
[viewController release];
[super dealloc];
}
@end
测试运行
在Xcode的菜单中选择 Product > Run 或者点击左上角工具栏上的 Run 按钮,iPhone模拟器应该会自动启动。当应用程序启动后,还是看到一个白色屏幕,不过第一次看到的白色屏幕,是应用程序代理中的Window,而这次看到的白色屏幕,是视图控制器RootViewController中的视图。
下一步,我们将开始对界面进行编辑。
编辑Nib文件
在iPhone开发中,一般都会用NIB文件来来负责界面显示,也就是MVC模型里面的视图对象,而NIB文件只包含用户界面元素,不包含任何源码,那么怎么让视图对象和视图控制器关联起来呢?这就需要用到两个非常重要的概念:插座变量(outlet)和文件拥有者代理对象(File's Owner)。
视图控制器的视图和Nib文件
视图控制器主要的职责就是配置和管理应用程序中所有的视图,一般来说,视图控制器的视图是放在一个Nib文件中,当然也可以不需要Nib文件,通过程序创建视图,典型的如UITableViewController这样的视图控制器,就可以不需要Nib文件。在创建视图控制器实例时,其中一个主要的构造函数 initWithNibName:bundle: 的第一个参数就是视图控制器对应的Nib文件的名字。视图控制器在其 loadView 方法中加载它的Nib文件。如果是使用 initWithNibName:bundle: 构造函数生成的实例,并且你想在视图加载完成后进行额外的设置,只要重写视图控制器的 viewDidLoad 方法就好了。
在Xcode中点击打开视图控制器的Nib文件(即RootViewController.xib文件),在Xcode中即可直接查看和编辑。文件包含三个对象,文件拥有者代理(File's Owner),第一响应者代理(First Responder)以及一个视图(View)。视图(View)是视图控制器的主视图,在主视图中还可以添加若干子视图。文件拥有者代理(File's Owner)代表Nib文件对应的视图控制器类。理解文件所有者代理的角色,以及如何建立文件所有者和Nib文件中界面元素之间的连接,是非常重要的。
小贴士: 在Xcode中编辑Nib文件时,可以通过点击右上角工具栏按钮 显示隐藏相应面板,方便对界面编辑和属性设置。
文件拥有者(File's Owner)
在一个Nib文件中,文件拥有者对象是其中最重要的对象之一,因为正是通过它,来建立起应用程序代码和Nib界面文件中对象之间的连接,具体来说,它就是对应Nib文件的视图控制器对象。以本项目为例,RootViewController.xib这个Nib文件的文件拥有者对象就是RootViewController类的实例。
一般来说,在使用模板同时创建UIViewController文件和对应的Nib文件时,它默认会设置Nib文件对应的文件拥有者为创建的UIViewController类。如果要修改或者设置Nib文件对应的文件拥有者,可以使用 Identity Inspector 面板进行设置。
如上图所示, 本项目的RootViewController.xib文件对应的文件所有者,在Identity Inspector 面板中,Custom Class部分的Class项,可以看到对应的值是RootViewController,这表示文件拥有者就是RootViewController类的实例,就可以在Xcode中访问文件拥有者类里面标志为IBOutlet的属性和IBAction的方法,和Nib文件中的界面元素建立关联。
视图插座变量
在Xcode中,使用 Inspector 面板,或者在连接面板,可以查看、创建、删除对象之间的连接。要查看视图控制器的连接,可以通过以下步骤:
在Xcode的界面中,从左侧的文件组选中要查看的视图控制器的Xib文件
在视图编辑界面,点击选中 File's Owner
在 Inspector 面板,选中 Connection inspector,这里会显示文件所有者所有的插座连接
在视图编辑界面,按住Control键点击 File's Owner 或者在 File's Owner上点击右键,弹出一个黑色半透明的面板显示文件所有者的所有连接
在上面第三步,右侧面板显示的连接面板和右键点击File's Owner弹出的半透明连接面板,显示的信息和作用都是一样的,可以根据个人习惯灵活使用。到目前为止唯一的连接是视图控制器的 view 插座变量。一个插座变量就对应视图控制器类的一个属性(有时候也可以是一个实例变量),只不过这个属性和nib文件中的某个界面元素连接在一起。此处的view的连接,表明当nib文件 RootViewController.xib 被加载,并且UIView的实例解档之后,视图控制器的view实例变量会被设置为指向nib文件中的视图。
中间测试
在项目开发中,尤其在对开发工具和语言不熟悉的时候,需要经常性的对新增的功能进行测试,以确保当前功能运行是正常的。比如我们新增了RootViewController这个自定义视图控制器,需要去测试一下它是不是已经成功添加。要测试视图控制器工作正常,简单的办法修改视图控制器的视图的背景色,例如修改为粉红色背景,然后重新运行,看看是不是界面变成了红色背景。
要设置视图控制器的视图的背景色,步骤如下:
在Xcode的界面中,从左侧的文件组选中视图控制器的Xib文件(RootViewController.xib)
在右侧的功能区域,选择属性面板(Attributes inspector)
在编辑区域,选择视图
在视图的属性面板,点击背景色(Background)对应的颜色下拉框,会弹出颜色选择面板
在颜色选择面板,选择一个合适的颜色,例如粉红色
保存nib文件
点击左上角工具栏的Run按钮,编译运行项目
正常情况下,编译应该不会出现任何错误,运行后会弹出模拟器,结果如下图所示:
确认没有问题后,再将应用的背景色还原。还原的话,将视图的背景色设置为白色就好了。
配置视图
Xcode提供了一套对象库,可以直接添加到Nib文件中。其中一部分示界面元素,例如按钮和文本输入框;其他一部分是控制器对象,例如视图控制器。我们当前项目的nib文件已经包含了视图,现在只要添加按钮和文本输入框就好了。从对象库中将用户界面元素拖动到视图中,基本步骤如下:
在Xcode的界面中,从左侧的文件组选中视图控制器的Xib文件(RootViewController.xib)
在右侧的功能区域,显示对象库(object library)
添加一个按钮(UIButton),一个文本输入框(UITextField),两个文本标签(UILabel)到视图中。可以从对象库里面拖动并将它们放到视图
参考前面的原型设计,对界面元素的尺寸和布局进行调整
将右侧功能区域切换到属性面板(Attributes inspector)
选中文本输入框(Text Field),设置Placehold属性为“请输入姓名”
选中左上侧的文本标签(UILabel),设置Text属性为“姓名”
选中下面的文本标签(UILabel),设置Text属性为空,Alignment属性设置为居中对齐
选中按钮(UIButton),设置Title属性为“招呼”
设置好的界面如下所示:
如果我们想让用户在输入时有一些更好的体验,比如用户输入英文名时,默认会首字母大写;比如键盘会显示完成(Done)按键,点击后完成输入隐藏键盘。要支持这样的输入细节,通过设置文本框属性就可以完成:
在Capitalization下拉列表,选择Words,以支持首字母大写
在Return Key下拉列表,选择Done,以支持键盘上显示完成(Done)按键
保存文件后,编译运行程序,可以看到运行的界面效果和我们在Xcode中摆放的效果是一样的。点击按钮,按钮会高亮,在文本输入框中点击,会弹出输入键盘,键盘里可以看到完成(Done)按钮。但是还不能根据输入的内容去显示文字,还不能隐藏键盘,因为目前我们还仅仅完成了视图部分的工作,还需要让视图中的对象和视图控制器的对象之间建立连接,并添加相应的逻辑,才能实现。
实现视图控制器
实现视图控制器需要完成以下几件事:
定义插座变量和动作方法,和Nib文件的视图中的界面元素进行关联
实现点击按钮后的相关逻辑——根据输入的名字显示相应的招呼语,判断输入的名字是不是为空是不是超长
用户点击键盘上的完成(Done)按键后,键盘会消失
建立连接
从业务角度来看,我们需要和界面的几个元素建立关联:
文本输入框,获取它的输入文字
文本标签,让它显示特定文字
按钮,响应它的点击事件
在Xcode4之前,Interface Builder和Xcode是分开的,一般是先在Xcode中定义好插座变量和动作方法,然后再在InterfaceBuilder中去建立界面元素和视图控制器之间的连接,到Xcode4之后,Interface Builder和Xcode已经统一合并在了一起,所以这部分也有一些变化,Xcode4让这部分工作变的更加容易一些,可以直接从视图编辑界面拖动连接到代码文件。
在我们正在开发的SayHello项目中,现在我们需要添加一个动作方法到视图控制器,当界面上的按钮被点击时,它会发送一个sayHello:消息到视图控制器,所以接下来要为按钮创建一个sayHello:动作方法:
在Xcode中,选择视图控制器对应的Nib文件(RootViewController.xib)
显示Assistant editor
让Assistant显示视图控制器的头文件(RootViewController.h)
按住Control键,从Nib文件中的按钮拖动到头文件的方法声明代码区域
在弹出的面板中,将按钮和视图控制器之间的连接设置为动作(Action)
设置 Connection 为 Action
设置 Name 为 sayHello:
设置 Type 为 id
设置 Event 为 Touch Up Inside,也就是用户在点击按钮,然后释放后触发
设置 Arguments 为 Sender
点击Connect建立连接
通过上面的为按钮添加动作的操作,完成了两件事
添加了相应的代码到视图控制器的类中
头文件中增加了如下代码:
- (IBAction)sayHello:(id)sender;
并且实现文件中增加了相应的实现方法:
- (IBAction)sayHello:(id)sender {
}
IBAction 是一个特殊的关键字,它唯一的作用是告诉Interface Builder将某个方法当成目标/动作关联中的动作。它被定义为void。
建立了按钮到视图控制器之间的连接。建立连接的意义,等同于在按钮上调用 addTarget:action:forControlEvents: ,并且 target 是文件拥有者(File's Owner)也就是视图控制器,action 是 sayHello: 方法,对应的事件是 UIControlEventTouchUpInside。
接下来要建立文本输入框和文本标签之间的连接:
在Xcode中,选择视图控制器对应的Nib文件(RootViewController.xib)
显示Assistant editor
让Assistant显示视图控制器的头文件(RootViewController.h)
按住Control键,从Nib文件中的文本输入框拖动到头文件的方法声明代码区域
在弹出的面板中,将文本输入框和视图控制器之间的连接设置为插座(Outlet)
设置 Connection 为 Outlet
设置 Name 为 nameTextField
设置 Type 为 UITextField
点击Connect建立连接
通过上面的为文本输入框添加插座变量的操作,完成了两件事
添加了相应的代码到视图控制器的类中
头文件中增加了如下代码:
@property (nonatomic, retain) IBOutlet UITextField *nameTextField;
并且实现文件中增加了相应的实现方法:
在顶部增加了:
@synthesize nameTextField;
在 dealloc 方法中添加了
[nameTextField release];
在 viewDidUnload 方法中添加了:
[self setNameTextField:nil];
IBOutlet是一个特殊的关键字,它唯一的作用是通知Interface Builder将某个实例变量或者属性当成插座变量。实际上,这个关键字被定义为空白,因此在编译的时候它没有任何作用。
建立了文本输入框到视图控制器之间的连接。建立连接的意义,等同于在视图控制器上调用 setNameTextFiled: 方法,将文本输入框作为参数传入。
按照上面创建文本输入框插座变量相同的方法,再建立用来显示问候语的文本标签的插座变量,并且将插座变量命名为 greetingLabel,类型为 UILabel。
实现逻辑代码
点击视图中的按钮,它会向视图控制器发送 sayHello: 消息,之后,视图控制器会取得文本输入框文字内容,根据内容来更新用来显示问候语的文本标签的内容。以下是RootViewController.m文件中 sayHello: 方法代码的实现:
- (IBAction)sayHello:(id)sender {
// 获取文本输入框内容,并存储到变量中
NSString *nameString = nameTextField.text;
// 检查输入的名字是否为空,如果为空,弹出提示信息
if (nameString.length == 0) {
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"名字不能为空" message:@"请输入名字后,重新点击按钮。" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alertView show];
[alertView release];
greetingLabel.text = @"";
return;
}
// 检查名字是不是超过16个字符,超过16个字符自动截断
if (nameString.length > 16) {
nameString = [nameString substringToIndex:16];
}
// 根据输入的名字,生成问候语
NSString *greeting = [NSString stringWithFormat:@"你好,%@!", nameString];
// 显示问候语
greetingLabel.text = greeting;
}
对于这个方法有几点补充说明:
UIAlertView是专门用来显示消息提示对话框
stringWithFormat:方法符串按照格式化字符串所指定的格式创建一个新字符串。%@表明此处应该使用一个字符串对象来代替。
隐藏键盘
编译并运行应用程序。在文本框中输入“Jim”,点击按键后,标签显示“你好, Jim!” 。但是选择文本字段进行输入,您会发现您没有办法表示已完成输入,也没有办法消除键盘。在iPhone应用程序中,当一个允许文本输入的元素变成第一响应者时,键盘就会自动显示出来,而当该元素不再处于第一响应者状态,键盘就会消失。我们不能直接向键盘发送消息,但是可以切换文本输入元素的第一响应者状态,利用该操作的附加效果来显示或消除键盘。在应用程序中,当用户点击文本字段时,该控件就会变成第一响应者,因此键盘就会显示出来。而当用户点击键盘中的Done按键时,希望键盘消失。
UITextFieldDelegate协议包含一个textFieldShouldReturn:方法,一旦用户点击Return按键,文本字段就会调用该方法(和按键的标题无关)。但将视图控制器设置成文本输入框(UITextField)的委托(Delegate),才可以实现该方法,在方法中向文本字段发送resignFirstResponder消息,这个消息的附加效果会让键盘消失。
通过以下步骤设置文本输入框的委托(delegate)连接:
在Xcode中,选择视图控制器对应的Nib文件(RootViewController.xib)
按住Control键,点击文本输入框
在弹出的半透明面板中,选中 delegate 后面的圆点,并拖动到 File's Owner
接下来,来实现将RootViewController作为文本输入框nameTextField的委托(delegate)
在视图控制器的头文件(RootViewController.h)中,在UIViewController后面添加<UITextFieldDelegate>:
@interface RootViewController : UIViewController<UITextFieldDelegate> {
这个申明表示视图控制器RootViewController将支持UITextFieldDelegate协议
在视图控制器的实现文件(RootViewController.m),实现 textFieldShouldReturn: 方法:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (nameTextField == textField) {
[nameTextField resignFirstResponder];
}
return YES;
}
因为这个应用程序只有一个文本输入框,所以其实不需要包含nameTextField == textField检查。不过有些时候,对象可能会被设置成多个相同类型的对象的委托,这时候就需要来区分这些对象。
至此我们已经开发完成了整个应用程序。接下来将对它进行测试。
测试
这个应用程序相对简单,我们设计几个测试场景:
输入正常的名字,例如“宝玉”,然后点击按钮,看看是不是会显示“你好,宝玉!”
不输入任何名字,点击按钮,看看是不是会有提示信息,要求输入名字。
分别输入16个、17个、20个字符的名字,看看名字是不是最多只能显示前16个字符
点击文本输入框,显示键盘,点击键盘上的Done按钮,看键盘是不是会隐藏
针对这个测试场景,逐一做一下功能的测试,看起来结果和我们预期的完全一样。
小结
通过这样一个简单的项目,了解以下知识点:
iOS开发常用的一些设计模式
iPhone程序的启动过程
视图控制器和Nib文件如何建立连接
这些知识对于iPhone开发和iOS开发来说,都是会经常用到的知识。
posted @ 2011-06-09 08:08 宝玉 阅读(7213) 评论(37) 编辑
2011年5月12日
基于Xcode4开发第一个iPhone程序:“Hello World”
项目要求
写一个iPhone程序,在屏幕正中显示文字“Hello Word”,粗体,字体大小26磅,字体颜色红色,有黑色阴影,阴影光源为左上角,偏移1像素,支持设备旋转。
需求分析
在开始之前,我们首先来分析一下项目需求,这是一个非常简单的项目,只要在屏幕上显示一段“Hello World”的文字,当然还有一些附加条件:
对字体、字体颜色、字体大小有要求,有阴影效果
要求文字显示在屏幕正中
支持设备旋转,并且无论设备如何旋转,文字都还是显示在屏幕正中
根据这些需求,我们将从简单到复杂,逐步来实现,分成2步来实现:
在屏幕上显示文字,设置字体和字体大小,让文字显示在屏幕正中心
支持设备旋转,并且保证旋转后文字还是居中状态
产品设计
iPhone4之前的屏幕是320x480,到iPhone4的时候,支持了高清屏,屏幕分辨率变成了640x960。iPhone支持四个方向的旋转的,横屏和竖屏表现略有差异,因为项目需求要求支持屏幕旋转,所以针对横屏和竖屏,界面表现有所差异,简单画一下原型设计图如下:
系统分析和设计
如果我们还没iOS下的开发经验,那么首先需要去查阅一些相关资料,让我们知道如何来开发一个iphone程序。苹果为iOS的开发者提供了一个非常详细和全面的网站:“iOS Developer Center”,网址:http://developer.apple.com/ios。在iOS Dev Center,有所有iOS SDK的类文档、入门文档、各种开发指南、示例代码库等,开发iOS平台的项目,免不了要经常上来查阅一些相关资料。不过比较遗憾的是,目前iOS Dev Center的文档和资料还是英文为主,中文资料较少,对于英文阅读不好的同学是一个考验。
现在,我们从技术角度来分析一下如何实现项目需求。同样一个项目,无疑是有很多种技术方案来实现的,所以我们有必要定一个原则,来帮助我们选择合适的方案,这个原则就是简单实用原则:“我们尽可能采用简单并且实用的技术方案,避免使用复杂的技术方案,把时间和精力浪费在一些华而不实的技巧上面”,本着这个原则,我们来开始对项目需求进行技术方案的选择:
在屏幕上显示特定字体和大小的文字
要在屏幕上显示特定字体和大小的文字,我们需要先看看iOS SDK中是否已经提供了简单实用的方式来显示文字,在iOS Dev Center中,有一篇文章“iOS Human Interface Guidelines”,专门讲解了iOS中用户界面相关的知识,从中我们可以系统的了解iOS的界面构成,各种基本界面元素,并且根据其中的说明,可以找到UILabel控件是最适合我们项目需求的控件,当然也有复杂的技术方案,就是采用在界面上自画的方式,根据简单实用原则,我们就使用UILabel这种iOS自带控件就可以了。
在开始使用UILabel之前,我们需要先来学习了解一下UILabel控件,想要了解UILabel控件的功能,在iOS Dev Center中,找到“UILabel Class Reference”,从中我们可以看到UILabel的介绍和所有属性、方法等详细的说明文档。
文档相当全面,不过对于我们来说,关键还是要去获取项目相关的资料,从文档中,我们可以逐一找到我们显示文字需要的相关属性:
text: Label显示的文字,类型为NSString类,也就是本项目需求中要显示的“Hello World”。
textAlignment: 文字在Label内的对其方式,类型为UITextAlignment枚举,在本项目需求中,要求文字在屏幕正中显示,对应的属性值为UITextAlignmentCenter。
font: 文字的字体和大小,类型为UIFont类,也就是本项目需求中要求的:“字体为粗体,字体大小26磅”,对应代码为:[UIFont boldSystemFontOfSize:26]。
textColor: 文字的颜色,类型为UIColor类,也就是本项目需求中要求的:“字体颜色红色”,对应代码为:[UIColor redColor]。
shadowColor: Label文字的阴影颜色,类型为UIColor类,也就是本项目需求中要求的:“有黑色阴影”,对应代码为:[UIColor blackColor]。
shadowOffset: Label文字阴影的偏移方向和偏移量,类型为CGSize,也就是本项目需求中要求的:“阴影光源为左上角,偏移1像素”,对应代码为:[CGSizeMake(1, 1)]。
让文字显示在屏幕正中心
要让文字显示在屏幕正中心,我们要优先考虑设置UILabel相关属性达到目的的方式,如果没有UILabel相关属性支持,那么我们就必须根据UILabel占的大小和屏幕大小来计算它应该摆放的坐标,从而实现让文字显示在屏幕正中心。在UILabel的文档中,没有发现有属性设置它的坐标,也没有设置对其的属性,这是不是代表UILabel不支持呢?不要忽略一个问题,iOS所用的编程语言是Objective-C,这个一个类似于C语言的很好的支持面向对象特性的语言,面向对象有个很重要的特性叫继承,同样对于UILabel类来说,它是有父类的,也就是UILabel父类支持的属性,UILabel都是支持的,在UILabel文档的首页,我们可以看到UILabel是从UIView继承的,所以我们可以链接到“UIView Class Reference”文档。
从文档中,我们可以找到2个重要属性,用来实现文字显示在屏幕正中:
frame: Label的位置和尺寸属性,类型为CGRect,在本项目需求中,要求显示在屏幕正中,就需要通过Label控件的frame属性的size值,结合主界面的尺寸,计算出x,y坐标值,以保证Label显示在屏幕正中。
autoresizingMask: 这个属性表示控件在其父容器尺寸发生变化时,它是怎么自动调整其尺寸或上下左右各个方向边距的。
支持屏幕旋转
iPhone程序默认不支持屏幕旋转,那么如何让界面支持旋转呢?在iOS Dev Center中,可以找到“View Controller Programming Guide for iOS”,在其中的“Custom View Controllers”一章中专门有一节“Managing a View Controller's Interface Orientation”,说明了如何让你的iOS界面支持设备旋转:
重写对应的View Controller的“shouldAutorotateToInterfaceOrientation:”方法,在方法中申明支持的方向。
配置对应的View Controller中的View的autoresizingMask属性,以适应因为界面旋转导致的布局变化。在本项目中,项目需求中要求设备在旋转也保证文字居中,利用这个属性,可以实现在界面旋转后,窗体宽度和高度发生变化时,UILabel还能继续居中。
项目开发
熟悉Xcode 4
经过前期的准备工作后,现在可以开始基于Xcode4进行实际的项目开发。对于Xcode4,在iOS Dev Center中,找到“Xcode 4 User Guide”,这是一个专门针对Xcode 4的说明和使用指南,非常详细。
在Xcode 4中,整合了原来专门用来编辑Mac或iOS项目界面的Interface Builder软件,“Xcode 4 User Guide”中专门有一章“Designing User Interfaces in Xcode”来讲述如何在Xcode 4中编辑界面。
创建新项目
启动Xcode4后,首先会有一个欢迎窗口,通过它,点击“Create a new Xcode project”,可以直接开始创建项目
当然也可以通过菜单或者快捷方式来开始创建新项目
选择新项目模板
为方便生成项目,Xcode4默认提供了几种项目模板:
Navigation-based Application: 该模板适用与需要界面导航的应用,基于该模板生成的应用程序,带一个导航,显示一个列表项
OpenGL ES Application: 该模板适用于基于OpenGL ES的应用程序,例如游戏类程序。基于该模板生成的应用程序,带一个用来输出OpenGL ES场景的视图和一个支持动画的视图
Splite View-based Application: 该模板适用于需要用到左右分栏视图的iPad程序,基于该模板生成的应用程序,提供了一个左右分栏的界面控件
Tab Bar Application: 该模板适用于适用采用标签页的应用程序,基于该模板生成的应用程序,默认带有标签页
Utility Application: 该模板适用与有一个主界面和一个信息页的应用,基于该模板生成的应用程序,主界面上有一个信息按钮,点击后,有一个翻转动画,切换到另一个信息界面
View-based Application: 该模板适用于单一界面的应用,基于该模板生成的应用程序,只有一个空白界面视图
Window-based Application: 该模板适用于空白的应用程序,基于该模板生成的应用程序,只有一个窗体,没有任何视图,需要手动添加
对于我们的Hello World项目来说,最适合的项目模板是“View-based Application”,我们只要基于它创建一个单一带有空白视图的应用,然后再将UILabel拖到上面就可以实现基本功能。
项目基本选项
点击下一步,进入“Choose options for your new project”界面,在这里,可以选择设置项目的基本选项,其中:
Product Name: 指产品名称,在这里项目中,我们直接命名为“Hello World”
Company Identifier: 公司标识符,一般命名规则为 “com.公司名”
Bundle Identifier: 指包标识符,用于唯一标识应用程序,默认会根据公司标识符和产品名来组合生成
Device Family: 指该应用支持的设备类型,共三个选项:iPhone、iPad、Universal(即iPhone、iPad通用)
Include Unite Tests: 是否包含单元测试代码模板,如果勾选,Xcode会帮助生成单元测试代码模板
选择存储路径
点击Next按钮后,进入选择文件存储路径界面,在这里,可以选择要存储项目的目录。
项目创建完成
点击“Create”按钮,项目创建完成,弹出项目窗口。
试运行项目
经过上面的步骤,我们已经基于模板创建了一个项目,在开始开发前,我们可以尝试先试运行一下项目,看看效果。点击Xcode左上角的“Run”按钮,Xcode即开始对项目进行编译,编译完成后,会弹出iPhone模拟器,在模拟器中运行项目,当然我们的项目现在运行起来还只能看到一个空白的界面。
点Xcode左上角的“Stop”按钮,停止运行项目。
编辑界面文件
一般创建一个新项目,在项目中会包含一个或多个界面文件,这些界面文件一般称之为“nib文件”,扩展名为nib或xib。或者通过向导创建一个新的View Controller的时候,Xcode会包含一个对应的nib文件,一个头文件和一个实现文件。在我们刚刚以View-based Application为模板创建的Hello World项目中,“Hello_WorldViewController.xib”就是主界面的nib文件。
在Xcode左侧选中“Hello_WorldViewController.xib”文件,并点击工具栏的“Hide or show the Navigator”和“Hide or show the Utilities ”按钮,隐藏左侧Navigator区域,显示Utility区域,这样我们就可以开始在Xcode 4中来编辑界面。
添加Label到界面中
从对象库中,找到我们所需要的Label控件对象,拖动到主界面中,即完成Label控件的添加
设置Label控件属性
选中新添加的Label控件,点击Inspector selector bar区域的“Show the Attributes inspector”按钮,切换到属性编辑界面,分别设置以下属性:
Text: 输入“Hello World”
Alignment: 选择居中对齐
Font: 选择“Helvetical Bold 26.0”
Text Color: 选择红色
Shadow: 选择黑色(Black Color)
Shadow Offset: Horizontal和Vertical的值分别输入1
设置Label控件的大小和位置
在上面的步骤中设置好Label的相关属性后,发现文字特别小,而且显示不完整,并非我们所选择的字体大小,这是由于UILabel有一个属性“adjustsFontSizeToFitWidth”,默认值是“YES”,如果这个属性的值为YES,并且Label的numberOfLines属性值是1,它会根据Label的宽度来自动调整字体大小,通过Xcode新添加的Label,默认宽度比较小,按照正常的26磅大小的字体,无法完整显示,所以就字体大小就被自动调整了,导致显示的和我们期望的不一样。解决这个问题很简单,就是我们重新设置一下Label的宽度,以让其可以完整显示文字。
选中新添加的Label控件,点击Inspector selector bar区域的“Show the Size inspector”按钮,切换到尺寸和位置设置界面,对宽度进行调整,这里我们给Label设置一个足够的宽度和高度:200x40,以保证字体不会被缩小。
接下来,就是要调整Label的位置,让它显示在屏幕的正中间。在Xcode中,用鼠标拖动Label,拖动过程中Xcode有辅助线来帮助定位,很容易就可以找到正中心的位置。当然也可以通过简单的计算得到Label如果要显示在正中心,坐标应该为:x = (屏幕宽度 - Label宽度) / 2 = (320 - 200) / 2 = 60; y = (屏幕高度 - 状态栏高度 - Label高度) / 2 = (480 - 20 - 40) / 2 = 210;
对修改过的xib文件保存,运行项目,看看效果
就这样,我们已经完成了第一步:在屏幕上显示文字,设置字体和字体大小,让文字显示在屏幕正中心。下一步,我们要让它支持旋转,并且旋转后,文字还是显示在屏幕正中。
支持设备旋转
前面我们已经学习了解过,要支持设备宣传,要做如下工作:
重写对应的View Controller的“shouldAutorotateToInterfaceOrientation:”方法,在方法中申明支持的方向。也就是首先要重写“Hello_WorldViewController.m”中的“shouldAutorotateToInterfaceOrientation:”方法
配置对应的View Controller中的View的autoresizingMask属性,以适应因为界面旋转导致的布局变化。也就是要设置好Label控件的autoresizingMask属性。
还是在界面文件中,选中Label,在尺寸和位置设置界面,通过点击Autosizing中的红色线条,设置Label对上下左右四个方向以及宽度和高度都自动调整,这样就可以保证在设备旋转后,界面的宽度和高度发生改变后,控件对上下左右四个方向的位置以及长度和宽度也会随着一起调整,由于已经设置了文字在Label内部是居中对齐的,就可以保证文字显示在界面居中的位置。
点击工具栏的“Hide or show the Navigator”和“Hide or show the Utilities ”按钮,显示左侧Navigator区域,隐藏Utility区域,在左侧Navigator区域,选中“Hello_WorldViewController.m”文件,找到“shouldAutorotateToInterfaceOrientation:”方法,对其进行重写,重写后代码如下
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
对所做的修改进行保存,然后运行项目,弹出模拟器,通过调用模拟器的设备旋转菜单,让iPhone模拟器变成横屏,你将看到文字会自动调整位置,还是显示在屏幕正中的位置。
至此,我们就实现了项目的全部需求。
项目总结
通过Hello World这个简单项目,我们学习了如何基于Xcode 4分析和开发iOS项目,学习了如何通过iOS Dev Center获取需要的资料。
源码下载:https://github.com/JimLiu/The-practice-of-iPhone-application-development/tree/master/Hello%20World
posted @ 2011-05-12 02:42 宝玉 阅读(13065) 评论(42) 编辑
2011年5月11日
iOS平台XML解析类库对比和安装说明
在iPhone开发中,XML的解析有很多选择,iOS SDK提供了NSXMLParser和libxml2两个类库,另外还有很多第三方类库可选,例如TBXML、TouchXML、KissXML、TinyXML和GDataXML。问题是应该选择哪一个呢?
解析 XML 通常有两种方式,DOM 和 SAX:
DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过遍历树结构可以检索任意XML节点,读取它的属性和值。而且通常情况下,可以借助XPath,直接查询XML节点。
SAX解析XML,是基于事件通知的模式,一边读取XML文档一边处理,不必等整个文档加载完之后才采取操作,当在读取解析过程中遇到需要处理的对象,会发出通知对其进行处理。
一般在iOS平台下,比较常用的XML解析类库有如下几种:
NSXMLParser,http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/Reference/Reference.html ,这是一个SAX方式解析XML的类库,默认包含在iOS SDK中,使用也比较简单。
libxml2,http://xmlsoft.org/,是一套默认包含在iOS SDK中的开源类库,它是基于C语言的API,所以使用起来可能不如NSXML方便。这套类库同时支持DOM和SAX解析,libxml2的SAX解析方式还是非常酷的,因为它可以边读取边解析,尤其是在从网上下载一个很大的XML文件,就可以一边下载一边对已经下载好的内容进行解析,极大的提高解析效率。
TBXML,http://www.tbxml.co.uk/TBXML/TBXML_Free.html,这是一套轻量级的DOM方式的XML解析类库,有很好的性能和低内存占用,不过它不对XML格式进行校验,不支持XPath,并且只支持解析,不支持对XML进行修改。
TouchXML,https://github.com/TouchCode/TouchXML,这也是一套DOM方式的XML解析类库,支持XPath,不支持XML的修改。
KissXML,http://code.google.com/p/kissxml/,这是一套基于TouchXML的XML解析类库,和TouchXML相比,支持了XML的修改。
TinyXML,http://www.grinninglizard.com/tinyxml/,这是一套小巧的基于C语言的DOM方式进行XML解析的类库,支持对XML的读取和修改,不直接支持XPath,需要借助另一个相关的类库TinyXPath才可以支持XPath。
GDataXML,http://code.google.com/p/gdata-objectivec-client/source/browse/trunk/Source/XMLSupport/,这是一套Google开发的DOM方式XML解析类库,支持读取和修改XML文档,支持XPath方式查询。
那么对于如何在项目中选择合适的XML解析类库呢?网上已经有人对这几款XML类库做过分析和对比,可参考《How To Choose The Best XML Parser for Your iPhone Project》http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project 一文,基本比较准确和客观,文中建议:
如果是读取很小的XML文档,性能基本上没有什么差别,不过从调用的方便性来说,建议使用TouchXML、KissXML或GDataXML
如果是需要读取和修改XML文档,建议使用KissXML或GDataXML
如果需要读取非常大的XML文档,则建议使用libxml2或TBXML
如果你不想去调用第三方类库,那么使用NSXML也可以
安装说明
GDataXML
1. 从http://code.google.com/p/gdata-objectivec-client/downloads/list下载“gdata-objective-c client library.”
2. 解压缩文件,找到Source\XMLSupport,并且将其中的GDataXMLNode.h 和 GDataXMLNode.m文件拖到项目中
3. 选中项目,选中“Build Settings”标签页
4. 将Build Settings页中,顶部的“Basic”标签切换到“All”
5. 找到“Paths\Header Search Paths”项,并添加“/usr/include/libxml2”到列表中
6. 找到“Linking\Other Linker Flags”项,并添加“-lxml2”到列表中
在需要调用GDataXML的代码文件头部,加入:
#import “GDataXMLNode.h”
TouchXML
1. 从https://github.com/TouchCode/TouchXML下载最新TouchXML源码
2. 解压后,将其中的Sources目录下的文件和目录都拖到项目中
3. 选中项目,选中“Build Settings”标签页
4. 将Build Settings页中,顶部的“Basic”标签切换到“All”
5. 找到“Paths\Header Search Paths”项,并添加“/usr/include/libxml2”到列表中
6. 找到“Linking\Other Linker Flags”项,并添加“-lxml2”到列表中
在需要调用TouchXML的代码文件头部,加入:
#import “TouchXML.h”
TBXML
1. 从http://www.tbxml.co.uk/TBXML/TBXML_Free.html下载最新TBXML源码
2. 解压后,将其中的TBXML.h, TBXML.m, NSDataAdditions.h和NSDataAddtions.m四个文件拖到项目中
3. 添加对libz.dylib类库的应用
在需要调用TBXML的代码文件头部,加入:
#import “TBXML.h”
使用说明
GDataXML
读取XML文件,并解析成为DOM文档对象示例:
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"xml"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (doc == nil) { return nil; }
NSLog(@"%@", doc.rootElement);
[doc release];
[xmlData release];
posted @ 2011-05-11 09:14 宝玉 阅读(2630) 评论(4) 编辑
2011年5月10日
ASIHTTPRequest类库简介和使用说明
官方网站: http://allseeing-i.com/ASIHTTPRequest/ 。可以从上面下载到最新源码,以及获取到相关的资料。
使用iOS SDK中的HTTP网络请求API,相当的复杂,调用很繁琐,ASIHTTPRequest就是一个对CFNetwork API进行了封装,并且使用起来非常简单的一套API,用Objective-C编写,可以很好的应用在Mac OS X系统和iOS平台的应用程序中。ASIHTTPRequest适用于基本的HTTP请求,和基于REST的服务之间的交互。
ASIHTTPRequest功能很强大,主要特色如下:
l 通过简单的接口,即可完成向服务端提交数据和从服务端获取数据的工作
l 下载的数据,可存储到内存中或直接存储到磁盘中
l 能上传本地文件到服务端
l 可以方便的访问和操作请求和返回的Http头信息
l 可以获取到上传或下载的进度信息,为应用程序提供更好的体验
l 支持上传或下载队列,并且可获取队列的进度信息
l 支持基本、摘要和NTLM身份认证,在同一会话中授权凭证会自动维持,并且可以存储在Keychain(Mac和iOS操作系统的密码管理系统)中
l 支持Cookie
l 当应用(iOS 4+)在后台运行时,请求可以继续运行
l 支持GZIP压缩数据
l 内置的ASIDownloadCache类,可以缓存请求返回的数据,这样即使没有网络也可以返回已经缓存的数据结果
l ASIWebPageRequest –可以下载完整的网页,包括包含的网页、样式表、脚本等资源文件,并显示在UIWebView /WebView中。任意大小的页面都可以无限期缓存,这样即使没有网络也可以离线浏览
l 支持客户端证书
l 支持通过代理发起Http请求
l 支持带宽限制。在iOS平台,可以根据当前网络情况来自动决定是否限制带宽,例如当使用WWAN(GPRS/Edge/3G)网络时限制,而当使用WIFI时不做任何限制
l 支持断点续传
l 支持同步和异步请求
2.1.1安装说明
如果想在iOS项目中使用ASIHTTPRequest,需要在项目中进行简单的配置,步骤如下:
1) 添加文件
往一个Xcode项目中添加第三方类库文件,有两种方式:
1. 第一种方式,在Finder中打开需要添加到文件或文件夹,在Xcode中打开要添加文件的项目,然后选中要添加的文件或文件夹,将它从Finder中拖到Xcode中,然后释放。在弹出的对话框中,如果文件已经拷贝到了项目文件目录中,则不需要选中“Copy items”的复选框;如果文件没有拷贝到项目文件目录,就需要选中“Copy items”的复选框,这样Xcode会自动把文件复制到项目文件目录下。如下图所示:
2. 第二种方式,在Xcode中,在要添加文件的分组下点右键,选中“Add Files to “My Project”…”菜单,在弹出的文件浏览对话框中选中要添加到文件或文件夹。如果要添加文件已经拷贝到了项目文件目录中,则不需要选中“Copy items”的复选框;如果文件没有拷贝到项目文件目录,就需要选中“Copy items”的复选框,这样Xcode会自动把文件复制到项目文件目录下。如下图所示:
根据上面的说明,添加ASIHTTPRequest相关文件到Xcode项目中,所需文件列表如下:
ASIHTTPRequestConfig.h
ASIHTTPRequestDelegate.h
ASIProgressDelegate.h
ASICacheDelegate.h
ASIHTTPRequest.h
ASIHTTPRequest.m
ASIDataCompressor.h
ASIDataCompressor.m
ASIDataDecompressor.h
ASIDataDecompressor.m
ASIFormDataRequest.h
ASIInputStream.h
ASIInputStream.m
ASIFormDataRequest.m
ASINetworkQueue.h
ASINetworkQueue.m
ASIDownloadCache.h
ASIDownloadCache.m
ASIAuthenticationDialog.h
ASIAuthenticationDialog.m
Reachability.h (在源码的 External/Reachability 目录下)
Reachability.m (在源码的 External/Reachability 目录下)
2) 链接相关类库
1. 选中项目
2. 选中目标
3. 跳转到“Build Phases”标签
4. 展开“Link Binary With Libraries”分组
5. 点击“+”添加类库
如下图所示:
6. 从列表中选择CFNetwork.framework,然后点击“Add”按钮。
7. 按照上一步相同的方法添加:SystemConfiguration.framework, MobileCoreServices.framework,CoreGraphics.framework和libz.1.2.3.dylib这几个类库。
8. 添加完后,可以将添加好的一起类库拖到Xcode项目的Frameworks目录下
2.1.2使用说明
ASIHTTPRequest有很多功能,所有功能说明都可以在其官方网站的相关文档中查到,限于篇幅,本章仅简单介绍一下如何使用ASIHTTPRequest来进行同步Http请求和异步Http请求。在后面的章节中,我们还会用到它的一些其他功能。
在使用ASIHTTPRequest之前,请确认已经正确安装,然后在需要应用它的代码文件头部,加入:
#import “ASIHTTPRequest.h”
这样就可以在代码中使用ASIHTTPRequest相关的类。
创建一个同步请求
这是ASIHTTPRequest最简单的一种使用模式,发送startSynchronous消息后即开始在同一线程中执行HTTP请求,线程将一直等待直到请求结束(请求成功或者失败)。通过检查error属性可以判断请求是否成功或者有错误发生。
要获取返回的文本信息,调用responseString方法。如果下载的是二进制文件,例如图片、MP3,则调用responseData方法,可以得到一个NSData对象。
- (IBAction)grabURL:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
}
}
一般情况下,应该优先使用异步请求代替同步请求,当在主线程中使用ASIHTTPRequest同步请求,应用程序的界面会锁定,无法进行任何操作,直到请求完成。
创建一个异步请求
上例中的同步请求,如果换成异步方式来调用,请求是在后台线程中运行,当请求执行完后再通知调用的线程。这样不会导致主线程进行网络请求时,界面被锁定等情况。
- (IBAction)grabURLInBackground:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// 当以文本形式读取返回内容时用这个方法
NSString *responseString = [request responseString];
// 当以二进制形式读取返回内容时用这个方法
NSData *responseData = [request responseData];
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
}
发表评论
-
SOCK_STREAM和SOCK_DGRAM
2015-07-23 20:08 1640sock_stream 是有保障的(即能保证数据正确传送到 ... -
SOCKET bind INADDR_LOOPBACK和INADDR_ANY的区别
2015-07-23 19:49 2057今天写程序时候,服务器端启动了,然后客户端总是连接不上,con ... -
htons()
2015-07-23 19:26 580在C/C++写网络程序的时候,往往会遇到字节的网络顺序和主机顺 ... -
使用symbolicatecrash分析crash文件
2015-03-10 11:32 1179原文 http://www.cnblogs.com/ning ... -
程序设计中的计算复用(Computational Reuse)
2015-02-10 10:18 662从斐波那契数列说起 ... -
didReceiveMemoryWarning
2015-02-09 16:11 541IPhone下每个app可用的内存是被限制的,如果一个app使 ... -
iOS开发中怎么响应内存警告
2015-02-09 16:08 654好的应用应该在系统内存警告情况下释放一些可以重新创建的资源。在 ... -
ASIHTTPRequest多次重复请求的问题
2014-12-17 14:34 641在一个车票订购的项目中,点击一次订购,却生成了2次订单,通过抓 ... -
从 CloudKit 看 BaaS 服务的趋势
2014-09-26 11:51 726从 6 月份 WWDC 苹果发布 ... -
ios编程--AVCapture编程理解
2014-09-26 11:03 9230、媒体采集的几个东西。这里所需要明白的是,在这个流程中,这里 ... -
NSURLProtocol
2014-09-25 10:42 8191、http://nshipster.com/nsurlpro ... -
关于iOS8的extension插件
2014-09-25 10:41 1279关于iOS8的extension插件,有兴趣的同学可以参考一下 ... -
【转】ios app在itunesConnect里面的几种状态
2014-08-05 10:34 1145Waiting for Upload (Yellow) Ap ... -
[转]iOS Dev (45) iOS图标与切片处理工具Prepo
2014-02-07 17:02 1034iOS Dev (45) iOS图标与切片处理工具Prepo ... -
phoneGap开发IOS,JS调用IOS方法/phoneGap插件开发
2014-01-13 17:49 1244前沿 废话不说phoneGap是什么不多介绍,官方网站: h ... -
如何在IOS平台下搭建PhoneGap开发环境(PhoneGap2.5)
2014-01-13 15:23 747由于在下最近在做基于HTML5的跨平台移植,搭建环境的时候着实 ... -
xcode 4 制作静态库详解
2013-12-20 18:27 533最近在做Apple的IOS开发,有开发静态库的需求,本身IOS ... -
【翻译】ios教程-创建静态库
2013-12-20 18:19 3108作者:shede333 主页:htt ... -
封装自己的控件库:iPhone静态库的应用
2013-12-20 17:03 581由于iPhone 控件的极度匮乏和自定义组件在重用上的限制,在 ... -
iphone:使用NSFileManager取得目录下所有文件(遍历所有文件)
2013-11-18 17:56 869From:http://note.sdo.com/u/xiao ...
相关推荐
标题 "第一个app——iPhone应用程序:“Say Hello”" 暗示了我们将探讨的是一个初学者级别的iOS应用开发教程,特别是如何创建一个简单的“Hello, World!”应用程序。这个过程通常使用苹果的集成开发环境(IDE)Xcode...
【描述】:“ios源码Last.fm的官方iPhone应用程序:支持500多万首音乐.zip”描述了这个压缩包的内容,即Last.fm的iOS应用源代码,它能够接入并播放海量音乐。这表明源代码包含了处理音乐搜索、播放、推荐、用户个性...
写一个iPhone应用程序,要求可以输入名字,点击按钮后,会显示一段文字向输入的名字打招呼,例如输入“宝玉”,显示“你好,宝玉!”这是一个很简单的应用程序,包含一个文本输入框,一个文本显示框,一个按钮。输入...
总之,《iPhone应用程序编程指南》中文版会提供一个全面的教程,覆盖了从基本概念到高级技术的所有方面,让读者能够构建功能丰富的、用户体验优秀的iOS应用程序。通过学习本书,开发者不仅可以掌握iOS开发的基本技能...
《iPhone高级编程:使用Mono Touch和.NET/C#》从基本的概念入手,全面地介绍了基于monotouch使用C#/.net进行iphone应用程序开发。从monotouch和.net开发环境到objective-c和c#开发语言,从基于monotouch进行iphone...
#### 二、iPhone SDK与本地应用程序 - **本地应用程序的概念**:本地应用程序是指那些直接在设备上运行的应用程序,与Web应用程序不同,它们拥有更多的权限去访问设备的各种硬件和软件特性。 - **本地应用程序的特点...
本篇文章将详细讲解如何在iPhone上开发第一个"Hello, World!"程序,帮助你快速入门iOS应用开发。 首先,我们需要安装Xcode。Xcode是Apple官方的集成开发环境(IDE),它包含了编写、调试和发布iOS应用程序所需的...
在本节“ios(iPhone)应用程序开发入门视频教程:第1讲HelloWorld概述”中,我们将探讨iOS应用开发的基础知识,特别关注初学者如何通过HelloWorld项目开启编程之旅。这节课是整个“iOS(iPhone)应用程序开发入门视频...
iPhone应用程序开发指南是iOS开发领域的专业参考书,为开发者提供在苹果的iOS平台上设计、开发和优化应用程序所需的工具和技术。在开发过程中,了解和掌握iPhone开发基础教程同样重要。本书及所提及的其他参考资料在...
软件创富密码:iPhone应用程序开发攻略之深入浅出Objective-C2.0分卷二 因为容量大,所以分两个卷下载。整体与书籍一致,没有缺页。 《软件创富密码:iPhone应用程序开发攻略之深入浅出Objective-C2.0(适用于ios4)》...
本章将介绍如何创建一个简单的 iPhone 应用程序,介绍基础的技术,不要求读者现在就掌握这些技术,但这些技术将有助于读者对基础开发过程有初步了解,窥视一下开发 iPhone 程序的神秘色彩,打破对开发 iPhone 程序的...
iPhone 开发的第一个程序 HelloWorld 是一个自动计算打折后价格的应用程序。该程序的开发过程中,我们将学习到如何使用 Xcode 和 Interface Builder 来设计用户界面、编写代码来实现业务逻辑。 知识点一:Xcode 和 ...