在處使用對的所有權進行了釋放所以此時對象(3)?[note1release]note1,note148的應該為retaincount1。
在處再次調用然後輸出對象的值此時應(4)?[note1release],note1retaincount,該為對嗎0,?
下麵就運行程序來驗證一下我們前麵的猜測是否正確如圖所示,3?9。
圖的值3-9notelretaincount在圖中可以看到我們前三條猜測都被證實非常正確但在第四條猜測的地方卻出,,現了一條警告向一個已經被釋放的對象發送了消息:retainCount。
原來已經被釋放了所以我們無法再向對象發送消息來獲note1,note1retainCount取它的引用計數值了我們認為這條警告是一個好消息當對象的引用計數值為時。:0,它竟然被釋放得這麼及時。
5使用自動釋放池.
那麼當一個對象自動釋放時情況是怎樣的呢下麵就讓對象自動釋放來觀,?note2察一下為了方便觀察刪除剛才用於對對象內存進行操作的代碼修改。,note1,Note.m文件如下:
代碼文件3.17Note.m#import#import\"NoteClassh\"intmainintargcconstchar*argvNSAutoreleasePool*pool=NSAutoreleasePoolallocinitinsertcodehereNSLog@\"alloc\"NoteClass*note1=NoteClassallocinitWithDate@\"600\"andContent@\"Running\"NoteClassnoteNoteClassallocinitWithDate\"\"*2=@700?
autoreleaseNSLog\"note?sretaincount%d\"noteretainCount@22?
49note1releasenote2releaseNSLog@\"afterpooldrain\"pooldrainNSLog@\"note2?sretaincount%d\"note2retainCountreturn0在處將對象聲明為了運行程序查看結果如圖所示?note2autorelease。,3?10。
圖使用時的3-10autorelease在運行結果中可以看到開始時輸出對象的值為當自動釋放,note2retaincount1。
池被釋放被調用再次輸出對象的值時可以發現向一,[pooldrain],note2retaincount,“個已經被釋放的對象發送了消息這條提示又出現了對象在自動retainCount”———note2釋放池銷毀後也隨著被銷毀了,。
圖簡單形象地描述了中內存管理的流程3-11Objective-C。
圖內存管理流程3-116其他注意事項.
以上便是關於內存管理大體的方法下麵來看一些關於內存管理的細微之處與實際,
使用時的小技巧:
50各種容器類如等會將引入的元素的引用計數(1)NSArray、NSDictionary、NSSet,值加來獲得所有權而在元素被移除或者整個容器對象被釋放時釋放容器內元素的1,,所有權。
開發中不支持垃圾回收機製(2)iPhone。
對象最好在需要時再創建從而節省內存開銷(3),。
絕不可以發送消息給對象(4)releaseautorelease。
在需要頻繁分配與釋放內存的地方如循環可以創建自己的(5)(for),NSAutoRe-leasePool。
353內存管理規則..
下麵總結一下內存管理的主要規則在今後的開發中遵循這些規則會使我們少出,,很多錯誤。
獲得所有權的函數要和釋放所有權的函數一一對應(1)。
在對象的函數中釋放對象所擁有的變量並調用父類的方法(2)deallocdealloc。
永遠不要直接調用來釋放對象隻使用引用計數來完成對象的釋放(3)dealloc,。
大道至簡我們應首先牢固掌握這三條這樣在今後的開發過程中程序在內存方,,,,麵應該就會平安無事了。
36小結.
本章介紹了關於的一些基本知識包括基本語法類的聲明與實現以及Objective-C,、關於內存的管理。
關於基本語法為了可以輕鬆快速地理解我們演示了一個簡單的例子並結合,,,語言進行了對比講解C++。
之後著重介紹了在中如何聲明並實現一個類在中基本,Objective-C。Objective-C,上任何一個類都要繼承才可以具有作為一個類的基本行為能力NSObject,Objective-C。
然後具體講解了如何聲明實現一個類如何初始化對象以及如何對屬性進行操作、,,。
本章的最後對中的內存管理進行了講解其中詳細介紹了常用於內存Objective-C。
管理的幾個函數等之後通過實例講解了如何手動管理內存與使用:alloc、retain、release;自動釋放池管理內存最後在小節列出了內存管理中最為重要的三條規則需要;,3.5.3,在今後的開發中牢記!
51第章幾個重要的類4Cocoa本章內容■NSObject與
■NSStringNSMutableString與
■NSArrayNSMutableArray■NSDictionary框架包含多個類本章將會為你介紹其中一些重要而且常用的類Foundation100,,比如等完成本章學習後你就完全可以在今後的開發過程中通過NSString、NSArray。,來繼續進行學習並解決開發中的問題了iPhoneSDK。
在框架中所包含的類大體可按以下類別進行劃分Foundation,:用於基本編程類型和操作的類包括字符串數組字典數字異常處理等(1),、、、、。
用於內核環境實體和服務的類包括任務運行循環計時器線程等(2),、、、。
對象管理類包括內存管理遠程調用存檔等(3),、、。
文件係統和功能的類包括處理文件查找等(4)I\/O,URL、。
其他功能類別包括格式化數據使用係統日期和時間等(5),、。
??
???????????????????????????
?框架不會涉及到界麵的操作,關於界?
?Foundation?
?麵操作的部分都在框架中,但在?
?ApplicationiPhone?
開發時,將由替代框架來進行界麵?UIKitApplication?
?設計,正是本書將要在後麵的開發章節?
?????????????????????????
?UIKitiPhone?
詳細介紹的內容?。?
這一章我們就來學習一下框架中比較重要而且常用的幾個類,Foundation。
4.1NSObject是絕大多數類的基類通過各類繼承了運行時NSObjectCocoa。NSObject,Cocoa係統的基本接口以及作為一個類的基本行為能力,Objective-C。
當需要自己創建一個類時也要直接或間接地繼承類隻有這樣所創建,NSObject,,的類才能具有作為一個類所需要的基本行為能力類的子類從Objective-C。NSObject52所繼承的方法中最為常用的是用來初始化對象的而且這些方法大多需要被子NSObject,類重寫下麵就來總結幾個最為常用的方法見表,4-1。
表4-1NSObject的常用方法方法介紹示例該方法是一個類方法它負責創建並返回調,NSString*strDem=+(id)alloc用該方法的類的一個實例[NSStringalloc];該方法負責對對象進行初始化一般會以,
類名的形式調用在對象被創[[alloc]init],建後馬上進行初始化。
在類中該方法隻是返回NSString*strDem=-(id)initNSObject,“self”,並未進行任何初始化工作子類如果要使用[[NSStringalloc]init];,
這個方法進行對象的初始化工作的話需要,
進行重寫該方法負責釋放對象的內存並做一些在釋,
放對象內存前需要處理的工作如釋放某些,
成員變量的所有權這就需要繼承自。
的子類重寫適合於自己的NSObjectdealloc-(void)dealloc方法。
在上一章內存管理章節中提到過對象絕不,
可以直接調用該方法當對象的保留計數器,
的值為時該方法自動被調用0,表中的方法是在自定義一個類時最為重要與常用的個方法在今後的學習與4?14,開發中你將會發現它們非常常見下一節將進行中另一個非常重要與常用的,。,Cocoa類類的學習———NSString。
4.2NSString在中是用來存儲和處理字符串的類它提供了多種方法讓開發者Cocoa,NSString,創建字符串和獲取其中的數據但是類的對象一旦被創建便無法再對其中。NSString,的內容進行修改如果要使用可變的字符串需要創建類的對象我。,NSMutableString,們將在小節對的相關內容進行講解4.2.4NSMutableString。
下麵再來回顧一下前麵的程序同時增加一個新功能查看是否有重複的記,Note,:錄如果有重複記錄則程序不會重複輸出相同記錄沒有重複的話程序便會將所有記,,;,錄正常顯示。
53421修改Note..
首先打開在菜單欄下選擇如圖所示Xcode,File→Open,4-1。
圖打開4-1“Note”選擇菜單項後則彈出如圖所示的窗口選擇的正確路徑然Open,4-2Open,Note,後打開文件就會出現的窗口了Note.xcodeproj,NoteXcode。
圖用來打開項目的窗口4-2Open在中將文件修改如下Xcode,Note.m:代碼文件4.1Note.m#import#import\"NoteClassh\"intmainintargcconstchar*argv54NSAutoreleasePool*pool=NSAutoreleasePoolallocinitinsertcodehere創建字符串NSStringnoteDateNSStringallocù*1=úinitWithString\"\"ú@600úNSStringnoteContentNSStringalloc*1=úinitWithString\"Running\"ú?
@úNSStringnoteDateNSStringalloc*2=úinitWithString\"\"?
@700創建記錄NoteClassnoteNoteClassalloc*1=initWithDatenoteDate1
andContentnoteContent1
NoteClassnoteNoteClassalloc*2=initWithDatenoteDate2
NoteClassnoteNoteClassalloc*3=initWithDatenoteDate1
andContentnoteContent1
NSLog@\"note1\"note1showNote檢查與是否是相同記錄note1note2ifnotedateisEqualToStringnotedateù12ú&¬econtentisEqualToStringnotecontentú12úNSLog\"noteissamewithnote\"@21úelseúú
NSLog\"noteandnoteisdifferentnote\"ú@212noteshowNoteú2úú
ú檢查note與note是否是相同記錄13ú?
ifnotedateisEqualToStringnotedateú13ú&¬econtentisEqualToStringnotecontent13úNSLog\"noteissamewithnote\"ú@31úelseúNSLog\"noteandnoteisdifferentnote\"ú@313únoteshowNoteú3ú?
55noteDaterelease1
noteContentrelease1
noteDaterelease2
note1releasenote2releasenote3releasepooldrainreturn0運行程序在控製台中將出現如圖所示的運行結果,4-3。
圖運行結果4-3422字符串的創建..
下麵將通過分析在程序中所做的修改來對關於創建對象的知識內Note,NSString容進行講解。
在代碼的處首先創建並初始化了個的對象並在後麵使用這4.1?,3NSString,3個對象來初始化類的對象NoteClass:代碼在文件中創建的對象4.2Note.mNSStringNSString*note1Date=NSStringallocinitWithString@\"600\"NSString*note1Content=NSStringallocinitWithString@\"Running\"56NSString*note2Date=NSStringallocinitWithString@\"700\"這條初始化語句均通過調用的實例方法來初始化3NSStringinitWithString:NS-對象方法的聲明如下String。:-idinitWithStringNSStringaString():(*)該方法通過複製另一個該類的對象來對調用該方法的對象進行初始化aString,。
??
???????????????????????????
?我們可以通過的形式來創建一個字符?
?@\"aText\"?
?串常量。實際上,一個形式的字符串常量,?
?????????????????????????
?@\"aText\"?
就是一個類的對象?。?
NSString除了上麵那個初始化方法外還提供了多種初始化方法以方便根據具體NSString,,情況用不同形式初始化對象下麵就用一個的類方法來實現相同功能更改。NSString,代碼如下:
代碼使用:方法初始化對象4.3stringWithStringNSStringNSString*note1Date=[[NSStringalloc]initWithString:@\"6:00\"];NSString*note1Content=[[NSStringalloc]initWithString:@\"Running\"];NSString*note2Date=[[NSStringalloc]initWithString:@\"7:00\"];NSStringnoteDateNSStringstringWithString\"\"*1=[:@6:00];NSStringnoteContentNSStringstringWithString\"Running\"*1=[:@];NSStringnoteDateNSStringstringWithString\"\"*2=[:@7:00];[note1Daterelease];[note1Contentrelease];[note2Daterelease];運行程序可以得到與前麵的例子同樣的結果在這裏將的初始化方法,。,NSString由實例方法換成了類方法initWithString:stringWithString:。
同時注意這裏取消了用於釋放與三個,note1Date、note1Contentnote2DateNS-對象所有權的語句正如在上一章內存管理中所講的在這裏沒有使用為這String。,alloc三個對象分配指定的內存它們被放在了自動釋放池當中所以不可以手動對其所有權,,進行釋放。
下麵我們就來總結一下幾個常用的的初始化方法見表,NSString,4-2。
57表4-2NSString常用的初始化方法方法介紹示例這兩個方法一個是類方法一NSString*strClass=[NSString(),+idstring個是實例方法使用它們均會,string];將對象初始化為一個不包含NSString*strInstance=[[NS--(id)init任何字符的空字符串Stringalloc]init];+(id)stringWithString:(NS-NSString*note1Date=[NSString這兩個方法將通過複製另一String*)aString;stringWithString:@\"6:00\"];個該類的對象來對對aString,[[象進行初始化NSString*note1Date=NS--(id)initWithString:Stringalloc](NSString*)aString;initWithString:@\"6:00\"];這兩個方法均提供了一個格NSString*strDate=[NSString+(id)stringWithFormat:式化的字符串模板並format,stringWithFormat:@\"%d:00\",(NSString*)format,...;通過用後麵的參數替換模板6];中的格式轉換符形成format,NSString*strDate=[[NSString-(id)initWithFormat:需要的格式化字符串來初始alloc]initWithFormat:@\"%d:(NSString*)format...;化對象00\",6];這三組方法會在今後的開發過程中經常遇到,。
423字符串的使用..
通過上一小節我們掌握了如何創建一個類的對象這一小節就來學習一,NSString,下如何對對象進行操作NSString。
類的對象是不可變的也就是說的對象一旦創建就不可以再NSString,,NSString,更改它的值所以創建之後可以對它進行的操作並不多。,。
為實現檢測重複記錄這一功能在代碼的處我們添加了如下語句,4.1?,:代碼檢查相同字符串4.4ifnote1dateisEqualToStringnote2date&¬e1contentisEqualToStringnote2contentNSLog@\"note2issamewithnote1\"elseNSLog@\"note2andnote1isdifferentnote2\"note2showNote其中調用了類的實例方法[note1.dateisEqualToString:note2.date]NSString58來判斷與是-(BOOL)isEqualToString:(NSString*)aString,note1.datenote2.date否相同如果兩者相同則該方法返回否則返回,,YES,NO。
??
???????????????????????????
?如果要判斷兩個字符串是否相同,我們需要使用?
??
?:方法,而不可以簡單地用“”,因?
i?sEqualToString==?
?為用“”判斷的是兩個指針所指內存地址是否相?
?????????????????????????
?==?
等而不是兩個字符串的內容是否相等?,。?
進行判斷後程序就會根據判斷的結果進行相應輸出結果如上麵的圖所示,,4-3。
以上就是的方法的使用下麵再來總結一下對一個創建NSStringisEqualToString:,好的對象進行操作的幾種常用方法見表NSString,4?3。
表4-3NSString常用方法方法介紹示例返回字符串中字符的UnicodeintnumOfStr=-(NSUInteger)length個數[note1Datelength];獲取在字符串給定位置-(unichar)characterAtIndex:indexNSLog(@\"%c\",[note1Date處的一個字符(NSUInteger)indexcharacterAtIndex:2]);以一個字符串形式返回調C
用該方法的對象返回的字符printf(\"%s\",[note1-(constchar*)UTF8String,串以結尾DateUTF8String]);null該方法將字符串追加aString-(NSString*)在調用該方法的對NSString*newNote1Date=NSStringstringByAppendingString:象後麵形成一個新的[note1DatestringByAppendingString:NS-(NSString*)aString對象並返回該對象@\"o?Clock\"];String,返回一個調用該方法的對象的子字符串在該子字符串中-(NSString*),NSString包含調用方法的對象從第一substringToIndex:*newNote1Date=[note1Date個字符一直到包括(NSUInteger)anIndexanIndex(substringToIndex:1];位置中間的所有字符anIndex)通過將調用該方法的字符串對象中的小寫字母全部替換NSString-(NSString*)uppercaseString為大寫字母形成新字符串*upNote1Content=[note1Content,,並返回該字符串uppercaseString];將調用該方法的對象轉化為FloatmyPIE=[@\"3.14\"floatVa--(float)floatValue浮點類型的值lue];594.2.4可變字符串剛剛創建的字符串是不可變的但是如果我寫錯了記錄怎麼辦難道我每寫錯記錄,?
中的一個字符就要重新將整條記錄再寫一遍嗎這當然不合適中的?,CocoaNSMutable-類便是的可變版本同時它也是的子類除了繼承StringNSString,NSString。NSString的所有屬性與方法外還提供了許多可以用來對字符串進行修改的方,NSMutableString法
。
下麵我們就來把程序修改一下今天早上時間匆忙不僅沒有及時記錄Note:,7:00時做的事情連時做的事情也記錯了現在我要修改一下之前的記錄,6:00,。
代碼文件4.5Note.m#import#import\"NoteClassh\"intmainintargcconstchar*argvNSAutoreleasePool*pool=NSAutoreleasePoolallocinitinsertcodehere創建可變字符串NSMutableStringnote1Date=NSMutableStringalloc*
initWithString@\"600\"?
NSMutableStringnote1Content=NSMutableStringalloc*
initWithString@\"Running\"NSMutableStringnote2Date=NSMutableStringalloc*
initWithString@\"700\"創建記錄NoteClass*note1=NoteClassallocinitWithDatenote1DateandContentnote1ContentNoteClass*note2=NoteClassallocinitWithDatenote2DateNoteClass*note3=NoteClassallocinitWithDatenote1DateandContentnote1Content輸出note1NSLog@\"note1\"note1showNote60修改記錄中的事件內容note1noteContentsetString\"Reading\"1@?
輸出修改內容後的note1NSLog@\"note1\"note1showNote檢查與是否是相同記錄note1note2ifnote1dateisEqualToStringnote2date&¬e1contentisEqualToStringnote2contentNSLog@\"note2issamewithnote1\"elseNSLog@\"note2andnote1isdifferentnote2\"note2showNote檢查與是否是相同記錄note1note3ifnote1dateisEqualToStringnote3date&¬e1contentisEqualToStringnote3contentNSLog@\"note3issamewithnote1\"elseNSLog@\"note3andnote1isdifferentnote3\"note3showNotenote1Datereleasenote1Contentreleasenote2Datereleasenote1releasenote2releasenote3releasepooldrainreturn0運行程序將會出現如圖所示的輸出結果,4-4。
61圖可修改記錄的運行結果4-4“Note”下麵來分析一下上麵的程序。
是的子類繼承了的一切方法所以在處我NSMutableStringNSString,NSString,?
們使用繼承自中的方法對和NSStringinitWithString:note1Date、note1Content對象進行初始化note2Date。
在處對錯誤的記錄進行了修改?note1Content:[note1ContentsetString:@\"Reading\"];上麵這行代碼使用了的NSMutableString-(void)setString:(NSString*)aString方法使用這個方法可以將調用該方法的對象的內容替換為,,NSMutableStringaString。
在本例中就將先前記錄的事件信息替換成了,“Running”“Reading”。
下麵我們再來看一下類中一些常用的方法見表,NSMutableString,4?4。
表4-4NSMutableString常用方法方法介紹示例該方法負責創建並返回一個可以容納個字符的空capacity字符串來初始化NSMutable-NSMutableString+(id)stringWithCapacity:對象隻是起String。capacity*note1Date=[NSMutableString(NSUInteger)capacity優化存儲的作用它並不會真,stringWithCapacity:5];正限製對象NSMutableString所能容納字符串的長度將一個新字符串添加aString-(void)appendString:(NS-到調用該方法對象的後麵從[note1DateappendString:,
String*)aString而改變該對象@\"o?Clock\"];在原對象的-(void)insertString:(NS-NSMutableString位置添加字符串[[note1ContentinsertString:String*)aStringatIndex:anIndex,來改變該對象@\"Iam\"]atIndex:0];(NSUInteger)anIndexaString62表中介紹的三個方法的作用分別為使用類方法創建一個規定了大小的4?4:對象向對象末尾增加一個字符串來改變原有對象NSMutableString,NSMutableString,以及向對象的指定位置添加一個字符串來改變原有對象除此之外NSMutableString。,的其他方法還可以完成刪除指定位置字符向對象末尾增加一個格式NSMutableString、化字符串來改變原有對象等功能關於這些方法的詳細使用你可以通過查閱。,iPhone幫助文檔來進行了解和學習SDK。
4.3NSArray假設這一天我做了件事我當然可以用個語句逐個輸出它們但通100,100NSLog,常我希望可以將這些語句組織得更有條理而不是像個語句這樣冗餘和雜,100NSLog亂無章。
提供了許多集合類來對數據進行組織就是進行開發時較為常用的Cocoa,NSArray一個它實現了數組的功能但使用時有兩點需要注意。,NSArray:隻能存儲的對象而不能存儲像這些基本的數(1)NSArrayObjective-C,int、float據類型但由於對兼容所以在程序中仍然可以使用的。Objective-CC,Objective-C,C數組來存儲普通類型的數據。
??
???????????????????????????
?不能存儲基本類型的數據,可以用?
?NSArray?
?類來將、等各種基本數據類型進?
?NSNumberintfloat?
?行封裝從而使它們“變為”標準的對象,這樣便?
?????????????????????????
?Cocoa?
可以將需要的數據存儲進了?。?
NSArray一旦創建便不可以再對它進行更改了如果要進行對數組的增刪改(2)NSArray,、、等操作的話需要使用的子類來創建對象這部分內容將會,NSArrayNSMutableArray,在後麵進行講解。
提供了大量方便的方法來創建對象和組織其中的元素下麵就使用NSArray,NSAr-來組織一下rayNote。
431用數組組織多個記錄..
程序可以檢測出相同的記錄並避免重複輸出但它們真的是相同的記錄嗎如Note,?
果不放心就通過這一節做一下驗證先將各條記錄全部輸出來查看一下之後再進行檢,:,測重複記錄的操作。
修改文件如下Note.m:63代碼文件4.6Note.m#import#import\"NoteClassh\"intmainintargcconstchar*argvNSAutoreleasePool*pool=NSAutoreleasePoolallocinitinsertcodehere創建可變字符串NSMutableString*note1Date=NSMutableStringallocinitWithString@\"600\"NSMutableString*note1Content=NSMutableStringallocinitWithString@\"Running\"NSMutableString*note2Date=NSMutableStringallocinitWithString@\"700\"創建記錄NoteClass*note1=NoteClassallocinitWithDatenote1DateandContentnote1ContentNoteClass*note2=NoteClassallocinitWithDatenote2DateNoteClass*note3=NoteClassallocinitWithDatenote1DateandContentnote1ContentNSArraynoteArrayNSArrayalloc*=initWithObjectsnote1
notenotenil23forintiinoteArraycounti=0<++noteArrayobjectAtIndexishowNoteNSLog@\"\"NSLog@\"testsamenote\"輸出note1NSLog@\"note1\"64note1showNote修改記錄中的事件內容note1note1ContentsetString@\"Reading\"輸出修改內容後的note1NSLog@\"note1\"note1showNote檢查與是否是相同記錄note1note2ifnote1dateisEqualToStringnote2date&¬e1contentisEqualToStringnote2contentNSLog@\"note2issamewithnote1\"elseNSLog@\"note2andnote1isdifferentnote2\"note2showNote檢查與是否是相同記錄note1note3ifnote1dateisEqualToStringnote3date&¬e1contentisEqualToStringnote3contentNSLog@\"note3issamewithnote1\"elseNSLog@\"note3andnote1isdifferentnote3\"note3showNotenote1Datereleasenote1Contentreleasenote2Datereleasenote1releasenote2releasenote3releasepooldrainreturn0@end65運行程序將會得到與以前一樣的效果如圖所示,,4-5。
圖使用後的運行結果4-5NSArray下麵就來具體分析一下修改後的程序並學習的相關知識,NSArray。
4.3.2NSArray對象的創建代碼中首先創建了一個的對象並用前麵的三條記錄來初4.6NSArraynoteArray,始化它:NSArray*noteArray=[[NSArrayalloc]initWithObjects:note1,note2,可以看到在這一句代碼中我們使用了的方法note3,nil]。,,NSArrayinitWithObjects:來對進行了初始化該方法聲明如下noteArray,:-(id)initWithObjects:(id)firstObj,…該方法的參數為不定參數它使用一組對象來初始化對象這組對象可以,NSArray,是任意多個也以是不同類型的比如你可以將類型的對象與類型,,NSStringNSNumber的對象同時包含在一個對象中這不會有任何問題最後一個參數必須是NSArray,。nil,以此表示初始化參數列表的結束。
這樣就用一組對象初始化好了需要的對象此外另外一個較為常用的初NSArray。,始化方法是通過另一個對象作為參數來進行初始化工作NSArray:-(id)initWithArray:該方法通過對象中的元素對新對象進行初始化比如(NSArray*)anArray。anArray,在初始化好了的基礎上可以這樣初始化另外一個對象noteArray,NSArray:NSArray*myNoteArray=[[NSArrayalloc]initWithArray:noteArray]。
4.3.3獲取NSArray指定索引處的元素創建好的對象後使用下麵語句將其中所包含的記錄進行一一NSArraynoteArray,輸出:
forinti=0i 然後由可以獲得中指定索引值為的(2)[[noteArrayobjectAtIndex:i]noteArrayi元素在本例中便是類的對象也就是前麵創建的與,NoteClass,note1、note2note3。 最後通過調用的顯示消息的方法將三條記錄進行了一(3),NoteClassshowNote,一輸出。 在這個循環中我們用到了獲取中元素個數的方法for,NSArray-(NSUInteger)和獲取指定索引位置對象的方法下麵count-(id)objectAtIndex:(NSUInteger)index。,我們在表中再列舉幾條的常用方法4-5NSArray。 表4-5NSArray常用方法方法介紹示例將一個對象添加到anObject-(NSArray*)原對象的末尾形成NSArray*newArray=[noteAr-NSArrayarrayByAddingObject:新的對象並返回該rayarrayByAddingObject:NSArray,(id)anObject對象note4];檢測調用該方法的if([noteArrayNSArray-(BOOL)containsObject:(id)對象的所有元素中是否包含containsObject:note1]){anObject對象[note1showNote];anObject} if([noteArrayisEqualToArray檢測調用該方法的-(BOOL)isEqualToArray:NSArraynewArray]){對象與是否相同(NSArray*)otherArrayotherArrayNSLog(@\"%d\",[newArraycount]);} 該方法使用字符串separator-(NSString*)compo-將對象中各個元素NSArray[noteArraycomponentsJoinedBy-nentsJoinedByString:(NS-連接成為一個類的NSStringString:@\"and\"];String*)separator對象並將該對象返回, 隻是一個不可變的數組如何既有條理地組織各條記錄又能隨時添加記NSArray,,錄呢下一小節就向你介紹可變數組的相關知識?NSMutableArray。 4.3.4NSMutableArray同與的關係一樣是的子NSMutableStringNSString,NSMutableArrayNSArray類也是的可變版本它繼承了的所有屬性及方法同時又增加了新,NSArray,NSArray,的方法從而可以方便地對已創建的對象進行修改,NSMutableArray。 這一小節將向你介紹可變數組的使用比如今天結束工作剛回到NSMutableArray,,家我想記錄下這件事那麼在程序中應該怎樣做呢現在來對程序做以下修改,,Note?,:67代碼文件4.7Note.m#import#import\"NoteClassh\"intmainintargcconstchar*argvNSAutoreleasePool*pool=NSAutoreleasePoolallocinitinsertcodehere創建可變字符串NSMutableString*note1Date=NSMutableStringallocinitWithString@\"600\"NSMutableString*note1Content=NSMutableStringallocinitWithString@\"Running\"NSMutableString*note2Date=NSMutableStringallocinitWithString@\"700\"NSMutableString*note4Date=NSMutableStringallocinitWithString@\"1800\"NSMutableString*note4Content=NSMutableStringallocinitWithString@\"Gettinghome\"創建記錄NoteClass*note1=NoteClassallocinitWithDatenote1DateandContentnote1ContentNoteClass*note2=NoteClassallocinitWithDatenote2DateNoteClass*note3=NoteClassallocinitWithDatenote1DateandContentnote1ContentNoteClass*note4=NoteClassallocinitWithDatenote4DateandContentnote4ContentNSMutableArraynoteArrayNSMutableArrayalloc*=initWithObjectsnote1 notenotenil23? forinti=0i forinti=0i 圖可修改內容的的運行結果4-6“Note”下麵我們就來分析一下這個程序,。 首先在處可以看到我們換用類聲明了用來組織記錄的數組對象,?,NSMutableArray:NSMutableArray*noteArray=[[NSMutableArrayalloc]initWithObjects:note1,note2,note3,nil];是的子類因此依然可用中的初始化方法NSMutableArrayNSArray,NSArrayinit-來對的對象進行初始化WithObjects:NSMutableArray。 之後處使用的方法在可變數組末尾添加了新增的?NSMutableArrayaddObject:,記錄note4:[noteArrayaddObject:note4]。 提供了多種方法來對一個可變數組進行增加刪除插入等操作NSMutableArray、、。 我們在每種操作的各方法中挑選出最為常用的見表,4?6。 表4-6NSMutableArray常用方法方法介紹示例在調用該方法的NSMutable-對象的末尾添加另一個Array-(void)addObjectsFromArray:對象中所包含的元NSArray(NSArray*)otherArray素來改變該,NSMutableAr-對象ray在調用該方法的NSMutable--(void)insertObject:對象的指定位置Arrayindex(id)anObjectatIndex:處添加一個元素來改變原(NSUInteger)index對象NSMutableArray70續表方法介紹示例-(void)移除對象的指定位置處indexremoveObjectAtIndex:的元素(NSUInteger)index以上列舉的一些對進行操作的方法隻是最為常用的幾個每種操NSMutableArray,,作除了上麵列出的外還有其他多種形式如關於移除對象的方法還有,,-(void)remove-等在此就不一一列舉了Object:(id)anObject,。 4.4NSDictionary是中另一個非常重要的集合類每個的元NSDictionaryFoundation。NSDictionary素由兩部分構成關鍵字和值在給定的關鍵字通常為類型的:。NSDictionary(NSString對象下存儲一個相應的值可以是任意類型的對象之後我們就可以根據關鍵字來查)(),找相應的值正如在現實中的字典一樣,。 也是不可變的如果我們要在程序運行過程中對中的元NSDictionary,NSDictionary素進行修改就需要使用它的子類來進行這些操作,NSMutableDictionary。 使用的是鍵查詢的優化存儲方式可以立即找出要查詢的數據而無NSDictionary,,需遍曆所有元素進行查找尤其對於大型數據集來說使用要比使用,,NSDictionary快很多NSArray。 下麵我們就使用來重新組織一下程序將記錄保存在NSDictionaryNote,NSDic-對象中用記錄的時間作為關鍵字來進行存取修改文件如下tionary,。Note.m:代碼文件4.8Note.mNSMutableArray*noteArray=NSMutableArrayallocinitWithObjectsnote1note2note3nilforinti=0i note1note1dateú? note2note2dateúú note3note3dateúú note4note4datenil? NSLog@\"1800\"noteDicobjectForKey@\"1800\"showNote? 運行程序得到如圖所示的輸出結果,4-7。 圖使用實現的輸出結果4-7NSDictionary現在就來分析一下這個使用組織記錄的程序,NSDictionary。 首先來看一下處用於創建對象的語句?NSDictionry:NSDictionary*noteDic=[[NSDictionaryalloc]initWithObjectsAndKeys:note1,note1.date,note2,note2.date,note3,note3.date,note4,note4.date,nil];這句代碼創建了一個的對象並用類的對象NSDictionarynoteDic,NoteClass和來初始化它同時又分別使用對應對象的變量作為鍵值note1、note2、note3note4,date進行存儲這樣就可以通過鍵值來檢索中的數據了的。,NSDictionary。NSDictionary方法聲明如下initWithObjectsAndKeys::-(id)initWithObjectsAndKeys:(id)firstObject,…這個方法與的方法類似後麵需要任意個用來初始化NSArrayinitWithObjects:,對象的參數並在參數列表最後用表示結束但要注意的是在NSDictionary,nil。:NSDic-中的元素包含值與關鍵字兩部分所以在參數列表當中也需要按tionary,NSDictionary,72照一個值一個對應關鍵字的次序列出各個參數來初始化對象比如在上NSDictionary。 麵的例子中是的關鍵字是的關鍵字它們需要一一,note1.datenote1,note2.datenote2,對應。 在本例中我想查看一下自己在做了什麼事情所以在程序中的處使用了,18:00,?,下麵的代碼來獲取以為關鍵字的記錄“18:00”:[[noteDicobjectForKey:@\"18:00\"]showNote];其中的就表示將關鍵字為的元素的值從[noteDicobjectForKey:@\"18:00\"]“18:00”中取出在本程序中也就是對象的方法聲noteDic,note4。NSDictionaryobjectForKey:明如下: -(id)objectForKey:(NSString*)key利用這個方法就可以方便地根據關鍵字取出對應在對象中的,keyNSDictionary值 。 依然是不可變的如果需要在程序運行過程中改變某些數據的話我NSDictionary,,們需要使用的子類創建對象來組織數據NSDictionaryNSMutableDictionary。NSMut-與的關係同與的關係是類似ableDictionaryNSDictionaryNSMutableArrayNSArray的 。 45小結. 在本章介紹了一些主要的類包括與Cocoa,NSObject、NSString、NSArrayNSDic-tionary。 其中是所有類的父類在創建一個自定義類時要直接或間接地繼NSObjectCocoa,,承 NSObject。 與是中用來進行字符串操作的類使用它們可以NSStringNSMutableStringCocoa,創建獲取編輯一個字符串兩者之間不同的是類的對象是不可變的而、、。,NSString,類的對象是可變的NSMutableString。 和是中的NSArray、NSMutableArray、NSDictionaryNSMutableDictionaryCocoa集合類與相當於其他語言中的數組但的對象是。NSArrayNSMutableArray,NSArray不可變的而則是可變的與中,NSMutableArray。NSDictionaryNSMutableDictionary的元素包含兩部分關鍵字和值我們通過關鍵字來對對應元素中的值進行存取而———,。 且與使用鍵查詢的優化存儲方式可以立即找出要NSDictionaryNSMutableDictionary,查詢的數據而不需遍曆所有元素進行查找適用於大型數據集,,。 至此本章就結束了下一章中將向你介紹中類別與協議的有關知識,,Objective-C。 73第章類別和協議5 本章內容類別的定義與實現■ 類別的使用■ 采用協議■ 自定義協議■ 類別與協議是中既重要又非常有特色的兩部分內(Category)(Protocol)Objective-C容類別允許為已經封裝好了的類添加新的行為是一種對類的功能進行豐富的新手。,段協議是一個命名的方法列表在中可以通過采用協議來實現某些功能。,Objective-C,這有些類似於中的接口下麵就來開始本章的學習Java。,。 51類別. 類別是對類的擴展使用類別可以不改變已經封裝好的類而為它添加新的行為,,。 看到這裏你也許會有疑問這項工作是不是可以通過創建該類的子類來完成呢下麵,:? 我們就來看兩個簡單的需要類別的情況: 當一個類過於龐大時例如後麵章節我們會講到的用於界麵設計的(1),UIWindow類將它放在一個文件中就不太合適這時便可以使用類別來分散該類的實現,,。 有些類如我們前麵講到的與等它們實際上隻是一個類簇(2)NSStringNSArray,的前台表示因而無法用來創建子類這時如果想為它們添加一些新的功能就可以通,。,過類別來實現。 現在假設前麵程序中的類已經封裝好了不可以對它再進行任何,NoteNoteClass,修改而在文件中那段用來檢測是否有重複記錄的代碼又過於繁瑣所以決定,Note.m,,將檢測重複記錄這個功能封裝為類的一個方法這時便可以使用類別來完成NoteClass,,這個功能的添加。 511類別的聲明與實現.. 使用類別為一個類添加方法需要先聲明該類別格式與聲明一個類類似,,:74代碼類別聲明的格式5.1interfaceClassNameCategoryName@ addedMethods……不能添加變量end@ 在類別聲明中是現有的類即該類別要為之添加方法的類(1),ClassName,。Cate-是要聲明的類別的名稱類別的聲明同樣要以結束goryName。@end。 在與之間是要為類添加的方法但有一點需要著(2)@interface@endClassName,重注意在這裏隻可以添加方法而不可以添加新變量:,。 下麵我們就來為類聲明一個類別並在該類別中添加用,NoteClassNoteCategory,來檢測重複記錄的方法testSameNote:。 首先添加兩個文件這一次選擇選項下的模板如圖所示,,otherEmptyFile,5-1。 圖選擇文件模板5-1EmptyFile75分別為兩個文件命名為和如圖所示NoteCategory.hNoteCategory.m,5-2。 圖建立文件5-2NoteCategory.h建立好文件之後將文件修改如下,NoteCategory.h:代碼文件5.2NoteCategory.hclassNoteClass@ interfaceNoteClassNoteCategory@ -BOOLtestSameNoteNoteClassaNote* end@ 這一句用來說明是一個類除此之外並沒有包含任何@classNoteClass:NoteClass,類的具體信息相當於中的前向引用作用就是告訴下麵的程NoteClass。@classC++,序段如果再見到時便將它當做一個類來處理從而避免了將整個頭文件導“NoteClass”,,入進來造成代碼臃腫,。 此外表示將聲明為,@interfaceNoteClass(NoteCategory)NoteCategoryNoteClass類的一個類別接著在該聲明之後為類添加了一個。,NoteClass-(BOOL)方法該方法用於檢測與調用該方法的對象testSameNote:(NoteClass*)aNote,aNote是否相同。 這樣類別便聲明完成了下麵就在文件中完成對,NoteCategory。NoteCategory.m方法的實現-(BOOL)testSameNote:(NoteClass*)aNote:76代碼文件5.3NoteCategory.m#import\"NoteClass.h\"import\"NoteCategory.h\"#? implementationNoteClassNoteCategory@()-BOOLtestSameNoteNoteClassaNoteù():(*){úifself.dateisEqualToaNote.dateú([:]ú&&self.contentisEqualToaNote.content[:]){úreturnYESú? úú }úreturnFALSE? } end@ 文件開頭處引入了該類別的頭文件而且在這裏?,:#import\"NoteCategory.h\"。,由於要用到的變量與等具體信息所以還需要在文件一開始引NoteClassdatecontent,進類的頭文件NoteClass:#import\"NoteClass.h\"。 與類的實現一樣在與兩個關鍵,@implementationNoteClass(NoteCategory)@end字的中間完成對類別中方法的實現NoteCategory。 在處實現了方法該方法將檢測?,-(BOOL)testSameNote:(NoteClass*)aNote,調用方法的對象與對象是否相同如果相同則返回不同則返回aNote,YES,NO。 這樣我們便完成了對類別的定義,NoteCategory。 512類別的使用.. 完成了類別的定義便可以在程序裏對類別中新添加的方法進行調用了調用類別,。 中定義的方法與調用類的一般成員方法形式完全一樣。 現在完成了類的類別的定義我們來修改一下程NoteClassNoteCategory,Note.m序 。 首先在文件開頭引入的頭文件將先NoteCategory:#import\"NoteCategory.h\"。 前用於檢測重複記錄的兩條語句替換為下麵的代碼if:代碼文件的修改5.4Note.m檢查與是否是相同記錄note1note2ifnote1testSameNotenote2? NSLog@\"note2issamewithnote1\"elseNSLog@\"note2isdifferentfromnote1note2\"note2showNote77檢查note1與note3是否是相同記錄ifnote1testSameNotenote3NSLog@\"note3issamewithnote1\"elseNSLog@\"note3isdifferentfromnote1note2\"note3showNote我們將先前冗餘的條件判斷語句替換成了在處對方法的調用if?testSameNote。 運行程序可以得到如圖所示的輸出結果,5-3。 圖程序輸出結果5-3可以看到程序的運行結果與先前相同而程序中對方法的調用與調,,testSameNote用一般成員方法無異:[note1testSameNote:note2]。 這樣我們便對如何聲明實現一個類別以及如何使用類別中添加的方法有一定的,、,了解了在今後的開發過程中如果遇到需要自己為類添加一個自定義方法。,NSString等情況便可以使用類別來輕鬆實現了,。 52協議. 協議是一個命名的方法列表是中一個非常重要的語言特性當一個類,Objective-C,采用了某個協議之後該類通過實現協議中的方法可以實現一些功能它類似於,,。Java當中的接口彌補了不支持多繼承的缺陷,Objective-C。 在以前的版本中如果某個類采用了一個協議那麼這個類必須實現該協議中的所,,有方法但在中增加了兩個新的協議修飾符和。Objective-C2.0,:@optional@re-78這兩個新增的修飾符用來修飾協議中的方法用來修飾則表示該方法quired,,@optional可以被選擇實現而用修飾的方法則必須實現是默認修飾符,@required,@required。 中已經為我們聲明好了很多方便好用的協議如協議Cocoa,NSCopying、NSCoding協議等通過采用這些協議可以方便地為自定義的類實現協議所對應的功能本章。,。,我們將繼續修改程序假設有一些重要的記錄需要備份則可以通過采用Note。,NSCo-協議來實現複製功能下麵就來學習中協議的使用並為pying。Objective-C,NoteClass實現複製這一功能。 521深拷貝與淺拷貝.. 看到我們要采用協議來實現記錄的備份你是否有這樣的疑惑使用NSCopying,:可以使具有與相同的內容不是一樣實現了備份為note2=[note1retain]note2note1,? 什麼還要通過采用協議呢這涉及到了深拷貝與淺拷貝的問題NSCopying?。 1淺拷貝. 當我們使用來為賦值時實現的是對的淺note2=[note1retain]note2,note2note1拷貝那麼什麼是淺拷貝呢。? 以為例該語句執行後與雖然是兩個對象但它note2=[note1retain],,note1note2,們指向的是同一塊內存區域也就是說它們隻是同一個內容的不同名稱若其中一個對,。 象改變了自己的內容實際也就改變了另一個對象的內容這並不是我們對記錄進行備,。 份的初衷實現了淺拷貝的與的關係如圖所示。note1note25-4。 圖淺拷貝示意圖5-42深拷貝. 如果對象對對象實現的是深拷貝的話則會為對象重新開辟一塊note2note1,note2隻屬於它自己的內存區域在這塊內存區域中存儲從中拷貝過來的數據實現了,note1。 深拷貝後的與的關係如圖所示note1note25-5。 圖深拷貝示意圖5-579此時再修改的內容時便不會對造成任何影響了下麵具體看一下應note1,note2。,該如何通過采用協議來實現備份的功能NSCopying。 522采用協議.. 在聲明一個類的時候我們要決定該類需要采用哪些協議並用尖括號將這些協議,,括起來格式如下,:@interfaceClassNameSuerClassName:pProtocolName1ProtocolName2同一個類在聲明時采用的協議可以有多個中間用隔開即可如上麵的,“,”, 。 現在就來修改一下類的聲明使該類采用協議,NoteClass,NSCopying:代碼在文件中修改聲明5.5NoteClass.hNoteClass?NSCopying? @interfaceNoteClassNSObject? NSString*dateNSString*content在這裏沒有做很大的修改隻是在處類聲明語句最後添加了要采用的,?NSCopying協議:@interfaceNoteClass:NSObject。 但僅僅這樣還未能具備協議所提供的複製功能要實現這一,NoteClassNSCopying,功能還需要實現協議中用於深層拷貝的方法,NoteClassNSCopying:-(id)copyWith-下麵我們就在文件中實現該方法Zone:(NSZone*)zone。,NoteClass.m:代碼():()的實現5.6-idcopyWithZoneNSZone*zone-idcopyWithZoneNSZonezone* NoteClassnoteCopy=selfclass* allocWithZonezoneinit? noteCopydate=selfdatecopy? noteCopycontent=selfcontentcopyreturnnoteCopy實現了方法後類的對象便具有了-(id)copyWithZone:(NSZone*)zone,NoteClass深拷貝的功能但在進行複製時類的對象並不會直接調用。,NoteClass-(id)copyWith-方法而是先調用從繼承來的方法方法再Zone:(NSZone*)zone,NSObjectcopy,copy負責調用方法如圖所示copyWithZone,5-6。 80圖複製過程5-6下麵我們就來分析一下這段代碼: 方法會在方法內部複製好對象並將它(1)-(id)copyWithZone:(NSZone*)zone:,作為該方法的返回值表示一塊可供分配的內存區域我們就將在這。(NSZone*)zone,塊區域中為新複製的對象開辟內存並存儲複製來的數據,。 處的是不是看?NoteClass*noteCopy=[[[selfclass]allocWithZone:zone]init]著較為複雜呢我們先來介紹一下這當中用到的兩個方法?:idallocWithZoneNSZonezone該方法是一個類方法它負責在一個給定+():(*):,區域中創建新對象並將新對象返回zone。 -Classclass它將返回調用該方法的對象所屬的類型():。 這裏使用的就是為了動態獲得要複製的對象所屬的類型假設[selfclass]。Note-還有一個子類它繼承了所采用的協議與ClassSubNoteClass,NoteClasscopyWithZone方法那麼子類方法中的返回的就是而不是,copyWithZone[selfclass]SubNoteClass,了這樣我們就動態獲取了要複製對象的類型也避免了子類對NoteClass。,,copyWith-方法的重複實現Zone。 創建好對象之後便可在方法中處通過調用類的方法分noteCopy,?NSStringcopy別實現對變量與變量的深層複製datecontent:noteCopy.date=[self.datecopy];noteCopy.content=[self.contentcopy];這樣便完成了的深層複製工作並將複製的數據存放在了對,NoteClass,noteCopy象對應的內存區域中最後我們將對象作為返回值返回。,noteCopy:returnnoteCopy。 現在已經在類中通過采用協議實現了複製功能下麵修改NoteClassNSCopying,文件驗證一下是否真的實現了深層複製功能Note.m,NoteClass:代碼的實現5.7Note.m#import#import\"NoteClass.h\"81intmain(intargc,constchar*argv[]){NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];\/\/insertcodehere... 創建可變字符串\/\/NSMutableString*note1Date=[[NSMutableStringalloc]initWithString:@\"6:00\"];NSMutableString*note1Content=[[NSMutableStringalloc]initWithString:@\"Running\"];創建記錄\/\/NoteClass*note1=[[NoteClassalloc]initWithDate:note1DateandContent:note1Content];NoteClassnote2=note1retain? *[];NoteClassnote3=note1copy*[];NSArray*noteArray=[[NSArrayalloc]initWithObjects:note1,note2,note3,nil];for(inti=0;i<[noteArraycount];i++){NSLog(@\"note%d:\",i+1);[[noteArrayobjectAtIndex:i]showNote];} 改變內容\/\/note1NSLog(@\"\");note1DatesetString@\"700\"[::];? for(inti=0;i<[noteArraycount];i++){NSLog(@\"note%d:\",i+1);[[noteArrayobjectAtIndex:i]showNote];} [note1Daterelease];[note1Contentrelease];[note1release];[note2release];[note3release];[pooldrain];return0;} @end82運行程序來查看結果如圖所示,5-7。 圖深拷貝輸出結果5-7下麵來分析一下上麵的程序代碼,:這次在程序中隻初始化了對象之後在代碼處通過使用對象分別,note1,,?note1為與賦值來初始化這兩個對象但使用為兩個對象賦值的方式有所note2note3。note1不同: NoteClass*note2=[note1retain];NoteClass*note3=[note1copy];對於使用方法來為它賦值進行初始化而對於則通過調用note2,retain;note3,copy方法來為它賦值進行初始化按照前麵所講的這樣就完成了對的淺拷貝與對。,note2的深拷貝note3。 在代碼的處對對象中的時間信息進行了修改然後再次輸出三條記錄按?,note1,。 照前麵深拷貝與淺拷貝的理論由於實現的是對的淺拷貝所以在修,note2note1,note1改後的輸出內容應該仍然與相同而實現了對的深拷貝所以,note2note1;note3note1,的任何改變均不會對造成影響看看圖中的輸出結果是不是這樣note1note3。5-4,? 現在我們便通過采用協議為類實現了深拷貝的功能,NSCopyingNoteClass。 在中還有很多常用且重要的協議但在這裏介紹隻會讓你感到困惑和乏味Cocoa,,。 所以關於更多的協議我們將在後麵章節中用到的時候再進行詳細講解,。 523自定義協議.. 在上一小節以為例介紹了如何采用一個中的協議我們也可以,NSCopyingCocoa,聲明自己的協議格式如下,:代碼自定義協議的格式5.8protocolProtocolName@ optional@ 83……required@ ……end@ 要聲明一個協議時需要使用關鍵字,@protocol。 在關鍵字與之間是協議的方法其中關鍵字表示在實現@protocol@end,@optional該協議時可以選擇實現下麵的方法而關鍵字下麵的方法則是必須實現,;@required,的 。 最後以表示協議聲明的結束,@end。 53小結. 這一章我們介紹了中兩個非常重要的語言特性類別和協議Objective-C:。 使用類別可以為特定的類添加新的功能從而可以對已經封裝好的類進行擴展或,,,者將過於龐大的類進行分解實現在節講解了一個類別從聲明到實現一直到使用。5.1,的過程在使用類別對類進行擴展時我們隻可以為類添加新的方法而不可以對類添。,,加新的變量。 在節中講解了如何采用一個協議以及如何自定義一個協議並通過讓5.2,Cocoa,采用協議使本類的對象具有了複製深拷貝的能力NoteClassNSCopying,()。 至此本書關於語言的介紹便結束了從下一章開始我們將開始,Objective-C,,開發的學習iPhone! 84本篇通過大量的實例,講解了開發中的基本概念和基礎知iPhone識,是讀者進一步學習本書擴展篇和叢書其他分冊的基礎。 核心篇包括章:7 第章視圖和控件,講解了開發中視圖和控件的基本概念6iPhone和使用方法,介紹了如何在程序中使用自定義視圖。 iPhone第章視圖控製器,通過三個小程序介紹了開發中視圖控7iPhone製器的使用方法,包括自定義視圖控製器、導航控製器和標簽欄控製器,本章還介紹了視圖間轉換動畫的兩種實現方法。 第章表視圖,係統而詳盡地講解了表視圖的概念和常用操作,包8 括創建表、填充數據、顯示數據及操作表中的數據等。 第章數據持久性存儲,介紹了應用程序沙盒的概念,係統地介紹9 了持久保存數據的四個方法:屬性列表、歸檔、和。 SQLite3CoreData第章用戶設置,通過程序介紹了如何在10NoteSettingSettings中和程序內部添加設置選項,本章還講解了表行上添加控件的方法。 第章觸摸、手勢和事件,介紹了上觸摸的底層機製,講11iPhone解了觸摸的各種常用手勢的實現方法,包括輕擊、拖拽、輕掃、捏合等。 第章國際化和本地化,介紹了國際化和本地化的概念,通過對12一個應用程序進行國際化和本地化操作,詳細講述了應用程序如何實現多語言版本。 第章視圖和控件6 本章內容視圖的概念和使用方法■ 理解和■IBOutletIBAction如何使用各種簡單控件■ 如何實現與控件交互■ 如何創建一個自定義視圖■ 你一定為上豐富多彩的應用程序而心動過吧從這一章開始就進入了AppStore!,本書的核心部分用和編寫應用程序:XcodeInterfaceBuilderiPhone。 如果想進行程序開發本章的內容是必不可少的這是我們開發的應用程序iPhone,,通向的必經之路AppStore。 在這一章中首先介紹了開發中最基本的視圖的概念以及各個視圖之間的,iPhone,繼承和層次關係然後介紹了程序中要用到的一些基本控件通過一個名為的;,“Controls”程序解釋了如何利用和編寫應用程序最後我們對XcodeInterfaceBuilderiPhone;程序進行了優化並用自定義視圖方式實現了它這一章涵蓋了開發“Controls”,。iPhone所需的關鍵概念學習完本章相信你一定能開發出能在上完美運行,,iPhone\/iPodtouch的程序。 現在就讓我們開始吧,! 61視圖概述. 在程序開發中視圖是最基礎的部分一般來說iPhone,。,幾乎所有顯示在屏幕上的內容都可以被稱為視圖比iPhone,如通常見到的按鈕開關圖片等我們可以設置視圖的大小、、。 和位置以及視圖之間的層次關係如圖所示屏幕上顯,。6-1,示的文字圖形等都是視圖、。 611視圖和窗口.. 視圖是顯示可見元素的圖形用戶界麵而窗口則是(),GUI圖視圖6-186存放視圖的容器它們都是構建程序界麵的基本組成部分具體來說窗口提供,iPhone。,了一個顯示具體內容的平台而視圖則承擔了大部分的繪製界麵和用戶響應的工作,。 界麵的設計通常采用單窗口多視圖的模式即程序隻有一個窗口卻可以有多iPhone“-”,個視圖打個比方如圖所示把窗口比作顯示器視圖就如同顯示出來的豐富多彩的,,6-2,,內容顯示器裏麵的內容是不斷更新和變化的而顯示器卻是不變的它不像。,。Windows那樣可以是多個窗口同時瀏覽如圖所示IE,6-3。 圖的單窗口多視圖模式圖可以打開多個窗口同時進行瀏覽6-2iPhone“—”6-3WindowIE窗口即窗口類的一個實例它用來定義一個定位和管理應用程序界,(UIWindow)。 麵的對象窗口有層次地保存所有的視圖並且位於所有層的根部從根本上說窗口。,。,就是一種特殊的視圖它對於桌麵係統非常重要但對應用程序就沒有那麼重要,,iPhone了因為應用程序一般隻有一個窗口畢竟的屏幕太過小巧這也是,iPhone,iPhone,程序采用單窗口多視圖模式的直接原因iPhone“-”。 視圖即視圖類的一個實例它通常用於定義屏幕上的一個矩形區域可,(UIView),,以用來顯示各種控件圖像等可視元素這些元素都是以子視圖的方式加載在視圖上的、,,這就是我們稍後要講解的視圖層次關係。 87612視圖的繼承.. 在開發中的繼承是一部分重要的內容具體來說視圖一般擁有一iPhone,UIView,,個父視圖和多個子視圖圖中列出了的這種繼承關係從中我們可以很清。6-4UIView,楚地看出的父類是而它的子類是等UIViewUIResponder,UIControl、UIWindow。UI-擁有很多子類其中包括等等這些Control,UIButton、UITextField、UISwitch、UISlider,基本上就是本章所要講解的內容。 圖視圖的繼承6-4這裏簡單介紹一下繼承自從圖中可以清楚地UIControl。UIControlUIView,6?4看出這種關係的主要作用是實現用戶和程序的交互當用戶操作某個控件。UIControl:時將觸發相應的事件來完成一定的功能或過程還可以控製控件的狀態例,;UIControl,如設置它們的或者屬性enabledhighlighted。 613視圖的層次結構.. 程序中每個視圖和顯示該視圖的窗口是相互關聯的一個窗口中的所有視圖可以根, 據視圖層次連在一起按照視圖加入的先後順序由後向前顯示這說明了視圖。iPhone,,層次是一種空間上的疊加關係所有視圖都可以有子視圖一個視圖可能擁有很多子視。,圖也可能沒有子視圖,。 從圖視圖層次中可以看出包含狀態欄的是程序窗口顯示的是在6-5WorldClock,,上運行的程序的界麵標號為的是去除狀態欄的程序視圖是程序視圖iPhone。2“”,3“”的導航欄部分是標簽欄部分是位於導航欄和標簽欄之間的自定義視圖部分,4,5。2、3、88部分疊加在一起形成程序視圖4、51。 圖視圖層次6-5WorldClock視圖層次就是視圖在空間上的相互位置關係它可以幫助我們從整體上理解視圖,,,也可以為接下來學習控件的知識做鋪墊。 62基本控件介紹和使用. 了解了有關視圖和窗口的知識後接下來我們學習基, 本控件的功能和使用方法這些控件是以後構建,iPhone應用程序的主要元素。 6.2.1UILabel和UIButton在實現本章開頭部分提到的程序之前我們Controls,先來實現一個簡單的程序如果你學習過其MyButton。 他的程序設計語言那一定還記得經典的,“HelloWorld”程序接下來我們將完成一個類似的程序程序的最終效。,果如圖所示它隻包含一個標簽和一個按鈕點擊按6-6,,鈕標簽中顯示的是通過這個程序我們,“HelloiPhone”,,會逐漸熟悉和開發環境以及圖程序效果圖XcodeInterfaceBuilder,6-6MyButton89程序開發的大致過程iPhone。 此程序大概需要以下幾個步驟: 新建項目·MyButton;在和文件中添加程序·MyButtonViewController.hMyButtonViewController.m代碼; 構建程序界麵·;為控件連接輸出口和操作方法·;編譯並運行·。 1.新建項目MyButton打開選擇如圖所示在層級下選擇Xcode,File→NewProject,6-7。iPhoneOSAp-如圖所示在右側模板選項中選擇基於視圖的應plication,6-8,,View-basedApplication(用程序)。 圖創建新項目6-7圖選擇項目模板6-890點擊將項目命名為如圖所示同時可以為程序指定一個儲Choose,MyButton,6-9,存路徑用於存放我們以後編寫的所有示例,。 圖給項目命名並指定存儲路徑6-9點擊之後展現在我們眼前的應該是一個完整的框架你一定注意到了Save,Xcode,左側的窗格吧展開和文件夾XcodeGroups&Files,Classes、ResourcesFrameworks,將看到如圖所示的項目視圖它展示的是這個項目的結構6-10,。 圖下的項目視圖6-10Xcode2在MyButtonViewController.h和MyButtonViewController.m文件中添加程序. 代碼選中文件在裏麵定義一個類型的輸出口MyButtonViewController.h,UILabelmy-和一個操作方法具體代碼如下LabelbuttonClick。:代碼文件6.1MyButtonViewController.h#import@interfaceMyButtonViewControllerUIViewControllerIBOutletUILabelmyLabel*? 91propertynonatomicretainIBOutletUILabelmyLabel@*? -IBActionbuttonClick? @end在文件中我們首先在處用關鍵字聲明一MyButtonViewController.h,?IBOutlet個類型的輸出口在處用通知編譯器編譯時如何創建該類的成員UILabel;?property;在處用關鍵字聲明了一個按鈕單擊時的操作方法關於和?IBAction;IBOutletIBAc-的問題我們稍後將進行講解tion。 接下來選中文件實現定義的操作方法,MyButtonViewController.m,buttonClick。 它用來實現單擊按鈕時在標簽上顯示的功能具體代碼如下“HelloiPhone”,:代碼文件6.2MyButtonViewController.m#import\"MyButtonViewControllerh\"@implementationMyButtonViewControllersynthesizemyLabel@? -IBActionbuttonClickmyLabeltext\"HelloiPhone\"=@? selfmyLabelsetText\"HelloiPhone\"@? -voiddeallocmyLabelrelease? superdealloc@end在文件中首先在處用關鍵字說明編譯MyButtonViewController.m,?synthesize器該如何設置這個成員變量接著在操作方法中使用了兩種方法顯示字符;buttonClick,串在處是通過設置標簽屬性的方法來實現的而處是通過調用方法:?text,?setText:來實現的兩種方法具有相同的效果每當程序結束時都要調用處的方法它,;?dealloc,是用來釋放對象所占的內存資源的。 至此程序代碼編寫工作完成了接下來的工作是構建程序界麵,,。 3構建程序界麵. 本程序的界麵比較簡單隻需要添加一個標簽和一個按鈕具體步驟如下,。:展開文件夾雙擊文件進入(1)Resources,MyButtonViewController.xib,Interface中如圖所示從左到右分別表示窗口窗口和窗口Builder,6-11,Xib、ViewInspector。 92圖界麵6-11InterfaceBuilder選擇或使用快捷鍵(2)Tools→Library(打開窗口如圖+Shift+L),Library(6-12所示並從窗口中拖出一個),LibraryLabel控件和控件到窗口RoundRectButtonView中如果當前沒有顯示可以雙擊窗(View,Xib口中的圖標調整大小將View)。Label,的標題設為這樣用戶界Button“ClickMe”。 麵就創建好了。 4為控件連接輸出口和操作方法. 在為控件連接輸出口和操作方法之前, 我們先來運行一下程序點擊中。Xcode圖標或使用快捷鍵運行BuildandGo(+R)程序彈出模擬器點擊按,iPhone,ClickMe鈕並沒有出現我們希望的效果為什麼會,。 這樣呢這就是程序中存在和?IBOutlet的緣故IBAction。 IBOutlet經常被稱為輸出口可以理解為, 程序中用來動態輸出數據的對象它主要用。 於在頭文件文件中聲明一個實例變量(.h)。 例如要聲明一個類型的實例變量:UILabel隻需在頭文件中添加如下代碼myLabel,:IBOutletUILabel*myLabel;它用來傳遞一個消息給圖窗口InterfaceBuild-6-12Library93該實例變量需要與文件中的某個控件進行連接這個工作需要手動完成從而實er:Xib(),現在程序中對相應控件進行控製可以認為它是一個需要與進行連接,InterfaceBuilder的標識因而請記住一點如果你創建的實例變量需要與文件中的某個對象關聯。,:Xib起來就必須使用,IBOutlet。 IBAction用來聲明一些實現與用戶交互的方法這些方法需要和。InterfaceBuilder中的控件的相關事件進行連接使用聲明的方法沒有返回值隻是用來執行。IBAction,,一些操作例如聲明一個按鈕點擊方法需要在頭文件中添加以下代碼。,,:-IBActionbuttonClickidsender或 -IBActionbuttonClick如上所示可以聲明帶參數或者不帶參數的方法參數名通常指定為即事件,,sender,的發送者相應地參數類型通常被定義為類型。,id。 ?? ??????????????????????????? ?在程序中,如果我們希望獲取控件相關屬性的值,? ?? ?如獲取按鈕的標題,可以聲明為帶參數的操作方法;如? ?? ?果控件本身隻是作為事件的發起者,與本身屬性無關,? ????????????????????????? ?可以聲明為不帶參數的操作方法? ?。? 現在你一定明白程序為什麼沒有達到預期的效果了因為我們沒有為標簽連接輸,,出口也沒有為按鈕指定操作方法下麵就來完成這些工作選中,。。MyButtonViewCon-窗口中的圖標同時按住鼠標右鍵拖動鼠標到中的troller.xibFile?sOwner,,ViewLa-上在移動過程中將出現一根沿著我們移動方向的藍色引導線如圖所示bel,,6-13。 圖連接輸出口6-1394釋放鼠標右鍵此時會出現如圖所示的選項框裏麵有一個我們之前,6-14Outlets,定義的輸出口選中它就可以了myLabel,。 圖選擇輸出口6-14myLabel接下來要完成另外一個連接為按鈕的單擊事件指定操作方法選中:buttonClick。 窗口下的按鈕同時按下鼠標右鍵拖動鼠標到窗口中的ViewClickMe,,XibFile?s圖標上注意這次移動方向和連接輸出口時相反釋放鼠標右鍵此時會出現如Owner,,;,圖所示的事件選項框同樣裏麵有我們定義的方法選中它就6-15Events(),buttonClick,可以了。 圖為控件連接操作方法6-15?? ?????????????????????????? ?? ?除了上述連接操作方法的方式以外,我們還可以? ?? ?使用快捷鍵調出窗口,在? ?+2ConnectionsEvents? 層級下選擇事件,連接到?TouchUpInsideFile?s? ?圖標;同時在彈出的選項框下選擇相應? ?? ????????????????????????? OwnerEvents? 的操作方法即可?。? 955編譯並運行. 至此這個小程序才算真正完成了現在再次運行一下看看效果點擊中的,,。Xcode圖標運行模擬器當我們點擊按鈕時將在標簽上顯示BuildandGo,iPhone,ClickMe,效果如圖所示“HelloiPhone”,6-6。 622UITextField.. 控件就是實際應用中經常見到的文本輸TextField入框它主要提供用戶輸入以及視圖之間的傳值等交互功, 能從本小節開始我們將逐步構建本章開始部分介紹的。,程序Controls。 這一節要完成的任務是將用戶在文本框TextField中輸入的信息顯示出來程序的最終效果如圖所。6-16示 。 要完成此程序需要做以下工作: 新建項目在·Controls,ControlsViewController.h文件中聲明輸出口和操作方法; 構建程序界麵並連接輸出口和操作方法·,;修改文件實現操作·ControlsViewController.m,方法; 編譯並運行·。圖程序運行效果圖6-161新建項目Controls,在ControlsViewController.h文件中聲明輸出口和操作方法. 打開仍然使用模板創建一個新項目將其命名為Xcode,View-basedApplication,展開窗格下的文件夾然後選中Controls;Groups&FilesClasses,ControlsViewCon-文件添加如下代碼troller.h,:代碼文件6.3ControlsViewController.h#import@interfaceControlsViewControllerUIViewControllerIBOutletUITextFieldtopic*? IBOutletUITextFieldform*? propertynonatomicretainUITextFieldtopic@*propertynonatomicretainUITextFieldform@*-IBActionbuttonClick? @end96在和處聲明了兩個類型的輸出口和分別用來接收用??UITextFieldtopicform,戶輸入的數據此外在處還聲明了一個操作方法該方法用來響應用戶;,?buttonClick,點擊按鈕的操作。 2構建程序界麵,並連接輸出口和操作方法. 雙擊打開文件將出現ControlsViewController.xib,界麵從窗口中拖出兩個InterfaceBuilder,Library兩個和一個控件Label、TextFieldRoundRectButton到窗口中設置各個控件的大小位置和標題如圖View,、,所示6-17。 最後我們需要將文件,ControlsViewController.h中聲明的兩個輸出口分別與界麵上的控件連TextField接同時還需要為按鈕的事件指定一;,TouchUpInside個操作方法即方法具體的連接方法和上,buttonClick。 一小節完全相同。 3修改ControlsViewController.m文件,實現操作. 方法為了能夠顯示用戶輸入的信息需要實現,button-圖程序界麵操作方法選中文件6-17ControlsClick,ControlsViewController.m,添加如下黑體字所示的代碼: 代碼文件6.4ControlsViewController.m#import\"ControlsViewControllerh\"@implementationControlsViewControllersynthesizetopic@ synthesizeform@ -IBActionbuttonClick獲得兩個中的內容TextFieldNSStringstringTopic=selftopictext* NSStringstringForm=selfformtext* UIAlertViewalert=UIAlertViewallocù*úinitWithTitle@\"顯示信息\"úú messageNSStringstringWithFormat@\"標題ú %@n類型%@\"stringTopicstringFormú? \\údelegatenilúú cancelButtonTitle@\"確定\"ú otherButtonTitlesnil? 97alertshow? alertrelease? -voiddealloctopicreleaseformreleasesuperdealloc@end在操作方法中我們主要看一下處的代碼首先創建了buttonClick,?。,UIAlert-類的一個實例對象其中顯示信息用於設置警告框的標Viewalert,initWithTitle:@\"\",題後麵是一個對象表示標題下的警告信息後麵用於設置;messageNSString,;delegate它的委托對象用於設置警告框上默認的按鈕標題我們還可以通過;cancelButtonTitle,添加並設置其他按鈕的標題其次創建完成對象之後需要調用處otherButtonTitles;,,? 的方法通知警告顯示在屏幕上最後別忘了調用處的方法將它釋放掉show;?release。 4編譯並運行. 點擊圖標編譯並運行程序在文本框中輸入相關信息點擊BuildandGo,,,“Click按鈕程序將彈出一個警告框來顯示用戶輸入的信息具體效果如圖所示Me”,。6-16。 623UISwitch.. 上一小節已經完成了程序的一部分功能在這裏將再加入一個開關Controls,Switch()控件一個和一個其中添加的開關用來控製和控件是否、LabelTextField,LabelTextField可見程序運行時初始界麵如圖所示開關處於狀態新添加的兩個控件顯示在。,6-18,ON,視圖上當點擊開關處於狀態時新添加的標簽和文本框將被隱藏如圖所示;OFF,,6-19。 圖處於打開狀態圖處於關閉狀態6-18Switch6-19Switch98用戶輸入完成之後點擊按鈕將彈出警告提示框若開關打開警告框中將顯示所,。,有用戶輸入信息如圖所示若開關關閉警告框中沒有內容的相關信息如圖,6-20;,“”,所示6-21。 圖開關打開時的提示信息圖開關關閉時的提示信息6-206-21程序的步驟大致如下: 修改文件添加輸出口和操作方法·ControlsViewController.h,;修改程序界麵並連接輸出口和操作方法·,;修改文件實現操作方法·ControlsViewController.m,;編譯並運行·。 1修改ControlsViewController.h文件,添加輸出口和操作方法. 使用打開程序選中文件並添加如下XcodeControls,ControlsViewController.h,黑體字所示的代碼: 代碼文件6.5ControlsViewController.h#import@interfaceControlsViewController:UIViewController{IBOutletUITextField*topic;IBOutletUITextField*form;99IBOutletUILabelcontentLabelù*;úIBOutletUITextFieldcontentFieldú*;úIBOutletUISwitchcontentSwitch;ú*ú}úú @property(nonatomic,retain)UITextField*topic;ú? @property(nonatomic,retain)UITextField*form;úpropertynonatomicretainUILabelcontentLabelú@(,)*;úpropertynonatomicretainUITextFieldcontentFieldú@(,)*;úpropertynonatomicretainUISwitchcontentSwitch? @(,)*;-IBActionhidden();? -IBActionbuttonClick();? -IBActiontextFieldDoneEditingidsender():();? @end在文件處增加了三個輸出口ControlsViewController.h?:contentLabel、content-和在處聲明的方法用來控製新添加的控件是否可見在FieldcontentSwitch。?hidden;處聲明的方法用來顯示用戶輸入信息在程序處聲明的?buttonClick;?textFieldDone-方法用來撤銷輸入過程中彈出的鍵盤Editing:,。 2修改程序界麵,並連接輸出口和操作方法. 接著我們需要對程序原有界麵做簡單修改在已有的標簽和文本框的基Controls。 礎上再往視圖上添加一個開關按下打開開關的窗口如圖所示,+1,Attributes,6-22,將初始狀態設為然後再添加一個標簽和一個文本框適當地調整它們的大小和位On。,置最後效果如圖所示。6-23。 我們還需要為相應的控件連接輸出口方法同上一小節此外還需要為控件連接操,;作方法選擇開關控件打開窗口點擊鼠標左鍵選擇事件,,Connections,ValueChanged,把它拖到上選擇方法選擇按鈕打開窗口將其File?sOwner,hidden;,Connections,事件連接到上並選擇方法最後將三個文本TouchUpInsideFile?sOwnerbuttonClick;框的事件均連接到上並選擇DidEndonExit,File?sOwnertextFieldDoneEditing:方法。 100圖的窗口圖添加新控件後的界麵6-22SwitchAttributes6-233修改ControlsViewController.m文件,實現操作方法. 保存上述操作並返回選中文件添加如下黑體字Xcode,ControlsViewController.m,所示的代碼: 代碼文件6.6ControlsViewController.m#import\"ControlsViewControllerh\"@implementationControlsViewController@synthesizetopic@synthesizeformsynthesizecontentLabel@ synthesizecontentField@ synthesizecontentSwitch@ -IBActionhiddenúùifselfcontentSwitchisOnúú selfcontentLabelsetHiddenNOúselfcontentFieldsetHiddenNOúú úú? elseú selfcontentLabelsetHiddenYESúú selfcontentFieldsetHiddenYESúú ? 101-IBActionbuttonClickNSString*stringTopic=selftopictextNSString*stringForm=selfformtextNSStringstringContentselfcontentFieldtext*=UIAlertView*alertifselfcontentSwitchisOnùú alert=UIAlertViewallocinitWithTitle@\"顯示信息\"úú messageNSStringstringWithFormatú @\"標題%@n類型%@n內容%@\"ú\\\\ústringTopicstringFormstringContentúú delegatenilú dcancelButtonTitle@\"確定\"úú dotherButtonTitlesnilú úú elseúú? alert=UIAlertViewallocinitWithTitle@\"顯示信息\"ú messageNSStringstringWithFormatúú @\"標題%@n類型%@\"ú\\ústringTopicstringFormú delegatenilúú cancelButtonTitle@\"確定\"ú otherButtonTitlesnilúú úú alertshowúú alertrelease? -IBActiontextFieldDoneEditingidsenderùú? senderresignFirstResponder? -voidviewDidLoadifselfcontentSwitchisOnselfcontentLabelsetHiddenYESselfcontentFieldsetHiddenYES102=@請輸入相關信息selftopicplaceholder\"\"=@請輸入相關信息selfformplaceholder\"\"selfcontentFieldplaceholder=@\"請輸入相關信息\"superviewDidLoad-voiddealloctopicreleaseformreleasecontentLabelreleasecontentFieldreleasecontentSwitchreleasesuperdealloc@end在此文件中處的方法是根據開關的狀態來控製相應的控件是否顯示的,?hidden;我們對方法做了簡單修改如處代碼段所示當開關處於狀態buttonClick,?,ON,con-和顯示可以顯示用戶輸入的全部信息當開關處於狀態tentLabelcontentField,;OFF,和將被隱藏最後還需要調用方法來顯示警告框並contentLabelcontentField。,show,用方法釋放資源release。 運行程序時點擊文本輸入框將推出一個鍵盤提供用戶輸入輸入完成之後我們需,,要將它隱藏起來這就需要調用處的方法程序運行時點擊鍵,?textFieldDoneEditing:,,盤上鍵就能隱藏鍵盤了Return,。 4編譯並運行. 點擊按鈕編譯並運行程序將會出現圖所示的界麵輸入信息並BuildandGo,,6-18,點擊按鈕將彈出圖所示的警告框當點擊開關轉換為狀態時將出現圖,6-20;OFF,6-19所示的界麵此時輸入信息之後點擊按鈕將彈出圖所示的警告框,,,6-21。 624用代碼創建按鈕控件.. 在上兩小節中我們都是利用設計程序界麵要在視圖中添加一個,InterfaceBuilder,控件非常簡單但上述方式需要在和之間來回切換操作比較繁,XcodeInterfaceBuilder,瑣本小節我們將介紹構建界麵的另一種方式用代碼實現下麵的。———,ControlWith-程序就是使用代碼在界麵上添加一個Code,Button。 本程序的主要步驟如下: 創建項目修改文件·,ControlWithCodeViewController.h;修改文件在主視圖上創建一個按鈕·ControlWithCodeViewController.m,;編譯並運行·。 1031.創建項目,修改ControlWithCodeViewController.h文件打開使用模板創建一個新項目並將其命名為Xcode,View-basedApplication,Con-選中文件在文件中添加如下黑體trolWithCode。ControlWithCodeViewController.h,字所示的代碼: 代碼文件6.7ControlWithCodeViewController.h#import@interfaceControlWithCodeViewControllerUIViewControllerUIButtonmyButton*? propertynonatomicretainUIButtonmyButton@*@end注意在處我們聲明了一個類型的變量但是並沒有使用關:?UIButtonmyButton,鍵字因為這裏不會用到IBOutlet,InterfaceBuilder。 2修改ControlWithCodeViewController.m文件,在主視圖上創建一個按鈕. 選中文件需要在文件中用代碼創建一個按ControlWithCodeViewController.m,鈕同時為它指定類型和標題具體代碼如下,,:代碼文件6.8ControlWithCodeViewController.m#import\"ControlWithCodeViewControllerh\"@implementationControlWithCodeViewControllersynthesizemyButton@ -voidviewDidLoadCGRectframe=CGRectMake1050f1500f1000f500f? myButton=UIButtonbuttonWithTypeUIButtonTypeRoundedRect? myButtonsetTitle@\"ClickMe\"forStateUIControlStateNormal? myButtonframe=frame? selfviewaddSubviewselfmyButton? superviewDidLoad-voiddeallocmyButtonreleasesuperdealloc@end104在方法中我們首先在處創建一個矩形區域用來定位按鈕的viewDidLoad,?frame,位置和大小其中的參數分別為矩形框的橫坐標縱坐標寬和高在處將賦給,、、,?,frame了按鈕在處為文件中聲明的按鈕實例指定類型屬性是的一個重要;?,TypeUIButton屬性在中當這條語句寫到時按下鍵將會出現如圖,Xcode,UIButtonType,Esc,6-24所示的提示框你可以根據需要選擇不同的按鈕類型在處設置了按鈕的標題和狀態,;?,同樣這條語句寫到時按下鍵會出現如圖的提示框裏麵包,UIControlState,Esc,6-25,含了按鈕的多種狀態這裏我們設置了按鈕正常狀態下顯示的標題最後一定不要忘了,;,使用處的方法將加載到視圖中?addSubview:myButton。 圖類型圖狀態6-24Button6-25Button3編譯並運行. 到目前為止用代碼創建按鈕程序就算完成了,。 點擊圖標編譯並運行程序將出現如圖BuildandGo,,所示的效果6-26。 從圖中看到創建的按鈕和實例中的按,MyButton鈕是一樣的但是點擊按鈕時卻不會有任何效果那,,,是因為沒有為按鈕製定任何操作方法如果想讓程序。 變得更豐富點可以嚐試著用代碼再創建一個標簽並,,添加相應的操作方法就能達到前麵小節程序的效果, 了想想看該怎麼實現,。 625其他控件.. 前麵已經詳細介紹了RoundRectButton、Text等控件再次打開選擇Field、Switch,InterfaceBuilder,調出窗口或使用快捷鍵Tools→Library,Library(+可以看到窗口提供了各種各樣的控Shift+L),Library件這些控件主要來自框架,iPhoneUIKit(iPhoneUI-是用於創建應用程序用戶界麵的框架以下列舉圖用代碼創建按鈕程序的Kit)。6-26了部分控件和它的作用運行效果: SegmentedControl分段控件由多個組成各個部分可看成相對獨立的按,,segment,鈕 。 Slider滑塊控件主要用於標識某個對象的變化我們會在本書第章用戶設置中,,。10105介紹這個控件的使用。 ProgressView進度條用來描述任務的進度值在與之間變化,,,0.01.0。 ActivitIndicatorView活性指示器旨在將當前任務的進度反饋給用戶y,,。 PageControl頁麵控製器應用程序可能有若幹頁在頁與頁之間切換時,,iPhone,,控件使用一個高亮的指示當前頁PageControldot。 63自定義視圖. 在上一節中我們創建了應用程序程序的初始界麵如圖所示仔細,Controls,6-18。 觀察可以發現界麵上有三組對應的和控件並且它們的創建方式也相,LabelTextField,同這就造成了代碼上的冗餘將影響程序的運行速度這裏我們將介紹更常用的創建,,。 方法自定義視圖它在應用程序中使用得非常廣泛———,iPhone。 自定義視圖就是創建一個自定義的視圖類並在其他的視圖控製器中使用它的實例, 對象來加載視圖從而實現代碼重用,。 這一節我們將用自定義視圖方法創建一個自定義的視圖並用它實現程,,Controls序 。 631創建自定義視圖.. 1創建自定義視圖類. 使用打開程序我們需要添加幾個新的文件展開文件(1)XcodeControls,,Classes夾點擊右鍵選擇如圖所示,Add→NewFile,6-27。 圖添加新文件6-27在彈出的對話框中選擇層級下的模板(2),CocoaTouchClassObjective-Cclass,106並確保選擇為如圖所示點擊按鈕將文件命名為SubclassofUIView,6-28。Next,這時文件夾下多了兩個新的文件和CustomView。Classes:CustomView.hCustom-View.m。 圖創建自定義視圖類6-28接著在文件夾下新建一個文件展開文件夾點擊右(3)ResourcesXib。Resources,鍵選擇在對話框中選擇層級下的Add→NewFile,NewFileUserInterfaceViewXIB,如圖所示同樣命名為6-29,CustomView。 圖創建文件6-29Xib107這樣文件就添加完畢了其中文件下的是我們要實現的自,。ClassesCustomView定義視圖類而下的是對應的視圖,ResourcesCustomView.xib。 2修改自定義視圖類代碼. 在中選中添加如下黑體字所示的代碼XcodeCustomView.h,:代碼文件6.9CustomView.h#import@interfaceCustomViewUIViewIBOutletUILabellabelCustom* IBOutletUITextFieldtextfieldCustom* propertynonatomicretainUILabellabelCustom@*propertynonatomicretainUITextFieldtextfieldCustom@*@end點擊保存修改然後選中文件添加如下黑體字所示的代碼,CustomView.m,:代碼文件6.10CustomView.m#import\"CustomViewh\"@implementationCustomViewsynthesizelabelCustom@ synthesizetextfieldCustom@ -voiddealloclabelCustomreleasetextfieldCustomreleasesuperdealloc@end在創建的自定義視圖類中我們聲明了一個類型的輸出口和,UILabellabelCustom一個類型的輸出口在程序中將重用它們UITextFieldtextfieldCustom,。 3構建自定義視圖界麵. 雙擊文件打開構建自定義視圖界麵選擇CustomView.xib,InterfaceBuilder,。Xib窗口下的圖標按下打開窗口將設為如圖View,+4,Identity,ClassCustomView,所示6-30。 108圖視圖的窗口圖視圖的窗口6-30Identity6-31Attributes按下打開的窗口並將設置為如圖+1,ViewAttributes,StatusBarNone,6-31所示因為程序的主視圖已經默認加載了所以在自定義視圖中不需要顯示。StatusBar,狀態欄按下鍵打開窗口給設置適當的尺寸寬度設為;+3,Size,CustomView,300,高度設為如圖所示49,6-32。 圖視圖的窗口6-32Size109接下來需要在自定義視圖中添加控件選擇或使用快捷鍵,。Tools→Library(+從中拖出一個和一個到中調整它們的大小Shift+L),LibraryLabelTextFieldView,、位置如圖所示,6-33。 圖自定義視圖的界麵6-334連接輸出口. 選中窗口中的圖標注意選擇的是圖標而不是File?sCustomView.xibView(ViewOwner圖標按住鼠標右鍵拖動鼠標到視圖中的上釋放右鍵選中),,Label,,labelCustom輸出口使用同樣的方法將輸出口連接到控件;textfieldCustomTextField。 632使用自定義視圖.. 上一小節我們已經創建了一個自定義的視圖現在就可以把它應用到CustomView,程序中了Controls。 程序的大致步驟如下: 修改程序界麵·;修改文件引入自定義視圖·ControlsViewController.h,;修改文件使用自·ControlsViewController.m,定義視圖; 編譯並運行程序·。 1修改程序界麵.Controls雙擊文件打開ControlsViewController.xib,In-刪除視圖上的所有和terfaceBuilder。LabelText控件隻留下開關和按鈕控件如圖所示Field,,6-34。 此外我們還要另外添加一個按鈕它是為了取消用戶,,輸入時彈出的鍵盤從中拖出一個。LibraryRoundRe-到中按下打開窗口將寬ctButtonView,+3,Size,設為高設為選中按鈕按下打開320,460;,+1,At-窗口將按鈕的類型從改為tributes,RoundRectCus-再從菜單中選擇tom;LayoutSendtoBack。 2修改ControlsViewController.h文件,引入自定. 義視圖圖調整後的界麵6-34選中文件我們需要對此文件做以下修改ControlsViewController.h,:110代碼文件6.11ControlsViewController.h#importimport\"CustomViewh\"#? @interfaceControlsViewControllerUIViewControllerIBOutletUITextField*topicIBOutletUITextField*formIBOutletUILabel*contentLabelIBOutletUITextField*contentFieldIBOutletUISwitch*contentSwitchCustomViewtopicViewù*úCustomViewformViewú*ú? CustomViewcontentView? *@propertynonatomicretainUITextField*topic@propertynonatomicretainUITextField*form@propertynonatomicretainUILabel*contentLabel@propertynonatomicretainUITextField*contentField@propertynonatomicretainUISwitch*contentSwitchpropertynonatomicretainCustomViewtopicView@*propertynonatomicretainCustomViewformView@*propertynonatomicretainCustomViewcontentView@*-IBActionhidden-IBActionbuttonClick-IBActiontextFieldDoneEditingidsenderIBActionbackgroundpressedidsender-? @end首先在處我們引入了自定義視圖類頭文件其次在處聲明了,?CustomView.h;,? 三個的實例對象對應著原來的三組和控件最後我們CustomView,LabelTextField;,刪除方法添加了一個取消彈出鍵盤的操作方法textFieldDoneEditing:,?。 3.修改ControlsViewController.m文件,使用自定義視圖選中文件對它做以下修改ControlsViewController.m,:代碼文件6.12ControlsViewController.m#import\"ControlsViewControllerh\"@implementationControlsViewController111@synthesizetopic@synthesizeform@synthesizecontentLabel@synthesizecontentField@synthesizecontentSwitchsynthesizetopicView@ synthesizeformView@ synthesizecontentView@ -IBActionhiddenifselfcontentSwitchisOnselfcontentLabelsetHiddenNOselfcontentFieldsetHiddenNOCGRectcontentFrame=CGRectMake00f2000fùú 3200f490fúú NSArraythirdView=NSBundlemainBundle*úloadNibNamed@\"CustomView\"úú ownerselfúotionsnilúpúselfcontentView=thirdViewobjectAtIndex0úú selfcontentViewlabelCustomtext=@\"內容\"ú selfcontentViewframe=contentFrameú? úselfcontentViewbackground=UIColorclearColorúú selfviewaddSubviewselfcontentViewú úú úelseúselfcontentLabelsetHiddenYESúú selfcontentFieldsetHiddenYESúselfcontentViewremoveFromSuperview? -IBActionbuttonClickNSString*stringTopic=selftopictextNSString*stringForm=selfformtextNSString*stringContent=selfcontentFieldtext112NSStringstringTopicselftopicViewtextfieldCustomtextù*=úNSStringstringFormselfformViewtextfieldCustomtextú*=ú? NSStringstringContentselfcontentViewtextfieldCustomtext? *=UIAlertView*alertifselfcontentSwitchisOn顯示信息alert=UIAlertViewallocinitWithTitle@\"\"messageNSString標題stringWithFormat@\"%@ 類型內容%@ %@\"stringTopicstringFormstringContentdelegatenil確定cancelButtonTitle@\"\"otherButtonTitlesnilelse顯示信息alert=UIAlertViewallocinitWithTitle@\"\"messageNSString標題stringWithFormat@\"%@ 類型%@\"stringTopicstringFormdelegatenil確定cancelButtonTitle@\"\"otherButtonTitlesnilalertshowalertrelease-IBActiontextFieldDoneEditingidsendersenderresignFirstResponderIBActionbackgroundpressedidsenderù-úselftopicViewtextfieldCustomresignFirstResponderúú selfformViewtextfieldCustomresignFirstResponder? úselfcontentViewtextfieldCustomresignFirstResponder? -voidviewDidLoadifselfcontentSwitchisOn113selfcontentLabelsetHiddenYESselfcontentFieldsetHiddenYES請輸入相關信息selftopicplaceholder=@\"\"請輸入相關信息selfformplaceholder=@\"\"請輸入相關信息selfcontentFieldplaceholder=@\"\"CGRecttopicFrame=CGRectMake00f250f3200f490fùú NSArrayfirstView=NSBundlemainBundleú*úloadNibNamed@\"CustomView\"úownerselfúú optionsnilúú selftopicView=firstViewobjectAtIndex0ú selftopicViewlabelCustomtext=@\"標題\"úú selftopicViewframe=topicFrameúselftopicViewbackground=UIColorclearColorúú selfviewaddSubviewselftopicViewúú? CGRectformFrame=CGRectMake00f950f3200f490fúNSArraysecondView=NSBundlemainBundleú*úloadNibNamed@\"CustomView\"úownerselfúú optionsnilúú selfformView=secondViewobjectAtIndex0ú selfformViewlabelCustomtext=@\"類型\"úú selfformViewframe=formFrameúú selfformViewbackground=UIColorclearColorú selfviewaddSubviewselfformView? superviewDidLoad-voiddealloctopicreleaseformreleasecontentLabelreleasecontentFieldreleasecontentSwitchreleasetopicViewreleaseformViewrelease114contentViewreleasesuperdealloc@end下麵我們來看一下文件中變動的地方ControlsViewController.m。 變動之一處的方法語句的判斷條件沒有發生改變仍然是開關的狀:?hidden,if,態隻不過添加控件的方式改變了原來是通過控製控件的可見性來改變視圖現在通過,,,控製自定義視圖的加載來改變視圖當開關狀態為時使用如下黑體代碼創建一個。ON,自定義視圖對象並使用方法加載自定義視圖設置視圖屬性,addSubview:,frame、back-屬性以及的屬性當開關狀態為時調用groundlabelCustomtext;OFF,removeFromSu-方法移除自定義視圖perview。 NSArraythirdViewNSBundlemainBundle*=[[]loadNibNamed\"CustomView\":@ownerself: otionsnilp:];self.contentView=thirdViewobectAtIndex0[j:];變動之二處的代碼表示通過自定義視圖對象來獲取用戶輸入的相關信息:?。 變動之三我們刪除了取消鍵盤的方法在處添加了一個:textFieldDoneEditing:,? 方法這是我們介紹的又一種取消鍵盤的方法程序運行時點擊視backgroundpressed:,。,圖中沒有控件的區域都將觸發這個操作從而關閉鍵盤,。 變動之四在方法中在代碼段中重用了兩次自定義視圖首先創建:viewDidLoad,?,一個用於設定視圖的位置和大小然後加載了可重用的視圖單元並將它賦給了frame,,自定義視圖實例對象最後使用方法在主視圖上添加子視圖,addSubview:。 4連接操作方法. 代碼添加完成之後還需要返回將控件和相應的方法連接起來,InterfaceBuilder,。 選擇開關控件按下打開窗口選擇事件按住鼠標,+2,Connections,ValueChanged,左鍵拖動至上選中方法即可同時將保存按鈕和背景按鈕的File?sOwner,hidden;“”事件分別與操作方法和操作方法連TouchUpInside,buttonClickbackgroundpressed:接 。 5編譯並運行程序. 一切工作完成之後點擊圖標編譯並運行程序效果如圖所示,BuildandGo,,6-18,點擊開關便會出現如圖所示的效果用戶輸入信息之後點擊按鈕效果如圖,6-19,,,6-20和圖所示6-21。 11564小結. 到目前為止你應該對開發有了進一步的了解了,iPhone。 通過本章的學習我們應當可以解決以下問題,:如何創建一個簡單的程序並掌握控件的使用(1)iPhone,;理解和的作用如何為控件連接輸出口和操作方法(2)IBOutletIBAction,;如何使用代碼創建簡單的控件(3);如何用自定義視圖實現代碼的重用自定義視圖為我們提供了一種不同的視圖(4),創建方法也提供了另一種編程體驗,。 本章介紹的是開發的基礎知識需要我們認真地弄懂每一個知識點為後麵iPhone,,章節的學習打好基礎。 116第章視圖控製器7 本章內容自定義視圖控製器■ 豐富多彩的動畫效果■ 導航控製器■ 標簽欄控製器■ 表視圖控製器■ 前麵章節中曾提到過應用程序界麵通常采用iPhone單窗口多視圖的設計模式中音樂播放器是“-”。iPhone這個模式的一個很好的運用如圖所示支持多視(7-1)。 圖讓能夠擁有更加豐富的功能而單窗口的限製iPhone,又使得程序要不斷地在視圖之間進行轉換對於這樣一。 個擁有多種功能的軟件來說視圖間的轉換是如何實現, 的這就需要用到本章將要講解的內容了?。 71視圖控製器概述. 在開發中視圖控製器起著舉足輕重的作用iPhone,。 任何應用程序都至少有一個視圖控製器對於多視圖應, 用程序每個視圖都有唯一的視圖控製器而一個視圖控,,製器可以控製一個或同時控製多個視圖這些視圖控製。 器共同搭建起應用程序的框架在界麵中顯示出一個視, 圖或實現多個視圖間的轉換。 根據視圖控製器所控製的視圖的數量將其分為單視圖圖音樂播放器視圖,7-1控製器和多視圖控製器兩種。 711單視圖控製器.. 顧名思義單視圖控製器隻控製一個視圖它不僅出現在單視圖應用程序中多視圖,,,應用程序中也經常用到。 第章中所構建的都是單視圖應用程序例如在應用程序中使用的是6,Controls,117模板該模板已經創建了一個視圖控製器View-basedApplication,ControlsViewCon-控製著有多個控件的視圖troller,。 單視圖控製器在多視圖應用程序中更為常見它通常是根視圖控製器的一個子控製, 器在本章節所構建的應用程序中關於視圖就是受單視圖控製器控製著它是。7.4,“”,標簽欄控製器的一個子控製器。 712多視圖控製器.. 在多視圖應用程序中程序由多個內容視圖組成每個視圖都有自己的控製器輸出,,、口和動作視圖之間不斷切換必須要有統一的控製器來控製它們的顯示。,。 視圖控製器是類的一個實例類在框架UIViewController,UIViewControllerUIKit中定義如圖所示,7-2。 圖類7-2UIViewController118從圖可以看出的父類為它有三個子類7-2,UIViewControllerNSObject;:UINavi-分別對應著不同類型的gationController、UITabBarController、UITableViewController,視圖控製器: 是導航控製器類控製多個具有層次關係的視圖是構(1)UINavigationController,,建分層應用程序的主要工具; 是標簽欄控製器類它用於管理多個具有相對獨立關係的(2)UITabBarController,視圖用戶可以在不同視圖之間切換每一個視圖代表著不同的運行模塊,,;是表視圖控製器類它用於顯示數據列表可以被配置(3)UITableViewController,,成所需的任何形式是用來顯示數據的最常用的機製,。 上述三種視圖控製器類是框架提供的視圖控製器類我們還可以直接使用其UIKit,父類定義自己需要的視圖控製器即自定義視圖控製器UIViewController,。 本章中將用三個應用程序分別介紹自定義視圖控製器導航控製器和標簽欄控製、 器前兩個程序都是完成視圖的轉換和數據傳遞的功能隻是實現方式不同第三個程。,;序中我們把導航控製器加在標簽欄控製器中作為其中的一個獨立功能模塊最後簡單,。 介紹了一下表視圖控製器它作為最常用的視圖控製器我們將在第章中予以詳細介,,8紹 。 7.2ViewController在這一節中我們構建一個基於窗口的應用程序親自創建三個視圖控製器其中,,。 一個控製器作為根視圖控製器控製另外兩個視圖之間的轉換及數據的傳遞,。 模板是所有項目模板中功能最簡單的模板它僅提供一Window-basedApplication,個窗口和一個應用程序委托使用此模板構建應用程序需要自己定義視圖或控製器手。,動創建對象間的連接由於操作的繁瑣性我們很少使用這個模板創建項目不過現。,。 在對於讓我們更加深刻地了解視圖控製器的工作原理這確實是一個不錯的方法,,。 7.2.1構建基於Window的應用程序下麵開始構建這個名為的多視圖應用程序程序的初始界麵如圖NoteController。 所示屏幕的底部是一個工具欄該工具欄右側有一個按鈕在該視圖7-3。(Toolbar),。 以下簡稱輸入視圖上方三個中輸入相關信息單擊轉換按鈕視圖轉換()TextField,“”,為顯示相關信息的視圖以下簡稱顯示視圖如圖所示輸入的信息在對應的三個(),7-4,中被成功讀取出來Label。 119圖程序運行時的輸入視圖圖程序運行時的顯示視圖7-37-4此程序操作比較複雜需要以下步,7:新建基於窗口的項目·NoteController;新建文件及·RootViewController.m、SaveViewController.mShowViewCon-及相應的頭文件troller.m;新建文件和·SaveViewController.xibShowViewController.xib;修改和及·NoteControllerAppDelegate.hNoteControllerAppDelegate.mMain-創建根視圖控製器及Window.xib,Toolbar;修改及·SaveViewController.h、SaveViewController.mSaveViewController.xib,設計輸入視圖; 修改及·ShowViewController.h、ShowViewController.mShowViewController. 設計顯示視圖xib,;修改和實現兩視圖間的轉換·RootViewController.hRootViewController.m,。 1新建基於窗口的項目NoteController. 打開選擇在窗口層級下選擇Xcode,File→NewProject,NewProjectiPhoneOS中的如圖所示點擊按鈕後輸入項ApplicationWindow-basedApplication,7-5,Choose目名稱NoteController。 120圖新建基於窗口的應用程序7-52新建文件RootViewController.m、SaveViewController.m及ShowViewController.m及相. 應的頭文件接下來開始創建所需要的三個視圖控製器單擊窗格中的,。Groups&FilesClas-文件夾單擊右鍵選擇之後出現窗口在該窗口左側選ses,Add→NewFile,NewFile。 擇可以看到大量用於類的模板如圖所示選擇CocoaTouchClass,CocoaTouch,7-6。 不要勾選單擊輸入文件UIViewControllersubclass,WithXIBforuserinterface。Next,名並且確保選中複選框RootViewController.m,Alsocreate“RootViewController.h”,單擊查看中文件夾這時已經增加了兩個新文件Finish。XcodeClasses,:RootViewCon-文件和文件troller.hRootViewController.m。 圖新建一個類7-6UIViewController121重複上述步驟依次創建和文件,SaveViewController.mShowViewController.m,並確保也為這兩個控製器創建了文件.h。 3新建文件SaveViewController.xib和ShowViewController.xib. 本例中輸入視圖和顯示視圖的界麵是在文件中定義的在中右鍵單擊,Xib。Xcode窗格中的文件夾選擇在出現的Groups&FilesResources,Add→NewFile,NewFile窗口左側選擇在右側選擇模板圖標如圖所示輸入文件UserInterface,ViewXIB,7-7。 名即可重複上述步驟創建另一個文件SaveViewController。,XibShowViewCon-troller.xib。 圖新建一個文件7-7Xib4修改NoteControllerAppDelegate.h和NoteControllerAppDelegate.m及MainWin-. dow.xib,創建根視圖控製器及Toolbar所需要的文件已經創建完畢現在需要在它們之間建立關聯搭建好程序的框架,,。 我們從修改文件開始NoteControllerAppDelegate.h:代碼文件7.1NoteControllerAppDelegate.h#importclassRootViewController@ @interfaceNoteControllerAppDelegateNSObjectUIWindow*windowIBOutletRootViewControllerrootViewController* @propertynonatomicretainIBOutletUIWindow*windowpropertynonatomicretain@ 122IBOutletRootViewControllerrootViewController* @end接下來在中添加如下黑體字所示的代碼,NoteAppDelegate.m:代碼文件7.2NoteControllerAppDelegate.m#import\"NoteControllerAppDelegateh\"import\"RootViewControllerh\"# @implementationNoteControllerAppDelegate@synthesizewindowsynthesizerootViewController@ -voidapplicationDidFinishLaunchingUIApplication*applicationOverridepointforcustomizationafterapplicationlaunchwindowaddSubviewrootViewControllerviewwindowmakeKeyAndVisible-voiddeallocwindowreleaserootViewControllerreleasesuperdealloc@end我們在應用程序的委托中聲明了RootViewCon-類的一個實例對象並將trollerrootViewController,根視圖控製器的視圖添加到應用程序的窗口作為它, 的子視圖。 在文件夾下選擇文ResourcesMainWindow.xib件在中將其打開其中有四個圖,InterfaceBuilder。 標:File?sOwner、FirstResponder、NoteController由於沒有視圖控製器需要AppDelegate、Window。,我們自己創建按下打開窗。+Shift+L,Library口如圖所示在窗口中,7-8。Library,CocoaTouch-子項是專門存放控製器的庫前麵講過的Controllers,幾類視圖控製器都在其中在本章後麵會陸續用到它, 們圖中的各類控製器。7-8Library123選中把它拖進ViewController,MainWindow. 中當鼠標旁顯示一個綠色的小加號時放開鼠xib,,標便添加到了結,ViewControllerMainWindow.xib,果如圖所示7-9。 選擇按下打開ViewController,+4,Identity窗口在屬性的下拉列表中選擇,ClassRootViewCon-此時窗口中視圖控製器的troller,MainWindow.xib名稱變為雙擊打開它是一個RootViewController。,灰色的中間顯示一個字樣的窗口這表示該視、View,圖控製器現在處於缺少的狀態再次打開View。Li-拖動一個到窗口圖視圖控製器被添加到文件brary,ViewRootViewController,7-9Xib自動填充整個屏幕右鍵點擊拖拽至View。NoteControllerAppDelegate,RootView-連接輸出口Controller,rootViewController。 程序中有一個工具欄為了能夠控製輸入視圖和顯示視圖間的切換需要將它放置,,在根視圖控製器的視圖中因此從中找到拖到剛才加入的視圖的底。,LibraryToolbar,部默認狀態下工具條中的按鈕是在左邊放置的有一個工具可以將按鈕調整到工具。,,條的右邊將它從中拖至按鈕前麵最後雙擊:FlexibleSpaceBarButtonItem,Library。 按鈕更改按鈕標題為轉換如圖所示,“”,7-10。 圖設計界麵圖界麵中的顯示7-10RootViewController7-11ToolBar124返回編譯並運行程序界麵下方帶按鈕的工具條已經出現了工具條上方的Xcode,。,屏幕卻是白的如圖所示這是由於我們還未定義程序的初始界麵因此我們應先設,7-11,,計輸入視圖和顯示視圖的界麵。 5.修改SaveViewController.h、SaveViewController.m及SaveViewController.xib,設計輸入視圖打開文件添加如下黑體字所示的代碼SaveViewController.h,:代碼文件7.3SaveViewController.h#import@interfaceSaveViewControllerUIViewControllerIBOutletUITextFieldsaveTopic* IBOutletUITextFieldsaveForm* IBOutletUITextFieldsaveContent* propertynonatomicretainIBOutletUITextFieldsaveTopic@*propertynonatomicretainIBOutletUITextFieldsaveForm@*propertynonatomicretainIBOutletUITextFieldsaveContent@*-IBActiontextFieldDoneEditingidsender@end我們聲明了三個類型的輸出口用來輸入消息內容UITextField,。textFieldDone-方法在第章中已經用過當完成輸入時通過點擊鍵盤的鍵取消鍵盤Editing:6,Return。 在中添加如下黑體字所示的代碼SaveViewController.m:代碼文件7.4SaveViewController.m#import\"SaveViewControllerh\"@implementationSaveViewControllersynthesizesaveTopic@ synthesizesaveForm@ synthesizesaveContent@ -IBActiontextFieldDoneEditingidsendersenderresignFirstResponder……-voiddeallocsaveTopicreleasesaveFormreleasesaveContentrelease125superdealloc@end完成了代碼的添加接下來設計輸入視圖的界麵,,。 將所需要的圖片導入文件夾下選中文件夾在上(1)Resources。Resources,Xcode方菜單欄中選擇在打開的提示框中選擇後綴為的兩張圖Project→AddtoProject,.png片和單擊文件夾下顯示了添加的圖saveImage.pngshowImage.png,Add,Resources像 。 雙擊文件打開由於根視圖控製器(2)SaveViewController.xib,InterfaceBuilder。 的視圖中有狀態條高度為和高度為因此我們需要調整(20)Toolbar(44),SaveView-視圖的大小為按下調出窗口將Controller416(480-20-44)。+1,Attributes,Sta-設為後按下調出窗口將該視圖高度設為注意隻有沒tusBarNone,+3,Size,416。,有狀態條的視圖才可以更改其大小。 選擇調出窗口更改其屬性為(3)File?sOwner,Attributes,ClassSaveViewCon-如果忘記了這一步程序在加載文件時將無法連接類troller。,XibSaveViewController。 此時若在上點擊右鍵發現輸出口並未連接選中按住File?sOwner,view,File?sOwner,鼠標左鍵將其拖到圖標上出現輸出口選中即可,View,view,。 接下來在界麵中加入背景圖片按下在中找到(4),。+Shift+L,LibraryImage拖入窗口打開窗口在其屬性的下拉列表中選擇View,View,Attributes,Imagesave-此時中就有了圖像Image.png。,ImageView。 從中拖入三個將它們放到視圖中合適的位置參見圖(5)LibraryTextField,,7-3。 首先將三個分別連接相應的輸出口然後,TextFieldsaveTopic、saveForm、saveContent;按下調出窗口將事件連接+2,Connections,DidEndOnExittextFieldDoneEditing:方法。 完成連接工作後保存關閉返回同樣地對,InterfaceBuilder,Xcode。,ShowView-做相似的操作Controller。 6.修改ShowViewController.h、ShowViewController.m及ShowViewController.xib,設計顯示視圖在中添加如下黑體字所示的代碼ShowViewController.h:代碼文件7.5ShowViewController.h#import@interfaceShowViewControllerUIViewControllerIBOutletUILabelshowTopic* IBOutletUILabelshowForm* IBOutletUILabelshowContent* 126propertynonatomicretainIBOutletUILabelshowTopic@*propertynonatomicretainIBOutletUILabelshowForm@*propertynonatomicretainIBOutletUILabelshowContent@*@end對應地在中修改代碼,ShowViewController.m:代碼文件7.6ShowViewController.m#import\"ShowViewControllerh\"@implementationShowViewControllersynthesizeshowTopic@ synthesizeshowForm@ synthesizeshowContent@ ……-voiddeallocshowTopicreleaseshowFormreleaseshowContentreleasesuperdealloc@end在文件和文件中我們僅聲明了三ShowViewController.hShowViewController.m,個類型的輸出口用於顯示已經存儲的數據UILabel,。 打開在中選擇更改其InterfaceBuilder,ShowViewController.xib,File?sOwner,屬性為將三個拖入視圖中具體設計可參見圖ClassShowViewController。Label,7-4。 為三個分別連接輸出口LabelshowTopic、showForm、showContent。 根視圖控製器控製的兩個視圖設計好後便可以在中定義兩個,RootViewController視圖轉換及數據傳遞的操作了選擇文件添加如下黑體字所示。RootViewController.h,的代碼: 代碼文件7.7RootViewController.h#importclassSaveViewController@ classShowViewController@ @interfaceRootViewControllerUIViewControllerSaveViewControllersaveViewController* 127ShowViewControllershowViewController* propertynonatomicretain@ SaveViewControllersaveViewController* propertynonatomicretain@ ShowViewControllershowViewController* -IBActionswitchViewsidsender@end代碼中引入了兩個視圖的視圖控製器類及一個方法該方法在點擊switchViews:。 上按鈕時被調用因此在中打開窗口Toolbar。,MainWindow.xibRootViewController,為按鈕連接事件所觸發的操作方法TouchUpInsideswitchViews:。 7.修改RootViewController.h和RootViewController.m,實現兩視圖間轉換保存並關閉在中添加如下黑體字所示的InterfaceBuilder,RootViewController.m代碼: 代碼文件7.8RootViewController.m#import\"RootViewControllerh\"import\"SaveViewControllerh\"# import\"ShowViewControllerh\"# @implementationRootViewControllersynthesizesaveViewController@ synthesizeshowViewController@ ……-voidviewDidLoadù SaveViewControllersaveMessageSaveViewControllerallocú*=úinitWithNibName\"SaveViewController\"@úbundlenilúú selfsaveViewControllersaveMessageú? =selfviewaddSubviewsaveViewControllerviewúú saveMessagerelease? superviewDidLoad-IBActionswitchViewsidsenderifselfshowViewControllerviewsuperviewnil==ifselfshowViewControllernil==ShowViewControllershowMessage*=128ShowViewControllerallocinitWithNibName\"ShowViewController\"@ bundlenilselfshowViewControllershowMessage= showMessagereleaseshowViewControllershowTopictextù=úsaveViewControllersaveTopictextúú showViewControllershowFormtext=úsaveViewControllersaveFormtextú? úshowViewControllershowContentshowTopictextú=úsaveViewControllersaveContenttext? saveViewControllerviewremoveFromSuperview? selfviewinsertSubviewshowViewControllerviewatIndex0? elseshowViewControllerviewremoveFromSuperviewselfviewinsertSubviewsaveViewControllerviewatIndex0 -voiddeallocsaveViewControllerreleaseshowViewControllerreleasesuperdealloc@end在方法中處將視圖作為根視圖控製器的視圖出現viewDidLoad?,SaveViewController後第一次載入的視圖方法中的邏輯判斷並不複雜不做過多解釋真正起。switchViews:,。 到視圖間轉換作用的是以下兩個方法通常成對出現處方法用():?removeFromSuperview於將視圖從父視圖移除然後在處使用方法載入另一視圖,?insertSubview:atIndex:。 當顯示為的視圖時點擊按鈕方法會將SaveViewController,switchViews:Text中輸入的值傳遞到中的值並顯示出來兩視圖間的傳FieldShowViewControllerLabel,值在處簡單地實現了?。 返回編譯並運行程序視圖之間實現了切換在輸入視圖中輸入的數據在顯Xcode,。,示視圖中被讀取出來。 129722豐富多彩的動畫效果.. 1加入動畫效果. 至此幾乎所有的工作都完成了視圖之間成功實現了轉換不過並沒有看到明顯,,。,的轉換效果如果在轉換時加入動畫效果程序會變得美觀很多而這並不需要我們做。,,太多的工作在文件中添加如下黑體字所示的代碼。RootViewController.m:代碼文件7.9RootViewController.m-IBActionswitchViewsidsenderUIViewbeginAnimations\"Curve\"contextnil@ UIViewsetAnimationDuration125UIViewsetAnimationCurveUIViewAnimationCurveEaseInOut? ifselfshowViewControllerviewsuperview==nilifselfshowViewController==nilShowViewController*showMessage=ShowViewControllerallocinitWithNibName@\"ShowViewController\"bundlenilselfshowViewController=showMessageshowMessagereleaseselfshowViewControllershowTopictext=saveTopictextselfshowViewControllershowFormtext=saveFormtextselfshowViewControllershowContenttext=saveContenttextUIViewsetAnimationTransitionúùUIViewAnimationTransitionCurlUpúú forViewselfview? úcacheYES? saveViewControllerviewremoveFromSuperviewselfviewinsertSubviewshowViewControllerviewatIndex0elseUIViewsetAnimationTransitionùú UIViewAnimationTransitionCurlDownúú forViewselfview? úcacheYES? showViewControllerviewremoveFromSuperview130selfviewinsertSubviewsaveViewControllerviewatIndex0UIViewcommitAnimations類的幾個方法用來修改動畫的屬性見表UIView,7-1。 表7-1UIView類方法及相應更改的屬性類中的方法動畫的屬性UIView開始位置beginAnimations:context:持續時間setAnimationDuration:動畫速度setAnimationCurve:轉換類型setAnimationTransition:forView:cache:結束位置commitAnimations我們想營造一種前後翻頁的視覺效果因此設置, 轉換動畫時在處由輸入視圖轉化到顯示視圖時使,?,用了向上卷起的動畫而在處由顯示視圖轉換到輸,? 入視圖時使用了向下卷放的動畫為使動畫顯得更,。 加自然在處設置動畫速度時其返回類型為,?,UIVie-使動畫在開始和結束的wAnimationCurveEaseInOut,時候速度較慢中間過程較快運行程序看看效果如,。,圖所示7-12。 除了UIViewAnimationCurveEaseInOut,setAni-方法還有以下幾種返回類型mationCurve::勻速(1)UIViewAnimationCurve:;開始慢後來(2)UIViewAnimationCurveEaseIn:,快 開始快後(3)UIViewAnimationCurveEaseOut:,來慢; 線性動畫效(4)UIViewAnimationCurveLiear:果平坦運行,。 在這組動畫轉換效果中起決定性作用的就是, 方法它除了支持圖翻頁動畫效果setAnimationTransition:,UIView-7-12這組上下翻頁的AnimationTransitionCurlUp\/Down動畫外還支持這組左右翻轉動畫,UIViewAnimationTransitionFlipFromLeft\/Right。 131效果同樣很明顯不妨試一下不過對於想把程序變得更加美觀的我們這些動畫還遠,。,,遠不足下麵我們換一種方式實現更加豐富的動畫效果。。 2更加豐富的動畫效果. 這次要用到框架中類該程序所使用的QuartzCoreCATransition。Window-based模板中沒有引入需要手動把它加入文ApplicationQuartzCore.framework,Frameworks件夾下右鍵選中左側窗格中項下的在菜單。Groups&FilesTargetsNoteController,中選擇打開窗口點擊選項卡下項左下方的加GetInfo,Info。GeneralLinkedLibraries號在出現的列表中選擇點擊如圖所,FrameworksQuartzCore.framework,Add,7-13示 。 圖添加7-13QuartzCore.framework關閉窗口返回你會發現文件夾中已經增加了Info,Xcode,FrameworksQuartz-接下來在中做以下更改Core.framework。,RootViewController.m:代碼文件7.10RootViewController.m-IBActionswitchViewsidsenderUIViewbeginAnimations@\"Curve\"contextnilUIViewsetAnimationDuration125UIViewsetAnimationCurveUIViewAnimationCurveEaseInOutCATransitionanimationCATransitionanimation*=animationsetDurationf125132animationsetTimingFunctionCAMediaTimingFunctionfunctionWithNamekCAMediaTimingFunctionEaseIn? ifselfshowViewControllerviewsuperview==nilifselfshowViewController==nilShowViewController*showMessage=ShowViewControllerallocinitWithNibName@\"ShowViewController\"bundlenilselfshowViewController=showMessageshowMessagereleaseselfshowViewControllershowTopictext=saveTopictextselfshowViewControllershowFormtext=saveFormtextselfshowViewControllershowContenttext=saveContenttextUIViewsetAnimationTransitionUIViewAnimationTransitionCurlUpforViewselfviewcacheYESanimationsetTypekCATransitionReveal? animationsetSubtypekCATransitionFromBottom? selfviewlayeraddAnimationanimationforKey\"Reveal\"@? saveViewControllerviewremoveFromSuperviewselfviewinsertSubviewshowViewControllerviewatIndex0elseUIViewsetAnimationTransitionUIViewAnimationTransitionCurlDownforViewselfviewcacheYESanimationsetType\"suckEffect\"@? selfviewlayeraddAnimationanimationforKey\"suckEffect\"@? showViewControllerviewremoveFromSuperviewselfviewinsertSubviewsaveViewControllerviewatIndex0133類能夠遍曆默認的動畫屬性它也有自己的一些修改動畫屬性的方CATransition,法見表,7-2。 表7-2設置動畫屬性的CATransition類方法類方法動畫屬性CATransition持續時間setDuration:動畫速度setTimingFunction:動畫類型setType:動畫子類型setSubtype:處的方法與方法的作用完全相同都是?setTimingFunction:setAnimationCurve:,設置動畫的速度即何時快何時慢雖然返回類型有所不同但同樣僅支持上麵提及的五,,,種動畫速度樣式。 也許你已經注意到了兩視圖間的轉換在處和處設置動畫類型的方式是不同,?? 的在由輸入視圖轉換到顯示視圖時我們使用了標準的設置動畫類型的方式,,。set-方法支持以下四種動畫類型Type::淡入淡出(1)kCATransitionFade:;新視圖滑入覆蓋原視(2)kCATransitionMoveIn:,圖 推入(3)kCATransitionPush:;原視圖滑出新視圖顯(4)kCATransitionReveal:,現效果如圖所示(7-14)。 還可以設置轉換動畫的方向即在處使用的,?set-方法稱為動畫的子類型它也有四種方式Subtype:,。:(1)kCATransitionFromRight;(2)kCATransitionFromLeft;(3)kCATransitionFromTop;(4)kCATransitionFromBottom。 在處由顯示視圖轉換到輸入視圖時我們使用了?,官方文檔中未定義的動畫類型同樣可以支持,iPhone。 這樣的方式豐富了可用的動畫類型但未經官方發布,,因此並不穩定隨時會被刪除或更改以下是其中的幾,。 種: 三角效果如圖所示(1)suckEffect:(7-15);水波抖動圖轉換到顯示視圖時的(2)rippleEffect:;7-14上翻頁效果同圖動畫效果(3)pageCurl:(7-12);134下翻頁(4)pageUnCurl:;上下翻轉(5)oglFlip:。 最後處方法將剛剛定義的動,?addAnimation:forKey:畫加到視圖的層上請注意與不同。,UIView,CATransition作用於層而不是視圖本身是視圖的屬性之一一個,。layer,視圖上允許很多個層的疊加比起視圖層可以有更複雜的。,轉換比如旋轉傾斜放大縮小等,、、、。 7.3NavigationController上一節我們認識了多視圖應用程序的結構並自定義了,,一個多視圖控製器在很多應用程序中屏幕上方都。iPhone,會有一個導航條如圖所示點擊右上角的導航按鈕,7-16。,切換到播放列表視圖如圖所示這就是多視圖間轉圖轉換到輸入視圖的“”,7-17。7-15換的另一種重要的實現方式導航控製器動畫效果:。 是用於構建分層應用程序的主要工具使程序能夠在具有層次NavigationController,關係的視圖間不斷切換像音樂播放器這樣的多視圖應用程序一部分視圖會具有某種。,層次關係由直接管理另一部分受控於導航控製器的子視圖控製,NavigationController,器或根視圖控製器。 圖音樂播放器中的導航控製器圖轉換到正在播放視圖7-167-17“”135731控製器棧.. 是作為棧來實現的棧是一種常用的數據結構采用先進UINavigationController。,後出的原則向棧中添加對象稱為入棧從棧中刪除對象稱為出棧根據先進後出的原。,。 則第一個進棧的最後一個出棧最後一個進棧的第一個出棧,,。 導航控製器控製一個視圖控製器棧在這個棧中存放著應用程序所有的視圖控製, 器在設計導航控製器時你需要指定應用程序運行時的第一個視圖在程序的整個視。,,圖層次中這個視圖位於底層而它對應的控製器就是根控製器當用戶選擇查看下一,,。 個視圖時控製器棧中加入一個新的對象這些新的對象稱為子控製器相信你已經注,,。 意到圖所示的視圖左上方的按鈕了這個按鈕用於由子控製器視圖切換到父控製器7-17,視圖導航控製器控製的每個子視圖中都有相應的返回按鈕返回按鈕可以讓程序在。,,父視圖和子視圖之間切換隨著程序的運行棧中的控製器對象不斷進棧出棧。,。 我們將要構建的這個程序實現的效果還是數據的傳遞和視圖的切換程序比較簡,,單是由兩個控製器構成一個充當根控製器另一個充當子控製器,,,。 7.3.2構建應用程序NoteNav該程序仍然實現程序中的功能隻不過這次用導航控製器的方式實NoteController,現最終效果如圖所示在輸入視圖中輸入相關信息點擊屏幕右上方的提交按,7-18。,“”鈕進入下級的顯示視圖如圖所示之前輸入的文字在該視圖中顯示出來,,7-19,。 圖程序運行時的根視圖圖程序運行時的子視圖7-187-19136為創建基於導航控製器的應用程序提供了一個很好的模板該模板已經建立Xcode,了一個導航控製器無需我們自己創建不過手動創建一個導航控製器更有助於我們,。,理解其工作機製因此本例中我們將繼續使用基於窗口的應用程序模板,。 打開新建一個將它命名為與Xcode,Window-basedApplication,NoteNav。Note-程序結構不同的是我們將作為根控製器將Controller,SaveViewController,ShowView-作為子控製器Controller。 首先創建根控製器右鍵點擊選擇在出現的向導中選擇,,ClassesAdd→NewFile,下的本例中我們選擇自動創建相應CocoaTouchClassUIViewControllersubclass。Xib文件因此應選中複選框單擊將此文件命名為,WithXIBforuserinterface,NextSave-確保選中創建頭文件的複選框此時窗格中ViewController.m,。,Groups&FilesClas-文件夾下新增了三個以命名的不同類型的文件用同樣的方式sesSaveViewController。 創建子視圖控製器的三個文件ShowViewController。 接下來我們為程序添加導航控製器選擇文件添加如下,。NoteNavAppDelegate.h,黑體字所示的代碼: 代碼文件7.11NoteNavAppDelegate.h#import@interfaceNoteNavAppDelegateNSObjectUIWindow*windowIBOutletUINavigationControllernavController* @propertynonatomicretainIBOutletUIWindow*windowpropertynonatomicretain@ IBOutletUINavigationControllernavController* @end在文件中添加如下黑體字所示的代碼NoteNavAppDelegate.m,:代碼文件7.12NoteNavAppDelegate.m#import\"NoteNavAppDelegateh\"@implementationNoteNavAppDelegate@synthesizewindowsynthesizenavController@ -voidapplicationDidFinishLaunchingUIApplication*applicationwindowaddSubviewnavControllerviewwindowmakeKeyAndVisible137-voiddeallocnavControllerreleasewindowreleasesuperdealloc我們定義了一個類型的輸出口並將導航控製器的視圖添UINavigationController,加到應用程序的窗口作為它的子視圖,。 雙擊下的文件與添加相似在庫中拖ResourcesMainWindow.xib,ViewController,入一個我們要將這個導航控製器的實例和剛才聲明的NavigationController。navCon-連接起來用鼠標右鍵點擊拖拽至troller。NoteNavAppDelegate,NavigationControl-上釋放鼠標會出現一個輸出口將其選中ler,navController,。 導航控製器必須要指定根控製器在窗口中展開,MainWindow.xibNavigationCon-可以看到兩個子項和選中圖troller,:NavigationBarViewController。ViewController標按下打開窗口將其屬性更改為此時,+4,Identity,ClassSaveViewController,變為打開窗口在屬性下ViewControllerSaveViewController。Attributes,NIBName拉列表中選擇在本例中這一操作是可選的因為SaveViewController,,SaveViewCon-的文件是自動生成的已指定其類為trollerXib,SaveViewController。SaveViewCon-有一個子項打開窗口將屬性設為請輸入相trollerNavigationItem,Attributes,Title“關信息”。 保存並關閉如果此時運行程序一個標題為請輸入相關信息的InterfaceBuilder,,“”導航條會出現在界麵的上方這個視圖就是根控製器的視圖由。SaveViewController。 於還未設計輸入視圖的界麵因此顯示為空,。 在中打開文件添加如下黑體字所示的代碼XcodeSaveViewController.h,:代碼文件7.13SaveViewController.h#import@classShowViewController@interfaceSaveViewControllerUIViewControllerIBOutletUITextField*saveTopicIBOutletUITextField*saveFormIBOutletUITextField*saveContentShowViewControllershowViewController* @propertynonatomicretainIBOutletUITextField*saveTopic@propertynonatomicretainIBOutletUITextField*saveForm138@propertynonatomicretainIBOutletUITextField*saveContentpropertynonatomicretain@ ShowViewControllershowViewController* -IBActiontextFieldDoneEditingidsender-IBActionsaveMessage@end上述文件中我們創建了顯示視圖的一個實例並聲明了一個,showViewController,方法在點擊導航控製器右側按鈕時被調用saveMessage,。 打開界麵設計如圖所示SaveViewController.xib,7-20。 圖界麵設計7-20SaveViewController.xib界麵設計的具體操作步驟可參見程序中的描述這裏不再重述也NoteController,。 許你已經發現本例中的背景圖片改變了沒有了上方的提示信息這個提示信息顯示,,。 在了導航條的標題上因此在引入圖片時應選擇文件在兩個視圖。,messageImage.png,中重用。 分別打開三個的窗口點擊事件後的小圓TextFieldConnections,DidEndOnExit圈拖拽到連接方法此事件在按下鍵盤右下角File?sOwner,textFieldDoneEditing:。Re-鍵時觸發turn。 接下來修改文件,SaveViewController.m:代碼文件7.14SaveViewController.m#import\"SaveViewControllerh\"#import\"ShowViewControllerh\"@implementationSaveViewController139@synthesizesaveTopic@synthesizesaveForm@synthesizesaveContent@synthesizeshowViewController-IBActiontextFieldDoneEditingidsendersenderresignFirstResponder-IBActionsaveMessageShowViewController*showMessage=ShowViewControllerallocinitWithNibName@\"ShowViewController\"bundlenilautoreleaseselfshowViewController=showMessageselfnavigationControllerpushViewControllershowViewControlleranimatedYES? selfshowViewControllershowTopictext=saveTopictextselfshowViewControllershowFormtext=saveFormtextselfshowViewControllershowContenttext=saveContenttext……-voidviewDidLoadUIBarButtonItemsaveButtonUIBarButtonItemallocúù*=úinitWithTitle\"提交\"@ústyleUIBarButtonItemStyleDoneúú targetselfú? actionselectorsaveMessageú@úselfnavigationItemrightBarButtonItemsaveButton? =superviewDidLoad-voiddeallocsaveTopicreleasesaveFormreleasesaveContentreleaseshowViewControllerreleasesuperdealloc@end140程序中在處方法創建了導航條上右側的按鈕使用,?viewDidLoad,initWithTitle:方法定義了按鈕的標題類型對象及事件style:target:action:、、。 點擊提交按鈕時調用方法在該方法中首先初始化了saveMessage,,ShowViewCon-並在處使用方法將子控troller,?pushViewController:animated:ShowViewController製器推入控製器棧從而進入子視圖最後將中輸入的信息顯示在中,。TextFieldLabel。 打開文件添加以下代碼ShowViewController.h,:代碼文件7.15ShowViewController.h#import@interfaceShowViewControllerUIViewControllerIBOutletUILabel*showTopicIBOutletUILabel*showFormIBOutletUILabel*showContent@propertynonatomicretainIBOutletUILabel*showTopic@propertynonatomicretainIBOutletUILabel*showForm@propertynonatomicretainIBOutletUILabel*showContent@end在中打開文件設計子視圖界麵如圖InterfaceBuilderShowViewController.xib,,所示不要忘了為三個連接輸出口7-21,Label。 圖界麵設計7-21ShowViewController141在中添加如下黑體字所示的代碼ShowViewController.m:代碼文件7.16ShowViewController.m#import\"ShowViewControllerh\"@implementationShowViewController@synthesizeshowTopic@synthesizeshowForm@synthesizeshowContent-idinitWithNibNameNSString*nibNameOrNilbundleNSBundle*nibBundleOrNilifself=superinitWithNibNamenibNameOrNilbundlenibBundleOrNilCustominitializationselftitle顯示相關信息=@\"\"returnself……-voiddeallocshowTopicreleaseshowFormreleaseshowContentreleasesuperdealloc@end方法在根控製器initWithNibName:bundle:saveMes-方法中初始化顯示視圖時被調用我們僅僅設置了子sage:,視圖中導航條的標題。圖視圖間轉換效果運行程序看看效果視圖間的轉換如圖所示7-22,7-22。 ?? ?????????????????????????? ?? ?在此應謹記一點:必須先將視圖控製推入棧才可? ?? ????????????????????????? ? 以成功傳遞數據?。? 1427.4TabBarController前麵我們分別用自定義視圖控製器和導航控製器的方式實現了兩個視圖之間的切換和數據傳遞這一節我們再介紹一種新的方式標簽欄控製器,:TabBarController()。 7.4.1TabBarController概述上的應用程序很多都使用了標簽欄作為根控製器來控iPhone,TabBarController製各個子控製器各子控製器之間是相互獨立的實現不同的功能如果一個應用程序,,。 有若幹功能獨立的模塊是個非常好的選擇,TabBarController。 如圖所示在音樂播放器應用程序中播放列表歌曲表演者專輯等這些相互7-23,,、、、獨立的功能以標簽的形式放置在屏幕的下方點擊標簽實現視圖間的切換如圖所,,,7-24示 。 圖音樂播放器中的標簽欄控製器圖轉換到播放列表視圖7-237-24“”同音樂播放器一樣在應用程序中經常和,iPhone,TabBarControllerNavigation結合起來使用使程序更加具有層次性圖展示了標簽欄控製器和導航Controller,。7-25控製器結合使用時的層次關係本節的程序就是用這種方式構建的。NoteTab,。 143圖標簽欄控製器與導航控製器結合使用7-257.4.2構建應用程序NoteTab沒有提供基於標簽欄的應用程序模板所以我們必須自己搭建程序的主框Xcode,架實現兩個相互獨立的功能記錄功能和關於功能我們把上節程序實,:“”“”。NoteNav現的功能完全移植到了本程序中的記錄功能模塊如圖和圖所示關於“”,7-267-27。“”功能提供該軟件的介紹信息如圖所示雖然僅顯示了一張圖片但不要小看它幾,7-28。,,乎所有在上發布的軟件的版本信息版權聲明等都會選擇用這種方式表達出AppStore、來 。 圖程序運行時的輸入視圖圖程序運行時的顯示視圖7-267-27打開使用模板創建一個新項目將其命名為Xcode,Window-basedApplication,No-通過前麵兩個程序的學習也許你已經輕車熟路知道我們下一步要做些什麼teTab。,,了打開文件添加如下黑體字所示的代碼。NoteTabAppDelegate.h,:144代碼文件7.17NoteTabAppDelegate.h#import@interfaceNoteTabAppDelegateNSObjectUIWindow*windowIBOutletUITabBarControllertabController* @propertynonatomicretainIBOutletUIWin-dow*windowpropertynonatomicretain@ IBOutletUITabBarControllertabController* @end該文件中聲明了一個類型的輸UITabBarController出口命名為在,tabController。NoteTabAppDelegate.m文件中添加如下黑體字所示的代碼圖程序運行時的關於視圖,:7-28“”代碼文件7.18NoteTabAppDelegate.m#import\"NoteTabAppDelegateh\"@implementationNoteTabAppDelegate@synthesizewindow@synthesizetabController-voidapplicationDidFinishLaunchingUIApplication*applicationwindowaddSubviewtabControllerviewwindowmakeKeyAndVisible-voiddealloctabControllerreleasewindowreleasesuperdealloc@end首先在程序中把標簽欄控製器視圖加載到程序的主窗口中與前麵,,ViewController和作為窗口的子視圖采用了相同的方法NavigationController。 接下來要在中創建一個標簽欄的實例在中打,InterfaceBuilder。InterfaceBuilder145開從窗口中找到拖入MainWindow.xib,LibraryTabBarController,MainWindow.xib窗口中右鍵選擇把它拖到上連接。NoteTabAppDelegate,TabBarController,tab-輸出口Controller。 雙擊圖標打開如圖TabBarController,7-29所示可以看到視圖下方的標簽欄默認標簽有。,,兩項保存並關閉返回。InterfaceBuilder,Xcode中 。 我們要新建四個視圖控製器的子類分別命名, 為NavViewController、SaveViewController、和作ShowViewControllerAboutViewController。 為記錄功能的根控製器不需,NavViewController創建文件其餘三個視圖控製器的子類在創建Xib,時應勾選複選框以便WithXIBforuserinterface,同時創建相應的文件Xib。 在文件夾下增加了個文件後還需Classes11,要將本程序所需的四個圖片加入文件夾Resources下作為記錄功能視圖中的:messageImage.png“”背景圖片在關於功能中會用;aboutImage.png“”到和是記錄和關於功圖的視圖;record.pngabout.png“”“”7-29UITabBarControllerview能對應的兩個標簽上的圖像。 重新打開文件在MainWindow.xib,TabBar窗口中選擇第一個視圖控製器注意Controller(:單擊鼠標第一次選中的是控製器如果在其圖標上, 再次點擊一下選中的是這個標簽調出,Item1)。 窗口更改其屬性為Identity,ClassNavViewCon-同時在窗口中你也可以為其指troller,Attributes定一個文件這裏我們保留這個屬性為空選Xib,。 中第二個視圖控製器更改其屬性為,ClassAbout-ViewController。 接下來兩次單擊間隔秒第一個標簽調出(1),的窗口將它的標題設為TabBarItemAttributes,記錄在屬性的下拉列表中選擇“”,Imagerecord. 作為圖像同樣地更改第二個標簽的屬性將png,,,其標題設為關於圖像為“”,about.png。 調整之後的標簽欄控製器視圖如圖所7-30示 。 這一次我們選擇用代碼在記錄功能的根控圖添加標題和圖片後的標簽欄“”7-30146製器中添加導航條在中添加如下黑體字所示的代碼。NavigationController.h:代碼文件7.19NavViewController.h#import@interfaceNavViewControllerUIViewControllerUINavigationControllernavController* propertynonatomicretain@ UINavigationControllernavController* @end在該文件中聲明了一個的實例而且不需要輸出口接下來NavigationController,。,在文件中添加如下黑體字所示的代碼NavViewController.m:代碼文件7.20NavViewController.m#import\"NavViewControllerh\"import\"SaveViewControllerh\"@implementationNavViewControllersynthesizenavController@ ……-voidviewDidLoad自定義NavigationSaveViewControllersaveController*=SaveViewControllerallocinitWithNibName\"SaveViewController\"@ bundlenilUINavigationControllernavUINavigationControlleralloc*=initWithRootViewControllersaveControllerselfnavControllernav= selfviewaddSubviewselfnavControllerviewsuperviewDidLoad……-voiddeallocnavControllerreleasesuperdealloc@end147首先定義了一個的實例然後使用,SaveViewControllersaveController,initWithRo-方法將它作為導航控製器的根控製器最後將這個創建的導航控製器otViewController:,的視圖加載到根視圖這樣在記錄功能中便有了一個導航控製器並且它的根控製。,“”,器為主視圖為輸入視圖SaveViewController,。 和的頭文件和執行文件中代碼添加與SaveViewControllerShowViewController程序幾乎完全相同你可以將代碼複製並粘貼到此程序中這是提高效率的一NoteNav,,個不錯的方法唯一不同的是主視圖中導航控製器的標題不是在窗口中更。,Attributes改的而是在文件中因此應添加如下黑體字所示的語句到,SaveViewController.m,文件SaveViewController.m:代碼文件7.21SaveViewController.m-idinitWithNibNameNSString*nibNameOrNilbundleNSBundle*nibBundleOrNilifself=superinitWithNibNamenibNameOrNilbundlenibBundleOrNilselftitle請輸入相關信息=@\"\"returnself輸入視圖和顯示視圖的設計與程序中操作完全相同關於視圖的設計就NoteNav,“”更加簡單了打開去掉視圖狀態條調整高度為然後隻。AboutViewController.xib,,416,需要拖入一個控件選擇圖片即可由於隻在關於功能ImageView,aboutImage.png。“”中顯示一個圖片因此無需在的頭文件和執行文件中添加任何代,AboutViewController碼 。 至此應用程序構建完成編譯並運行一下程序吧可見除去與上節程序,NoteTab,!,中重複的操作實現基於的應用程序並不複雜,TabBarViewController。 7.5TableViewController除了前麵介紹的視圖控製器外還有一種非常重要的視圖控製器表視圖控製器,:同和一樣(TableViewController)。UINavigationControllerUITabBarController,也是的子類表視圖控製器將在本書第章UITableViewControllerUIViewController。8詳細介紹。 在使用表視圖控製器時我們會大量地使用數據源和數據委托應用程序將一些工,。 作分配給它的委托委托的方法在指定時被調用數據源的工作原理和委托類似通常,。,148情況下使用數據源獲得表單元數使用委托方法進行有關表的操作,,。 表視圖控製器和導航控製器是密不可分的並且它們兩者也可以和標簽欄控製器結, 合起來使用如圖所示點擊列表第三行轉換到風格視圖如圖所示,7-31。,“”,7-32。 圖音樂播放器中的表視圖控製器圖轉換到風格視圖7-317-32“”76小結. 這一章我們使用三種不同的方式實現了一個視圖切換和數據保存的應用程序從,,中學習了視圖控製器及其子類導航控製器和標簽欄控製器的工作原理。 是一個非常重要的視圖控製器本章中隻是做了簡單的介紹TableViewController,,接下來我們會使用一章的內容詳細學習將表視圖控製器與導航控製器結合起來是非。,常好的一種視圖轉換的方式值得你耐心地深入研究,。 149第章表視圖8 本章內容表視圖的概述與分類■ 數據源與委托■ 如何創建表視圖■ 表視圖單元的各種操作■ 添加搜索功能■ 自定義表視圖單元■ 表視圖的美化■ 通過前麵的學習我們已經對視圖和視圖控製器有了一定的了解本章將重點介紹表, 視圖的有關知識。 表視圖是上顯示數據的元素如圖和圖所示中電子郵件設iPhone。8-18-2,iPhone、置時鍾瀏覽器書簽等軟件都使用了表視圖隻是它們的外觀和顯示的內容不盡相同、、、,。 圖表視圖一圖表視圖二8-1()8-2()15081表視圖概述. 在應用程序中表視圖應用非常廣泛它最主要的功能是以列表形式向用戶iPhone,,顯示數據在中表視圖並沒有對行的數量進行限製用戶可以通過垂直滾動的方。iPhone,式導航到一個表視圖的任意行上並可以自定義每一行數據的顯示方式需要注意的是,,中每個表視圖隻能有一列iPhone。 811表視圖簡介.. 表視圖是用來顯示列表數據的視圖對象從本質, 上講表視圖是類的一個實例從結構,UITableView;組成上講表視圖是由多個行組成的其中每一行都是,,由表視圖單元類來實現的UITableViewCell。 在表視圖中顯示數據是通過實現兩個協議和中UITableViewDelegateUITableViewDataSource的方法來完成的。 雖然每個表視圖隻能有一列但是圖所示的表,8-3視圖卻不止一列這是通過創建自定義表視圖單元“”,來實現的。 812分組表和索引表.. 表視圖有兩種基本樣式分組表和索引表:。 圖所示的中的設置就采用了分組表的8-4iPhone樣式分組表可以包含多組當然也可以隻有一個組圖表視圖的多列假象。,,8-3“”每個組都由嵌入在圓角矩形中的多個行共同構成。 圖所示的索引表視圖也稱無格式表如果數據源提供了必要的信息我們可以8-5。,在索引表右側添加索引來導航視圖圖中的索引是個英文字母,26。 151圖分組表圖索引表8-48-5813表視圖的結構.. 圖展示了分組表的結構其中的每一單獨部分稱為分區而每個分區8-6。(Section),又由多個行構成此外每個分區都擁有一個頭和尾例如在分組表,(Header)(Footer)。,中一個分組就是一個分區,。 圖展示了索引表的結構在索引表中每個字母段都是一個分區如上麵圖8-7。,,8-5聯係人列表中的分區分區等“A”、“B”。 152圖分組表的結構圖索引表的結構8-68-78.1.4UITableView和UITableViewController一般每一個表視圖都有表視圖控製器它作為(UITableViewController),UITable-的視圖控製類負責管理並控製的生命周期我們可View,UITableViewUITableView。 以把作為表視圖的數據源和委托然後利用相對應的協議的方UITableViewController,法來定義表視圖不同的顯示風格甚至可以自定義表視圖單元的每一個元素,。 815數據源和委托.. 要實現一個表視圖必須為其指定一個數據源和一個委托其中數據源為表視圖提供, 顯示的內容委托用來處理用戶對表行的操作,。 在程序中我們需要添加和協議通UITableViewDataSourceUITableViewDelegate,過實現這兩個協議中聲明的方法來構建表視圖。 表和表列舉了和協議的一8-18-2UITableViewDataSourceUITableViewDelegate些方法在後麵的章節中我們會陸續用到,。 153表8-1UITableViewDataSource方法一覽表方法方法描述UITableViewDataSource設置分區裏的行數tableView:numberOfRowsInSection:繪製特定的一行tableView:cellForRowAtIndexPath:設置分區的數目numberOfSectionsInTableView:設置分區的標題sectionIndexTitlesForTableView:確定表視圖單元的可編輯性tableView:commitEditingStyle:forRowAtIndexPath:返回一個值通知該行能夠被編輯tableView:canEditRowAtIndexPath:Boolean,返回一個值通知該行能夠被移動tableView:canMoveRowAtIndexPath:Boolean,移動表視圖單元tableView:moveRowAtIndexPath:toIndexPath:表8-2UITableViewDelegate方法一覽表方法方法描述UITableViewDelegate定義表的行高tableView:heightForRowAtIndexPath:添加細節擴展按鈕tableView:accessoryButtonTappedForRowWithIndexPath:處理將被選中的行tableView:willSelectRowAtIndexPath:處理已被選中的行tableView:didSelectRowAtIndexPath:返回行的編輯類型tableView:editingStyleForRowAtIndexPath:82實現一個簡單的表. 至此我們對表視圖已經有一定的了解了在這一節裏將真正地實現一個簡單的表,,。 圖是這個簡單表的最終效果8-8。 154下麵是完成這個項目的具體步驟: 修改文件聲明遵守表視圖·NoteScanViewController.h,協議; 修改文件構建表視圖·NoteScanViewController.xib,;修改文件實現協議方法·NoteScanViewController.m,。 1修改NoteScanViewController.h文件,聲明遵守表視圖. 協議首先打開並使用模板創建Xcode,View-basedApplication一個新項目命名為打開和文件,NoteScan,ClassesResources夾 。 選中文件添加如下黑體字所NoteScanViewController.h,示的代碼圖簡單表:8-8代碼文件8.1NoteScanViewController.h#import@interfaceNoteScanViewControllerUIViewControllerUITableViewDelegateUITableViewDataSource<>? NSArray*notelist? @propertynonatomicretainNSArray*noteList@end在處添加了和?UITableViewDelegateUITable-協議實際上是讓表視圖控製器類使ViewDataSource,用這兩個協議來充當表視圖的委托和數據源。 在處聲明了一個數組用來存放將要顯示在表?,中的數據接下來需要對。NoteScanViewController. 文件進行操作構建表視圖xib,。 2修改NoteScanViewController.xib文件,構建表. 視圖雙擊打開文件打開NoteScanViewController.xib,窗口接下來的操作很簡單隻需將如View,:TableView(圖所示從窗口中拖到窗口裏)。圖8-9LibraryView8-9TableView155表視圖會自動調整高度和寬度以適應窗口View的大小當然也可以自己定製表視圖的大小在這裏,。 我們設定表視圖大小為如圖所示320*460,8-10。 選中表視圖按下鍵調出窗口,+2,Connections,表視圖的前兩個可用連接是和分別datasourcedelegate,將它們連接到圖標上這樣就為表視圖指File?sOwner,定了數據源和委托完成上麵的這些操作保存並關。,閉然後返回中修改,Xcode,NoteScanViewController.m文件以實現協議方法,。 3修改NoteScanViewController.m文件,實現協. 議方法選中文件添加如下NoteScanViewController.m,黑體字所示的代碼圖表視圖:8-10代碼文件8.2NoteScanViewController.m#import\"NoteScanViewControllerh\"@implementationNoteScanViewControllersynthesizenoteList@ -voidviewDidLoadNSArrayarrayNSArrayallocinitWithObjectsù*=ú\"--\"\"--\"\"--\"ú@2009121@2009122@2009123ú\"--\"\"--\"\"--\"nilú@2009124@2009125@2009126? selfnoteListarrayú=úarrayrelease? superviewDidLoad數據源方法實現pragmamark-# pragmamarkTableViewDataSourceMethods# -NSIntegertableViewUITableViewtableViewù*únumberOfRowsInSectionNSIntegersectionúú returnselfnoteListcount? ú? -UITableViewCelltableViewUITableViewtableView**cellForRowAtIndexPathNSIndexPathindexPath*? 156staticNSStringNoteScanIdentifier\"NoteScanIdentifier\"*=@? UITableViewCellcelltableView*=dequeueReusableCellWithIdentifierNoteScanIdentifier? ifcellnilù==úcellUITableViewCellallocinitWithStyleú=úUITableViewCellStyleDefault? úreuseIdentifierNoteScanIdentifier? NSUIntegerrowindexPathrowù=úcelltextLabeltextnoteListobjectAtIndexrowú=ú? returncell? @end在方法裏進行了初始化操作通過處的代碼將要在表視圖中顯示的ViewDidLoad,? 數據存儲在數組中。 接下來我們重點說明如何在程序中添加數據源方法,TableView。 處的方法用於設定指定的分區中有多少行默認的分區數量為在這裏用它來?。1。 返回組成文本列表分區的行數。 處是程序繪製表行的方法第一個參數是類型的實例?。tableViewUITabelView對象第二個參數是實例變量用來確定表行的位置,IndexPathNSIndexPath,。 處聲明了一個靜態的字符串實例作為表示表視圖單元的鍵在這個表裏我們?,。,隻使用一種表視圖單元所以隻定義了一種標識符,。 處是使用類型的可重用單元?NoteScanIdentifer。 處的代碼檢查一下單元是否為空如果是就要使用前麵所提到的標識符字?(nil)。,符串來創建一個新的表視圖單元。 到現在為止我們已經構建了表視圖框架和一個可以重用的表視圖單元接下來需,,通過處的代碼把要顯示的數據放置到表視圖單元裏?。 編譯並運行程序就會得到圖所示的效果了,8-8。 83表的簡單操作. 接下來我們將介紹對表格的一些基本操作並結合上一章導航控製器的內容構建,,一個項目來實現行的移動刪除操作,、。 157831構建項目框架.. 本項目將要構建一個包含表視圖和一個導航控製器的框架如圖所示,8-11。 接下來我們將通過以下步驟完成此項目,:創建項目·;修改文件·RootViewController.h;修改文件·RootViewController.m。 1創建項目. 打開使用模板創Xcode,Navigation-basedApplication建一個項目並把它命名為如圖所示,NoteNav,8-12。 圖項目框架8-11圖新建項目8-12這與之前創建項目時所選擇的模式有所不同這一節我們的主要目的在於表的操, 作所以直接使用自帶導航控製器和表視圖的模板來構建項目當然也可以利用前麵所,,學的知識創建一個帶有導航控製器和表視圖的框架這對於前麵知識的鞏固很有幫助,。 158打開和文件夾共有四個文件ClassesResources,。Root-和兩個文件是模板的ViewController.hRootViewController.m根視圖控製器文件也是本項目進行代碼編輯的主戰場,“”。 編譯並運行一下看看這個新模板產生的視圖效果以便對,,它有更加直觀的了解如圖所示,8-13。 2修改RootViewController.h文件. 這裏要實現的效果和上一節項目是一樣的隻是NoteScan,這裏的表視圖要在根視圖裏顯示所以接下來的變量和方法聲明, 都會在根控製器文件內添加。 選中文件添加如下黑體字所示的RootViewController.h,圖模板效果代碼8-13: 代碼文件8.3RootViewController.h@interfaceRootViewControllerUITableViewControllerUITableViewDataSourceUITableViewDelegate<>NSMutableArraynoteList*? propertynonatomicretainNSMutableArraynoteList@*@end在處聲明一個可變數組而不是簡單的數組這是為了後麵?MutableArray,Array,進行移動行和刪除行的操作而特意準備的。 3修改RootViewController.m文件. 選中文件添加如下黑體字所示的代碼RootViewController.m,:代碼文件8.4RootViewController.m#import\"RootViewControllerh\"@implementationRootViewControllersynthesizenoteList@ -voidviewDidLoadselftitle\"NoteScan\"=@? NSMutableArrayarray*=NSMutableArrayallocinitWithObjects\"--\"\"--\"\"--\"@20081201@20081202@20081203\"--\"\"--\"\"--\"nil@20081204@20081205@20081206selfnoteListarray= 159arrayreleasesuperviewDidLoad-voiddidReceiveMemoryWarningsuperdidReceiveMemoryWarning-voidviewDidUnload數據源方法實現#pragmamarkTableviewDataSourceMethods-NSIntegernumberOfSectionsInTableViewUITableView*tableViewreturn1-NSIntegertableViewUITableView*tableViewnumberOfRowsInSectionNSIntegersectionreturnselfnoteListcount-UITableViewCell*tableViewUITableView*tableViewcellForRowAtIndexPathNSIndexPath*indexPathstaticNSString*CellIdentifier=@\"Cell\"UITableViewCell*cell=tableViewdequeueReusableCellWithIdentifierCellIdentifierifcell==nilcell=UITableViewCellallocinitWithStyleUITableViewCellStyleDefaultreuseIdentifierCellIdentifierautoreleaseNSUIntegerrowindexPathrow= celltextLabeltextnoteListobjectAtIndexrow= returncell-voiddeallocnoteListreleasesuperdealloc@end160處添加的代碼用來?self.title=@\"NoteScan\",設置導航控製器的標題。 到現在為止我們已經把前麵項目裏麵NoteScan的表格移植到新項目裏來了現在編譯並運行程“”,序就得到圖所示的效果,8-11。 832移動表視圖單元.. 我們將在前麵的基礎上添加行的移動操作這種, 操作對於應用程序來說是很有幫助的如圖所,8-14示 。 這裏我們需要完成以下工作: 修改文件添加移動·RootViewController.h,方法; 修改文件實現移動·RootViewController.m,操作; 編譯並運行·。 1修改RootViewController.h文件,添加移動方法.圖可移動表視圖選中文件添加如下黑體8-14RootViewController.h,字所示的代碼: 代碼文件8.5RootViewController.h@interfaceRootViewControllerUITableViewControllerNSMutableArray*noteList@propertynonatomicretainNSMutableArray*noteList-IBActionnoteMove? @end在處聲明了一個移動表視圖單元的操作方法?noteMove。 2修改RootViewController.m文件,實現移動操作. 選中文件添加如下黑體字所示的代碼RootViewController.m,:代碼文件8.6RootViewController.m#import\"RootViewControllerh\"@implementationRootViewController@synthesizenoteList161-IBActionnoteMoveúùselftableViewsetEditingúú selftableVieweditinganimatedYES? ú? -voidviewDidLoadselftitle=@\"NoteScan\"NSMutableArray*array=NSMutableArrayallocinitWithObjects@\"2009-12-01\"@\"2009-12-02\"@\"2009-12-03\"@\"2009-12-04\"@\"2009-12-05\"@\"2009-12-06\"nilselfnoteList=arrayarrayrelease添加移動按鈕UIBarButtonItemmoveButtonUIBarButtonItemallocù*=úinitWithTitle\"Move\"ú@ústyleUIBarButtonItemStyleBorderedútargetselfúú? actionselectornoteMoveú@úselfnavigationItemrightBarButtonItemmoveButton=úmoveButtonrelease? superviewDidLoad-voiddidReceiveMemoryWarningsuperdidReceiveMemoryWarning-voidviewDidUnload-voiddeallocnoteListreleasesuperdealloc數據源方法#pragmamark-#pragmamarkTableviewDataSourcemethods-NSIntegernumberOfSectionsInTableViewUITableView*tableViewreturn1162-NSIntegertableViewUITableView*tableViewnumberOfRowsInSectionNSIntegersectionreturnselfnoteListcount-UITableViewCell*tableViewUITableView*tableViewcellForRowAtIndexPathNSIndexPath*indexPathstaticNSString*CellIdentifier=@\"Cell\"UITableViewCell*cell=tableViewdequeueReusableCellWithIdentifierCellIdentifierifcell==nilcell=UITableViewCellallocinitWithStyleUITableViewCellStyleDefaultreuseIdentifierCellIdentifierautoreleasecellshowsReorderControlYES=? NSUIntegerrow=indexPathrowcelltextLabeltext=noteListobjectAtIndexrowUIImage*image=UIImageimageNamed@\"aisidepng\"cellimageViewimage=imagereturncell行的移動方法-UITableViewCellEditingStyletableViewúùUITableViewtableViewú*úeditingStyleForRowAtIndexPathú? NSIndexPathindexPathú*úreturnUITableViewCellEditingStyleNone? -BOOLtableViewUITableViewtableViewù*úcanMoveRowAtIndexPathNSIndexPathindexPathú*úreturnYES? ú? 163-voidtableViewUITableViewtableViewù*úmoveRowAtIndexPathNSIndexPathfromIndexPathú*útoIndexPathNSIndexPathtoIndexPath*úNSUIntegerfromRowfromIndexPathrowú=úNSUIntegertoRowtoIndexPathrowú=úidobjectnoteListobjectAtIndexfromRowretain? =únoteListremoveObjectAtIndexfromRowúú noteListinsertObjectobjectatIndextoRowúú objectreleaseú ? @end處添加的方法用來控製用戶是否能夠對表進行操作?。 處代碼為導航欄添加了一個其中用來確定按?BarButton,initWithTitle:@\"Move\"鈕的名稱確定按鈕的類型傳遞;style:UIBarButtonItemStyleBordered;target:selfself作為目標即指向自己用來指定觸發的方法;action:@selector(noteMove)]。 ?? ??????????????????????????? ?我們可使用下麵的方法來設置導航按鈕在不同狀? ?? ?態時的名稱:? ?? ?[:!? Self.tableViewsetEditingslf.tableView.ed-?:];()? i?tinganimatedYESifself.tableView.editing? ?[? ?self.navigationltem.rightBarButtonltemsetTi-? :];t?le@\"Done\"else? ?[? ????????????????????????? ?self.navigationltem.rightBarButtonltemsetTi-? ?:];? tle@\"Move\"處的代碼為行指定了標準擴展圖標圖中每行右部的圖標隻有表處於編輯?(8-15),模式時才會顯示通過設置表視圖單元的這個屬性才能啟動移動控件進入可以移動。,,的狀態。 處添加的方法是用來確定編輯類型這裏的返回類型是?。UITableViewCellEdit-指明為移動類型此外還有另外兩種類型ingStyleNone,;:UITableViewCellEditing-和分別表示刪除和插入類型StyleDeleteUITableViewCellEditingStyleInsert,。 處添加的方法主要是用來指定該行能夠進行移動操作?。 處添加了方法我們通過它來?tableView:moveRowAtIndexPath:fromIndexPath,實現真正的移動兩個實例用來存儲移動行的原位置和新位置同時聲明。NSIndexPath;了一個類型實例對象它用來存儲將要被移動對象最後需要將該對象從原位置上移id,;164除並插入到新位置上,。 3編譯並運行. 到這裏行的移動操作就完成了編譯並運行程序當點擊按鈕時行的右側會,。Move出現重新排序控件如圖所示可以選中任意行拖拽到表中任何位置再次單擊,8-15。,按鈕就可以對表進行重新排序了Move。 圖移動效果圖可刪除表視圖一8-158-16()833刪除表視圖單元.. 接下來學習行的刪除操作這裏將在原有代碼基礎上進行修改以實現行的刪除功。 能最終效果如圖所示,8-16。 要實現此功能大致需要以下幾步: 修改文件聲明刪除方法·RootViewController.h,;修改文件實現刪除方法·RootViewController.m,;編譯並運行·。 1修改RootViewController.h文件,聲明刪除方法. 選中文件添加如下黑體字所示的代碼RootViewController.h,:165代碼文件8.7RootViewController.h@interfaceRootViewControllerUITableViewControllerNSMutableArray*noteListBOOLeditState? @propertynonatomicretainNSMutableArray*noteListpropertyBOOLeditState@ -IBActionnoteMove-IBActionnoteDeleteidsender? @end在處聲明了一個類型變量它主要用於判斷編輯狀態區分同一?BOOLeditState,,個導航條上麵的不同狀態然後決定采用何種操作在處添加了刪除方法,。?。 2修改RootViewController.m文件,實現移動操作. 接下來選中文件對程序做以下修改,RootViewController.m,:代碼文件8.8RootViewController.m#import\"RootViewControllerh\"@implementationRootViewController@synthesizenoteListsynthesizeeditState@ #pragmamark-#pragmaTableMethods添加行的移動與刪除方法-IBActionnoteMoveúùeditStateYESú=úselftableViewsetEditingúú selftableVieweditinganimatedYESúú -IBActionnoteDeleteidsenderú? editStateNOú=úselftableViewsetEditingúselftableVieweditinganimatedYESúú ? -voidviewDidLoadselftitle=@\"Note\"NSMutableArray*array=NSMutableArrayallocinitWithObjects@\"2009-12-01\"@\"2009-12-02\"@\"2009-12-03\"166@\"200912-04\"@\"2009-12-05\"@\"2009-12-06\"nilselfnoteList=arrayarrayreleaseUIBarButtonItem*moveButton=UIBarButtonItemallocinitWithTitle@\"Move\"styleUIBarButtonItemStyleBorderedtargetselfaction@selectornoteMoveselfnavigationItemrightBarButtonItem=moveButtonmoveButtonreleaseUIBarButtonItemdeleteButtonUIBarButtonItemallocù*=úinitWithTitle\"Delete\"ú@ styleUIBarButtonItemStyleBorderedúú targetselfúactionselectornoteDeleteú? @úselfnavigationItemleftBarButtonItemdeleteButtonú= deleteButtonreleaseúú editStateNO? =superviewDidLoad數據源方法的實現#pragmamark-#pragmamarkTableviewDataSourcemethods-NSIntegernumberOfSectionsInTableViewUITableView*tableViewreturn1-NSIntegertableViewUITableView*tableViewnumberOfRowsInSectionNSIntegersectionreturnselfnoteListcount-UITableViewCell*tableViewUITableView*tableViewcellForRowAtIndexPathNSIndexPath*indexPathstaticNSString*CellIdentifier=@\"Cell\"UITableViewCell*cell=tableViewdequeueReusableCellWithIdentifierCellIdentifierifcell==nilcell=UITableViewCellallocinitWithStyleUITableViewCellStyleDefaultreuseIdentifierCellIdentifierautorelease167cellshowsReorderControl=YESNSUIntegerrow=indexPathrowcelltextLabeltext=noteListobjectAtIndexrowreturncell-voiddidReceiveMemoryWarningsuperdidReceiveMemoryWarning-voidviewDidUnload-voiddeallocnoteListreleasesuperdealloc委托方法的實現#pragmamark-#pragmamarkTableDeleteMethods-UITableViewCellEditingStyletableViewUITableView*tableVieweditingStyleForRowAtIndexPathNSIndexPath*indexPathifeditStateúùreturnUITableViewCellEditingStyleDeleteúelseúú? returnUITableViewCellEditingStyleNoneú ? -BOOLtableViewUITableView*tableViewcanMoveRowAtIndexPathNSIndexPath*indexPathúùifeditStateúreturnYESúú elseú? returnNOúú ? -voidtableViewUITableView*tableViewmoveRowAtIndexPathNSIndexPath*fromIndexPathtoIndexPathNSIndexPath*toIndexPathNSUIntegerfromRow=fromIndexPathrowNSUIntegertoRow=toIndexPathrowidobject=noteListobjectAtIndexfromRowretainnoteListremoveObjectAtIndexfromRow168noteListinsertObjectobjectatIndextoRowobjectrelease刪除方法的實現-voidtableViewUITableViewtableViewù*úcommitEditingStyleUITableViewCellEditingStyleúeditingStyleforRowAtIndexPathúú NSIndexPathindexPathú* NSUIntegerrowindexPathrowú=úselfnoteListremoveObjectAtIndexrowú? tableViewdeleteRowsAtIndexPathsúú NSArrayarrayWithObjectindexPathúwithRowAnimationUITableViewRowAnimationFadeúú ? @end在處設置移動方法為真刪除方法為假?,。 在處添加了刪除按鈕並設置它的編輯默認狀態為假?。 在處加入了判斷語句這裏我們可以這樣理解如果?,:為則進入默認的刪除狀態否則進入編輯等待狀!editState,,態 。 在處添加的代碼用於判斷是否執行移動操作如果返?,回為則執行移動操作YES,。 在處添加的是真正實現刪除操作的方法首先獲取當?。 前行然後在數組中執行刪除最後是刪除的動畫效果當然,,。 還有其他效果你可以查閱幫助文檔分別試驗一下效果,,。 3編譯並運行. 到這裏刪除操作就完成了編譯並運行程序就會得到,,如圖所示的效果當單擊按鈕時進入可刪除的8-16。Delete狀態單擊紅色的圓形按鈕就可以刪除一行了如圖所,,,8-17圖可刪除表視圖二示8-17()。 84行的選擇處理. 當我們選中一行時表視圖需要確定是否選擇了該行,,通常需要借助委托來確定這一操作具體來講有兩種辦法可以實現下麵我們就借用在。,本章節創建的簡單表來進行行的選擇處理8.2,。 1691選中後調用方法. 在表視圖單元被選中之後需要調用委托的行選擇方法為了表明我們確實選中了,。 一行這裏將在單擊選中行後彈出一個警告打開項目然後在,,NoteScan,NoteScanView-文件尾部的之前添加如下代碼Controller.m@end:-voidtableViewUITableViewtableView* didSelectRowAtIndexPathNSIndexPathindexPath* NSUIntegerrowindexPathrow= NSStringrowValuetableDataobjectAtIndexrow*=NSStringmessageNSStringalloc*=initWithFormat\"你選中了%\"rowValue@@UIAlertViewalertUIAlertViewalloc*=initWithTitle\"選中行\"@ messagemessagedelegatenilcancelButtonTitle\"確定\"@ otherButtonTitlesnilalertshowmessagereleasealertrelease編譯並運行程序如圖所示單擊某一行時會彈出一個警告,8-18,。 圖選中效果圖8-181702阻止行被選中的方法. 指定某一行不能被選中接著上麵的代碼繼續在之前添加如下代碼。@end:-NSIndexPathtableViewUITableViewtableView**willSelectRowAtIndexPathNSIndexPathindexPath* NSUIntegerrowindexPathrow= ifrow==3returnnilreturnindexPath通過這個方法可以獲取所傳遞的值確定選中了哪一行如果是選中了第,indexPath,。 四行將它的索引設為空那麼它的返回值為如果選中其他行將返回,(nil),nil;,indexPath值表示可以繼續選擇其他行編譯並運行會發現無法選中第四行但是可以選擇其他行,。,,。 85公開. 所謂公開就是指表視圖單元右側的細節展示按鈕或者擴展指示器(disclosure),使用公開可以使單元格進入到下一級視圖。。 細節展示按鈕其實是一個按(UITableViewCellAccessoryDetailDisclosureButton),鈕它能夠響應用戶操作隻有點擊這個按鈕才能夠進入下一級視圖如圖所示的,,。8-19常見的設置視圖就是采用這種按鈕Wi-Fi,。 圖細節展示按鈕8-19171擴展指示器也能夠響應用戶操作(UITableViewCellAccessoryDisclosureIndicator),與細節展示按鈕不同的是隻要點擊了某一行就可以進入下一級視圖如圖所示的,。8-20設置視圖就采用了這種符號點擊後進入下一級子菜單選項Settings,。 圖擴展指示器8-20這一節我們就主要學習一下細節展示按鈕的使用方法本節的項目將在節創。8.3建的框架基礎之上進行修改最終效果如圖所示,8-21。 圖使用公開8-21172本程序的步驟如下: 添加並編輯下級詳細視圖·;修改文件實現公開的使用·RootViewController,;編譯並運行·。 1添加並編輯下級詳細視圖. 首先打開項目創建一個顯示詳細信息的視圖選擇文件夾然後NoteNav,,Classes,按下打開新建文件向導在左側的窗格裏麵選擇在右邊+N,,CocoaTouchesClasses,的窗格裏選擇並把它命名為保證UIViewControllersubclass,NoteDetailController.m,選中頭文件在詳細視圖裏麵添加一個標簽用它來顯示我們選擇的行。,,。 選中文件添加如下黑體字所示的代碼NoteDetailController.h,:代碼文件8.9NoteDetailController.h#import@interfaceNoteDetailControllerUIViewControllerIBOutletUILabelnoteLabel*? NSStringmessage*? propertynonatomicretainUILabelnoteLabel@*propertynonatomicretainNSStringmessage@*@end處為標簽聲明了一個輸出口同時在處聲明了一個字符串類型實例變量?,?。 接下來看一看文件的修改代碼如下NoteDetailController.m,:代碼文件8.10NoteDetailController.m#import\"NoteDetailControllerh\"@implementationNoteDetailControllersynthesizenoteLabel@ synthesizemessage@ -voidviewWillAppearBOOLanimatedúùú únoteLabeltextmessageú=? superviewWillAppearanimatedúú ? -voiddidReceiveMemoryWarningsuperdidReceiveMemoryWarning173-voidviewDidUnload-voiddeallocnoteLabelreleasemessagereleasesuperdealloc@end在處使用方法進行數據更新因為方法隻在第一?viewWillAppear。viewDidLoad次加載視圖時調用而在這裏要多次調用視圖所以需要使用,NoteDetailController,方法viewWillAppear。 接下來在文件夾上單擊右鍵創建新的文件並把它命名為Resources,Xib,NoteDe-雙擊打開文件單擊然後調tailController.xib。NoteDetailController.xib,File?sOwner,出窗口把屬性改為我們還要重新連接Identity,ClassNoteDetailController,File?s到視圖因為剛才控製器類的更改打斷了這個連接OwnerView,。 從中拖出一個到視圖中並調整它的大小在窗口中將對齊LibraryLabel,,Identity方式設為居中最後一步就是連接到選擇輸出口保存。File?sOwnerLabel,noteLabel,然後關閉文件。 2修改RootViewController文件,實現公開的使用. 選中文件添加如下黑體字所示的代碼RootViewController.h,:代碼文件8.11RootViewController.hclassNoteDetailController@ @interfaceRootViewControllerUITableViewControllerNSMutableArray*noteListNoteDetailControllersubController*? @propertynonatomicretainNSMutableArray*noteList@end在此文件中隻是在處聲明了一個實例對象接下來選中?NoteDetailController。,文件添加如下黑體字所示的代碼RootViewController.m,:代碼文件8.12RootViewController.m#import\"RootViewControllerh\"import\"NoteNavAppDelegateh\"# 174import\"NoteDetailControllerh\"# @implementationRootViewController@synthesizenoteList-voidviewDidLoadselftitle=@\"NoteScan\"NSMutableArray*array=NSMutableArrayallocinitWithObjects@\"2009-12-01\"@\"2009-12-02\"@\"2009-12-03\"@\"2009-12-04\"@\"2009-12-05\"@\"2009-12-06\"nilselfnoteList=arrayarrayreleasesuperviewDidLoad-voiddidReceiveMemoryWarningsuperdidReceiveMemoryWarning-voidviewDidUnload數據源方法的實現#pragmamark-#pragmamarkTableDataSourceMethods-NSIntegernumberOfSectionsInTableViewUITableView*tableViewreturn1-NSIntegertableViewUITableView*tableViewnumberOfRowsInSectionNSIntegersectionreturnselfnoteListcount-UITableViewCell*tableViewUITableView*tableViewcellForRowAtIndexPathNSIndexPath*indexPathstaticNSString*CellIdentifier=@\"Cell\"175UITableViewCell*cell=tableViewdequeueReusableCellWithIdentifierCellIdentifierifcell==nilcell=UITableViewCellallocinitWithStyleUITableViewCellStyleDefaultreuseIdentifierCellIdentifierautoreleaseNSUIntegerrow=indexPathrowNSStringrowStringnoteListobjectAtIndexrow*=celltextLabeltextrowString= rowStringreleasecellsetAccessoryTypeUITableViewCellAccessoryDetailDisclosureButton? returncell委托方法的實現#pragmamark-#pragmamarkTableDelegateMethods-voidtableViewUITableViewtableViewù*údidSelectRowAtIndexPathNSIndexPathindexPathú*úUIAlertViewalertUIAlertViewallocú*=úinitWithTitle\"查看詳細信息\"ú@úmessage\"如果要查看詳細信息請點擊藍色按鈕\"@údelegatenilúú? cancelButtonTitle\"確定\"ú@úotherButtonTitlesnilúú alertshowú alertreleaseúú ? 點擊公開按鈕後觸發的操作176-voidtableViewUITableViewtableViewù*úaccessoryButtonTappedForRowWithIndexPathúú NSIndexPathindexPathú*úifsubControllernilú==úsubControllerNoteDetailControlleralloc=úinitWithNibName\"NoteDetailController\"ú@úbundlenilúú úú subControllertitle\"詳細信息\"=@úNSUIntegerrowindexPathrowú=úNSStringselectedDatenoteListobjectAtIndexrowú*=ú? NSStringdetailMessageNSStringallocinitWithFormatú*=ú\"您選擇的日期是%\"selectedDate@@úsubControllermessagedetailMessageú=úsubControllertitleselectedDateú=údetailMessagereleaseúú NoteNavAppDelegatedelegate*=úUIApplicationsharedApplicationdelegateúú delegatenavigationControllerúú pushViewControllersubControlleranimatedYESúú ? -voiddeallocsubControllerreleasenoteListreleasesuperdealloc@end處添加的代碼用於為每個行後麵添加一個細節展示按鈕?,。 處的方法在用戶選中某一行時調用它告訴用戶要單擊細節展示按鈕而不是點擊?,行並且實現了一個警告來提示用戶要進行的操作如果直接選擇了細節展示按鈕就,,,,會調用下麵的方法。 處的方法首先檢查子控製器實例變量查看它是否為空如果為空?subController,,,就會執行初始化操作接下來根據所選的行來為新視圖設置標題在入棧之前為它分。,,177配所要顯示的文本在這裏設置來反應單擊的是哪一行的展示按鈕最後使用,message。 實例獲取應用程序委托這樣做是因為導航控製器是由應用程序的委托維UIApplication,護的然後利用委托的導航控製器輸出口將顯示信息的下級視圖放入導航控製器堆棧, 中當點擊某一行時從棧中取出並顯示,,。 3編譯並運行. 到這裏對於代碼的操作就完成了現在編譯並運行程序吧單擊第三行會看到圖,! 所示的效果當點擊細節展示按鈕時就會進入到下級視圖如圖所示8-22,,,8-23。 圖單擊行圖下級視圖8-228-2386分組表、索引表和搜索功能的實現. 前麵幾節我們學習了表視圖的基本知識和一些簡單操作其中可以了解到表視圖分, 為分組表和索引表兩種基本樣式接下來我們就來實現簡單的分組表索引表並添加一,、,項常用的搜索功能。 178861實現分組表和索引表.. 在這一小節裏我們將通過構建分組表和索引表來深入, 了解它們的內部結構最終要實現的效果如圖所示,8-24。 程序具體的步驟如下: 修改文件·NoteSectionViewController.h;構建分組表視圖·;修改文件·NoteSectionViewController.m;編譯並運行·;修改視圖為索引表樣式並添加索引·。 1修改NoteSectionViewController.h文件. 首先使用模板創建一個項目並View-basedApplication,把它命名為選中圖分組表NoteSection。NoteSectionViewController.8-24文件添加如下黑體字所示的代碼h,:代碼文件8.13NoteSectionViewController.h#import@interfaceNoteSectionViewControllerUIViewControllerUITableViewDelegateUITableViewDataSource<>NSDictionarywordsù*úNSArraykeys?? *propertynonatomicretainNSDictionarywords@*propertynonatomicretainNSArraykeys@*@end首先添加了和協議這跟我們以前UITableViewDataSourceUITableViewDelegate,所做的操作一樣接下來在處添加並聲明了。? 和實例變量其中NSDictionaryNSArray,NSDic-用於保存所有行數據數組用於保存各個時間tionary,分區。 2構建分組表視圖. 構建分組表視圖時將拖進窗,TableViewView口中然後把數據源和委托連接到圖標,File?sOwner上麵選中表視圖調出窗口把表視圖的。,Attributes,圖調整8-25Style179改為如圖所示這樣做是因為在這裏要創建的是一個分組表保存StyleGrouped,8-25,,並返回Xcode。 前麵創建的項目中都是將數據直接寫入程序裏而在這個項目中將使用屬性列表,,,作為數據源這個屬性列表包含一個字典它的結構如圖所示首先要將隨書光盤,,8-26。 中文件下的文件添加到項目的文件Chapter8NoteSectionNoteSection.plistResources夾中。 圖屬性列表8-263修改NoteSectionViewController.m文件. 選中文件添加如下黑體字所示的代碼NoteSectionViewController.m,:代碼文件8.14NoteSectionViewController.m#import\"NoteSectionViewController.h\"@implementationNoteSectionViewControllersynthesizewords@;synthesizekeys@;pragmamark-# pragmamarkUIViewControllerMethods# 讀取屬性列表文件並存入字典\/\/180-voidviewDidLoad(){úùNSStringwordsPathNSBundlemainBundleú*=[[]úpathForResource\"NoteSection\"ofType\"plist\":@:@];úNSDictionarydictionaryNSDictionaryallocú*=[[]úinitWithContentsOfFilewordsPath:];úself.wordsdictionaryú?