項目需求
寫一個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函數:
該函數將會創建一個UIApplicaion類的實例。同時它會搜索應用程序的Info.plist屬性列表文件。 Info.plist文件是一部字典,它主要包含諸如應用程序名稱、圖標這樣的信息,它也包含應用程序對象應該加載的nib 文件(雖然該文件的擴展名為“xib”,但是我們習慣稱之為“nib 文件”)的名稱。Nib文件主要有用戶界面的信息。本項目的Info.plist文件具有下面的內容:
這表明應用程序啟動時將會加載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)的頭文件:
然后在頭文件大括號之間添加下面的代碼,這是為了向應用程序委托添加一個實例變量:
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文件中界面元素之間的連接,是非常重要的。

文件擁有者(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開發來說,都是會經常用到的知識。