



版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
(lOS)Objective-C入門教程(2016年度最熱門)2016年度最熱門的學習課程iPhone路程:)0bjective-CoObjective-C是進行iPhone開發(fā)的主要語言,掌握了Objective-C的基本語法以及數(shù)據(jù)結(jié)構(gòu)之后.)iPhone的SDK.筆者很難做到在ー篇文章里面把所有的東西都介紹清楚,所以筆者打算分成兩個主題,—是〇bjective-C,T是iPhone開發(fā)。本系列將側(cè)重于Objective-C。當然,任何ー種開發(fā)語言都無法脫離于運行環(huán)境,Objective-C也不例外。所以在本系列當中也會穿插的介紹一些SDK里面的一些特性,主要是數(shù)據(jù)結(jié)構(gòu)方面,比如說NSString,NSArray等等。看到NSString,NSArray這些名詞,你也許會感到有些茫然,不過沒有關系,隨著本系列的深入介紹,你會發(fā)現(xiàn)你非常喜歡這些東西。.2I開發(fā)前準備第一,你需要一臺蘋果電腦。當然這個不是必需的條件,如果你可以在你的!ntelPC上成功安裝MACOS的話,那么請忽略這一條。第二,你需要去蘋果網(wǎng)站上下載開發(fā)工具XCODE,注意,XCODE是完全免費的,但是需要你去注冊一個賬號オ可以下載.由于XCODE不時的在更新,所以如果你的MACOS不支持你下載的XCODE的話,那么你也許需要考慮買ー個最新的MACOS。第三,你需要至少有CC++,或者JAVA的背景知識.不過如果你沒有,那么也不用擔心,相信閱讀了筆者的文章之后應該也可以掌握。最后需要的東西就不是必須的了,當然有的話會更好一些。這些東西是,開發(fā)者賬戶(需要付費),iPhone手機(在部分國家可以免費獲得,但是中國會怎么樣,筆者不是很清楚),iPodTouch(需要購買)。L4,本文檔結(jié)構(gòu)第1章,也就是本章第2章,從Hello,World!開始第3章,類的聲明和定義第4章,繼承第5章,Class類型,選擇器Selector以及函數(shù)指針第6章,NSObject的奧秘第7章,對象的初始化以及實例變量的作用域第8章,類方法以及私有方法第9章,內(nèi)存管理第10章,到目前為止出現(xiàn)的內(nèi)存泄漏事件第11章,字符串,數(shù)組以及字典第12章,屬性第13章,類目(Categories)第14章,協(xié)議(Protocols)第15章,Delegate第16章,線程第17章,文件系統(tǒng)第18章,數(shù)據(jù)系列化以及保存用戶數(shù)據(jù)第19章,網(wǎng)絡編程第20章,XML解析2,從Hello,World!開始現(xiàn)在筆者假設大家已經(jīng)有了開發(fā)的環(huán)境。好了,我們開始構(gòu)筑我們的第一個程序。在開始第一個程序之前,筆者需要提醒大家一下,如果手里面有開發(fā)環(huán)境的話并且是第一次親密接觸Xcode的話,為了可以熟悉開發(fā)環(huán)境,強烈建議按照筆者的步驟ー步ー步的操作下去。2.1,構(gòu)筑Hello.World第一步,啟動Xcode。初次啟動的時候,也許會彈出ー個"WekometoXcode"的ー個對話框。這個對話框和我們的主題沒有關系,我們可以把它關掉。第二步,選擇屏幕上部菜單的"File->NewProject",出現(xiàn)了一個讓你選擇項目種類的對話框。你需要在對話框的左邊選擇"CommandLineUtility",然后在右邊選擇
"FoundationTool",然后選擇"Choose..."按鈕。如圖2.1幅。NewProjectChooseatemplateforyournewproject:iPhoneOSk-ftIuui wrcruunudiiuriToolApplicationMacOSXApplicationAudioUnitsFoundationToolStandardToolAutomatorActioniPhoneOSk-ftIuui wrcruunudiiuriToolApplicationMacOSXApplicationAudioUnitsFoundationToolStandardToolAutomatorActionBundleCommandLineUtilityDynamicLibraryFrameworkJavaKernelExtensionStandardApplePlug...CommandLineUtilityDynamicLibraryFrameworkJavaKernelExtensionStandardApplePlug...StaticLibraryOtherDescriptionThisprojectbuildsacommand-linetoolthatlinksagainsttheFoundationlibrary.圖2-1I新建項目注意也許有人會問,你不是要講解iPhone的開發(fā),那么為什么不選擇"iPhoneOS"下面的"Application"呢?是這樣的,在這個系列當中,筆者主要側(cè)重于〇bjective-C的語法的講解,為了使得講解簡單易懂,清除掉所有和要講解的內(nèi)容無關的東西,所以筆者在這里只是使用最簡單的命令行。第三步,Xcode會提問你項目的名字,在"SaveAs"里面輸入"02-HelloWorld",然后選擇"Save".如圖2-2所示
iDiskSkypeMier..Ope...Macinto...▼DEVICES0?北三皿しSLOBCSaveAs:|02-HelloWorld'NewFolder'NewProject目I3-ロロ笛BcbjcBIPLOobiDiskSkypeMier..Ope...Macinto...▼DEVICES0?北三皿しSLOBCSaveAs:|02-HelloWorld'NewFolder'NewProject目I3-ロロ笛BcbjcBIPLOobロロ?▼SHARED(■japfccS6a|M|bombjllicaboverde型icayman鼻galapagos(_Cancel'(Save、ー.圖2-2,輸入項目的名字第四步,得到一個如圖2-3所示的ー個畫面。嘗試ー下用鼠標分別點擊左側(cè)窗口欄里面的"02-HelloWorld"“Documentation""ExternalFrameworksandLibraries","Products"(然后觀察一下右邊的窗口都出現(xiàn)了什么東西。一般來說,"〇2-HelloWorld"就是項目的名字下面是項目所有的文件的列表。項目下面的子目錄分別是和這個項目相關的一些虛擬或者實際上的目錄。為什么我說是虛擬的呢?大家可以通過Finder打開你的工程文件的目錄,你會發(fā)現(xiàn)你的所有文件居然都在根目錄下,根本就不存在什么"Source"之類的目錄。
辰02-HelloWorld.m-02-HelloWorld10.5|_Debug|_1386 Overview▼丨[修 ,、 ( ) SiAction BuildandGoTasksInfo SearcGroups&FilesIlJFileName へCode C▼△02-HelloWorldS|向02-HelloWorld.m ?SourceDocumentationL_ExternalFrameworksancProductsTargetspExecutables傅ErrorsandWarningsQFindResultsQ5BookmarksgSCM■ProjectSymbolsル㈤ImplementationFiles?K)NIBFiles同)2-HelloWorld_Prefix.pch?02-HelloWorld.m:9:「main。:#import<Foundation/Foundation.h>intmain(intargc,constchar*argv[]){NSAutoreleasePooI*pool=[[NSAutoreleasePooIalloc]init];//insertcodehere...NSLog((3"Hello,World!");[pooldrain];return0;}圖2-3,項目瀏覽窗口第五步,選擇屏幕上方菜單的"Run"然后選擇"Console",出現(xiàn)了如圖2-4所示的畫面,用鼠標點擊窗口中間的"BuildandGo"按鈕。A〇〇 二02-HelloWorld-DebuggerConsole10.51Debug|i386 ▼ アネ(Overview BuildandGoTas<sRestartPauseActivate ClearLog[Sessionstartedat2009-03-2717:01:39+0900.]2009-03-2717:01:39.07602-HclloWorld[1335:10b]Hello,World!TheDebuggerhasexitedwithstatus0.Debuggingof*02-HelloWorld"endednormally. QSucceeded圖2-4,運行結(jié)果畫面如果不出什么意外的話,大家應該看到我們熟悉得不能再熟悉的"HelloWoIrd!"。由于我們沒有寫任何的代碼,所以從理論上來說,這部分代碼不應該出現(xiàn)編譯錯誤。好的,從下面開始,筆者要開始對這個HelloWorld里面的ー些新鮮的東西進行講解。2.2,頭文件導入在Java或者C/C++里面,當我們的程序需要引用外部的類或者方法的時候,需要在程序源文件中包含外部的類以及方法的包java里面的jarpackage或者頭文偉C/C++的.h),在Objective-C里面也有相類似的機制。筆者在這ー節(jié)里面將要向大家介紹在Objective-C里面,頭文件是怎樣被包含進來的。請同學們到Xcode開發(fā)環(huán)境的左側(cè)窗口里面,點擊Source文件夾,然后就在右側(cè)部分看到了代碼源文件的列表,找至リ02-HelloWorld.m之后單擊會在Xcode的窗口里面出現(xiàn),雙擊鼠標代碼會在ー個新窗口出現(xiàn),請同學們按照這種方法打開"02-HelloWorld.m"。對于Java程序來說,源程序的后綴為.java,對于C/C++代碼來說,后綴為c/cpp,現(xiàn)在我們遇到了.m。當Xcode看到了.m文件之后,就會把這個文件當作Objective-C文件來編譯。同學們也許會猜到,當Xcode遇到c/cpp,或者java的時候也會對應到相應的語言的。好的,我們順便提了一下Xcode對.m文件的約定,現(xiàn)在我們開始從第一行代碼講起,請參看下列代碼:l#import<Foundation/Foundation.h>23intmain(intargc,constchar*argv[]){4NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];56//insertcodehere???7NSLog(@"Hello,World!");8[pooldrain];9return0;)有過C/C++經(jīng)驗的同學看到第一行,也許會覺得有些親切;有過Java經(jīng)驗的同學看到第一行也許也會有一種似曾相識的感覺.同學們也許猜到了這是干什么用的,沒錯,這個正是頭文件。不過,在C/C++里面是#include,在java里面是import,這里是#import。在C/C++里面會有#include互相包含的問題這個時候需要#ifdef來進行編譯的導向,在Xcode里面,同學們可以“放心的”包含各種東西,這個沒有關系,因為我們的編譯器有足夠的“聰明”,因為同一個頭文件只是被導入一次.除了#import變得聰明了一點之外,和#include的功能是完全一樣的。我們再來看看我們的另外一個新的朋友---Foundation.h。這個是系統(tǒng)框架Foundationframework的頭文件,有了它你可以免費的獲取系統(tǒng)或者說蘋果公司為你精心準備的ー系列方便你使用的系統(tǒng)功能,比如說字符串操作等等。Foundation框架從屬于Cocoa框架集,Cocoa的另外一個框架為ApplicationKit,或者是UIKit,其中前者的應用對象為MACOS后者的應用對象為iPhoneOS。本系列入門指南將只是使用Foundation,因為筆者需要向同學們介紹〇bjective-C的基本使用方法,為了避免過多的新鮮東西給同學們造成閱讀上的困難,所以命令行就已經(jīng)足夠了。說到這里,筆者需要澄清一點,其實MACOS的Cocoa和iPhone的Cocoa是不一樣的,可以說,其中iPhone是MACOS的一個子集。,main函數(shù)有過C/C++或者java經(jīng)驗的同學們對第3行代碼應該很熟悉了,是的大家都一樣主程序的入口都是main。這個main和C/C++語言里面的main是完全ー樣的,和java語言在本質(zhì)上也是完全ー樣的。因為Objective-C完全的繼承了C語言的特性。確切的說,不是說Objective-C和C語言很相似,而是Objective-C和C語言是完全兼容的。關于main函數(shù)是干什么用的,筆者就不在這里羅嗦了,有興趣的同學可以找一本C語言的書看看。I關于NSAutoreleasePool自己動手,豐衣足食ー--在第4行,我們遇到了另外一個新鮮的東西,這就是NSAutoreleasePool.讓我把這個單詞分為三部分,NS,Autorelease和Pool當我們看到NS的時候,也許不知道是代表著什么東西。NS其實只是ー個前綴,為了避免命名上的沖突.NS來自于NeXTStep的ー個軟件,NeXTSoftware的縮寫,NeXTSoftware是Cocoa的前身,ー開始使用的是NS,為了保持兼容性所以NS一直得以保留。在多人開發(fā)的時候,為了避免命名上的沖突,開發(fā)組的成員最好事先定義好各自的前綴。但是,最好不要有同學使用NS前綴,這樣會讓其他人產(chǎn)生誤解。略微有些遺憾的是,Objective-C不支持namespace關鍵字,不知道后續(xù)的版本是否會支持。下面我們討論一下Autorelease和Pool.程序在執(zhí)行的時候,需要向系統(tǒng)申請內(nèi)存空間的,當內(nèi)存空間不再被使用的時候,毫無疑問內(nèi)存需要被釋放,否則有限的內(nèi)存空間會很快被占用光光,后面的程序?qū)o法得到執(zhí)行的有效內(nèi)存空間。從計算機技術(shù)誕生以來,無數(shù)的程序員,我們的無數(shù)先輩都在為管理內(nèi)存進行努力的工作,發(fā)展到現(xiàn)在,管理內(nèi)存的工作已經(jīng)得到了非常大的完善。在Objective-C或者說Cocoa里面,有三種內(nèi)存的管理方式。第一種,叫做"Garbagecollection"。這種方式和java類似,在你的程序的執(zhí)行過程中,始終有一個高人在背后準確地幫你收拾垃圾,你不用考慮它什么時候開始工作,怎樣工作。你只需要明白我申請了一段內(nèi)存空間,當我不再使用從而這段內(nèi)存成為垃圾的時候,我就徹底的把它忘記掉,反正那個高人會幫我收拾垃圾。遺憾的是,那個高人需要消耗一定的資源,在攜帶設備里面,資源是緊俏商品所以iPhone不支持這個功能。所以-(Garbagecollection"不是本入門指南的范圍,對"GarbageCollection”內(nèi)部機制感興趣的同學可以參考一些其他的資料,不過說老實話"GarbageCollection"不大適合適初學者研究。第二種,叫做"ReferenceCounted"。就是說,從一段內(nèi)存被申請之后,就存在ー個變量用于保存這段內(nèi)存被使用的次數(shù),我們暫時把它稱為計數(shù)器,當計數(shù)器變?yōu)椹柕臅r候,那么就是釋放這段內(nèi)存的時候.比如說,當在程序A里面一段內(nèi)存被成功申請完成之后,那么這個計數(shù)器就從〇變成1(我們把這個過程叫做alloc),然后程序B也需要使用這個內(nèi)存,那么計數(shù)器就從1變成了2(我們把這個過程叫做retain).緊接著程序A不再需要這段內(nèi)存了,那么程序A就把這個計數(shù)器減1(我們把這個過程叫做release);程序B也不再需要這段內(nèi)存的時候,那么也把計數(shù)器減1(這個過程還是release).當系統(tǒng)(也就是Foundation)發(fā)現(xiàn)這個計數(shù)器變成了〇,那么就會調(diào)用內(nèi)存回收程序把這段內(nèi)存回收(我們把這個過程叫做dealloc).順便提一句,如果沒有Foundation,那么維護計數(shù)器,釋放內(nèi)存等等工作需要你手工來完成.這樣做,有一個明顯的好處就是,當我們不知道是A先不使用這段內(nèi)存,還是B先不使用這段內(nèi)存的時候,我們也可以非常簡單的控制內(nèi)存.否則,當我們在程序A里面釋放內(nèi)存的時候,還需要看看程序B是否還在使用這段內(nèi)存,否則我們在程序A里面釋放了內(nèi)存之后,可憐的程序B將無法使用這段內(nèi)存了.這種方式,尤其是在多線程的程序里面很重要,如果多個線程同時使用某一段內(nèi)存的時候,安全的控制這些內(nèi)存成為很多天才的程序員的夢魘.如果有同學搞過COM的話那么應該對Release/AddRef很熟悉了其實Obejctive-C和他們的機制是ー樣的.接下來我需要解釋一下Autorelease方式。上述的alloc->retain->release->dealloc過程看起來ヒ匕較令人滿意,但是有的時候不是很方便,我們代碼看起來會ヒ匕較羅嗦,這個時候就需要Autorelease.Autorelease的意思是,不是立即把計數(shù)器減1而是把這個過程放在線程里面加以維護。當線程開始的時候,需要通知線程(NSAutoreleasePool),線程結(jié)束之后,オ把這段內(nèi)存釋放(drain)。Cocoa把這個維護所有申請的內(nèi)存的計數(shù)器的集合叫做pool,當不再需要pool(水池)的時候就要drain(放水)。筆者想要說的是,雖然iPhone支持Autorelease但是我們最好不要使用.因為Autorelease方式從本質(zhì)上來說是ー種延遲釋放內(nèi)存的機制,手機的空間容量有限,我們必須節(jié)約內(nèi)存,確定不需要的內(nèi)存應該趕快釋放掉,否則當你的程序使用很多內(nèi)存的情況下也許會發(fā)生溢出.這ー個習慣最好從剛剛開始學習使用Objective-C的時候就養(yǎng)成,否則長時間使用Autorelease會讓你變得"懶散",萬一遇到問題的時候,解決起來會非常耗費時間的。所以,還是關于內(nèi)存管理,我們還是自己動手,豐衣足食。當然筆者不是說絕對不可以使用,而是當使用Autorelease可以明顯減低程序復雜度和易讀性的時候,還是考慮使用一下?lián)Q一下口味。說到這里,可能有的同學已經(jīng)開始發(fā)暈了,認為這個東西比較難以理解。是的,筆者在這里只是介紹ー個大概的東西,在這里只要了解計數(shù)器的概念就可以了,筆者將在隨后的章節(jié)里面對這個功能加以詳細論述,請同學們放心,這個東西和HelioWorldー樣簡單。關于Pool在使用Pool的時候,也要記住系統(tǒng)給你的Pool的容量不是無限大的,從這一點來說和在現(xiàn)實世界的信用卡比較相似。你可以在一定程度透支,但是如果“忘記掉"信用卡的額度的話,會造成很大的系統(tǒng)風險。第三種,就是傳統(tǒng)而又原始的c語言的方式,筆者就不在這里敘述了.除非你在Objective-C里面使用C代碼,否則不要使用C的方式來申請和釋放內(nèi)存,這樣會增加程序的復雜度。線程是什么東西?線程指的是逬程中一個單ー順序的控制流。它是系統(tǒng)獨立調(diào)度和分派的基本單位。同一逬程中的多個線程將共享該進程中的全部系統(tǒng)資源,比如文件描述符和信號處理等等。一個逬程可以有很多線程,每個線程并行執(zhí)行不同的任務。,^7[[NSAutoreleasePoolalloc]init];關于程序第4行等號右邊出現(xiàn)的括弧以及括弧里面的內(nèi)容,筆者將在后續(xù)的章節(jié)里面介紹。在這里,同學們可以理解為,通過告訴Objective-C編譯器[[NSAutoreleasePoolalloc]init],編譯器就會成功的編譯生成NSAutoreleasePoo對象的代碼就可以了。,Objective-C里面的注釋同學們在第6行看到了〃的注釋,這個和C++以及Java是ー樣的,表示這一行的內(nèi)容是注釋,編譯器將會忽略這一行的內(nèi)容。筆者在上面說過Objective-C完全兼容C語言,所以C語言里面?zhèn)鹘y(tǒng)的/**/在Objective-C里面也是有效的。,命令行輸出第7行,我們看到了NSLog這個函數(shù)。NS上面已經(jīng)講過了,我們都知道Log是什么意思,那么這段代碼的意思就是輸出一個字符串,Xcode的代碼生成器自己把字符串定義為-Hello,World!".NSLog相當于C語言里面的printf,由于我們是在使用Objective-C所以筆者將會和同學們ー起,在這里暫時忘記掉我們過去曾經(jīng)熟悉的printf.有眼光銳利的同學會發(fā)現(xiàn)在字符串的前面多了一個@符號,這是ー個什么東西呢?如前所述,Objective-C和C是完全兼容的,但是NSLog這個函數(shù)需要的參數(shù)是NSString,這樣就產(chǎn)生了一個問題,如果使用C的字符串方式的話,為了保持和C的兼容性編譯器將會把字符串理解為c的字符串。為了和C的字符串劃清界限,在C的字符串前面加上@符號,Objective-C的編譯器會認為這是ー個NSString,是ー個NSLog喜歡的參數(shù).為什么NSLog或者Cocoa喜歡使用NSString?因為NSString封裝了一系列的字符串的方法比如字符串比較,字符串和數(shù)字相互轉(zhuǎn)換等等的方法,使用起來要比C的字符串方便的多。,本章總結(jié)非常感謝同學們耐心的看到這里!通過理解本章的內(nèi)容,同學們應該可以使用Xcode創(chuàng)建一個命令行的工程,理解.m文件的基本要素,理解內(nèi)存的管理方法的思路,還有Objective-C的注釋的寫法,以及命令行的輸出方法。是不是很簡單又很有樂趣呢?筆者將會盡最大努力把看起來復雜的東西講解的簡單ー些,并且真心的希望大家可以從中找到樂趣。3,類的聲明和定義本系列講座有著很強的前后相關性,如果你是第一次閱讀本篇文章,為了更好的理解本章內(nèi)容,筆者建議你最好從本系列講座的第1章開始閱讀,請點擊這里。上一章我們寫了一個非常簡單的〇bejctive-C下面的Hell。,World!的〃灌序,并且對里面出現(xiàn)的ー些新的概念進行了解釋。這一章,我們將要深入到Objective-C的ー個基本的要素,也就是類的聲明和定義。通過本章的學習,同學們應該可以定義類,給類加上變量,還有通過方法訪問類的變量。不過準確的說,變量和方法的名詞在Objective-C里面并不是最準確的稱呼,我們暫時引用Java的定義,稍后我們將統(tǒng)ー我們的用語定義。,本章的程序的執(zhí)行結(jié)果。我們將構(gòu)筑一個類,類的名字叫做Cattle,也就是牛的意思,今年是牛年而且我還想給在股市奮戰(zhàn)的同學們ー個好的名字,所以我們暫時把這個類叫做牛類。我們在main里面初始化這個牛類,然后調(diào)用這個類的方法設定類的變量,最后調(diào)用這個類的一個方法,在屏幕上輸出,最終輸出的結(jié)果如下圖3-1所示?CQ Q03-HelloClass-DebuggerConsole CDI10.5|Debug|i386Overview缸?日業(yè)。,一?I10.5|Debug|i386OverviewBuildandGoTasksRestartPauseActivateClearLog[Sessionstartedat2009-03-3020:32:15+0900.]2009-03-3020:32:15.90703-HclloClass[5577:10b]Hollo,Iamacattle,Ihave4logs.TheDebuggerhasexitedwithstatus0?|Debuggingof-03-HclloClass"endednormally. QSucceeded圖3-1,牛類的輸出結(jié)果完整的代碼在這里。不過為了熟悉編輯環(huán)境以及代碼,筆者強烈建議同學們按照下面的步驟自己輸入。,實現(xiàn)步驟第一步,按照我們在第二章所述的方法,新建一個項目,項目的名字叫做03-HelloClass。當然,你也可以起一個別的更好聽的名字,比如說HelloCattle等等(這個并不妨礙我們的講解。如果你是第一次看本系列文章,請到這里參看第二章的內(nèi)容。第二步,把鼠標移動到左側(cè)的窗口的"Source"目錄,然后單擊鼠標右鍵,選擇"Add”,然后界面上會出來ー個子菜單,在子菜單里面選擇"NewFile..."。如圖3-2所示:
_203-HelloClass[10.5|Debug|1386▼J(jd &,エノ0QStringMatchOverviewAction BuildandGoTasksInfoCroups&FilesTTFileName▼電03-HelloClass sEJr:]03-HelloClass.mA—???? ?? C ??>ひAdd1?NewFile...?&OpenWithFinderNewGroup?Pr?(^■TargRevealinFinderNewTarget...NewCustomExecutable.?pExecGetInfoNewBuildPhase??處Error▼QFindRenameTouchUntouchExistingFiles...ェ?LJJBook一SCM?ProjeExistingFrameworks...DeleteNoEditorA囪!mph?NIBFUngroupGroupPreferences?圖3-2,新建文件第三步,在新建文件對話框的左側(cè)選擇"CocoaTouchClasses”,然后在右側(cè)窗口選擇"NSObjectsubclass”,然后單擊"Next".如圖3-3所示:
第四步,在"NewFile"對話框里面的"FileName"欄內(nèi)輸入"Cattle.m".注意,在確省狀態(tài)下,Xcode為你加上了".m"的后綴,這個也是編譯器識別Objective-C源文件的方法,沒有特殊理由請不要修改這個后綴(否則會讓編譯器感到不舒服。另外請確認文件名字輸入欄的下方有一個,'Alsocreate-Cattel.h",,選擇框,請保持這個選擇框為選擇的狀態(tài)。如圖3-4所示。
第5步,在項目瀏覽器里面選擇"Cattle.h”文件,把文件改為如下代碼并且保存(Command鍵+S):#import<Foundation/Foundation.h>@interfaceCattle:NSObject{intlegsCount;)-(void)saySomething;-(void)setLegsCount:(int)count;@end為什么legsCattle者,牛也;legs者,股也。不過牛股里面的牛正確的英文說法應該是Bull,請大家不要著急,我們會在類的繼承里面命名ー個Bull類的。第六步,在項目瀏覽器里面選擇"Cattle.m"文件,把文件改為如下代碼并且保存(Command鍵+S):#import"Cattle.h"@implementationCattle-(void)saySomething(NSLog(@"Hello,lamacattle,Ihave%dlegs.",legsCount);)-(void)setLegsCount:(int)count(legsCount=count;)@end第七步,在項目瀏覽器里面選擇〃〇3-HelloClass.m"文件,把文件改為如下代碼并且保存(Command鍵+S):#import<Foundation/Foundation.h>#importMCattle.h"intmain(intargc,constchar*argv[]){NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];idcattle=[Cattlenew];[cattlesetLegsCount:4];[cattlesaySomething];[pooldrain];returnO;)第八步,選擇屏幕上方菜單里面的〃Run〃,然后選擇〃Console",打開了Console對話框之后,選擇對話框上部中央的"BuildandG〇〃,如果不出什么意外的話,那么應該出現(xiàn)入圖3-1所示的結(jié)果。如果出現(xiàn)了什么意外導致錯誤的話,那么請仔細檢查ー下你的代碼。如果經(jīng)過仔細檢查發(fā)現(xiàn)還是不能執(zhí)行的話,可以到這里下載筆者為同學們準備的代碼。如果筆者的代碼還是不能執(zhí)行的話,請告知筆者。,類的聲明從〇bjective-C名字我們就可以得知,這是ー個面向?qū)ο蟮恼Z言。面向?qū)ο蟮末`個最基礎的要素就是類的概念,〇bjective-C也不例外。所謂的類的概念,其實是從C語言的結(jié)構(gòu)體發(fā)展而來的。我們知道,C語言里面的結(jié)構(gòu)體僅僅有數(shù)據(jù)的概念,面向?qū)ο蟮恼Z言不僅僅支持數(shù)據(jù),還可以在結(jié)構(gòu)體里面封裝用于存取結(jié)構(gòu)體數(shù)據(jù)的方法。結(jié)構(gòu)體的數(shù)據(jù)和方法結(jié)合,我們把整個結(jié)構(gòu)體稱為類(Class)。僅僅有了類,是不能執(zhí)行任(可操作的,我們必須把類進行實體化,實體化后的類我們稱之為對象(Object)。從這個角度上來說,我們可以認為類是對象的模版。如果要使用類,那么和構(gòu)造體相類似,我們必須聲明這個類。請參照"Cattle.h"文件:l#import<Foundation/Foundation.h>234@interfaceCattle:NSObject{5intlegsCount;6)7-(void)saySomething;8-(void)setLegsCount:(int)count;9@end如果看過本系列第二章的同學們,第一行應該是ー個老面孔了,我們知道我們需要這個東西免費獲得蘋果公司為我們精心準備的FoundationFramework里面的很多的功能。如果不使用這個東西的話,我們的工作將會很復雜.同學們請看第4行和第9行的第一個字母,又出現(xiàn)了"@"符號。為什么說又呢,因為我們在第二章的字符串前面也看到過這個東西。字符串前面出現(xiàn)這個符號是因為我們需要和C語言的字符串定義區(qū)別開來,我們需要編譯器導向。在這里,我要告訴同學們的是,這里的"@"符號的作用還是同樣是編譯器導向。我們知道Java和C++定義了一個關鍵字class用于聲明ー個類,在Objective-C里面,不存在這樣的關鍵字。在Objective-C里面,類的定義從@interface開始到@end結(jié)束,也就是說,編譯器看到了@interface就知道了這是類的定義的開始,看到了@end就知道,類的定義結(jié)束了。我們這里類的名字是"Cattle",我們使用了空格和@interface分開,通知編譯器,我們要聲明一個類,名字叫做Cattle,在Cattle的后面,我們有":NSObject”,這是在通知編譯器我們的Cattle是從NSObject繼承而來的,關于繼承和NSObject,我們將在后面的章節(jié)里面詳細介紹,關于":NSObjecピ我們現(xiàn)在可以理解為,通過這樣寫,我們免費獲得了蘋果公司為我們精心準備的一系列的類和對象的必備的方法。NSObject被稱為rootclass也就是根類。在Java或者.NET里面根類是必備的,C++不需要。在Obejctive-C里面原則上,你可以不使用NSObject,構(gòu)筑ー個你自己的根類,但是事實上這樣做將會有很大工作量,而且這樣做沒有什么意義,因為蘋果為你提供的NSObject經(jīng)過了很長時間的檢驗。也許有好奇心的同學們想自己構(gòu)筑根類,不過至少筆者不會有自己去構(gòu)筑一個根類的欲望.好的,大家現(xiàn)在來看第5行。我們以前把這個東西叫做變量,我們從現(xiàn)在開始,需要精確的使用Objective-C的用語了,這是實體變量(instancevariables,在有的英文資料里面會簡寫為iVars).雖然作為一個Cattle,它有不止ー個實體變量,比如說體重等等,但是為了代碼簡潔,我們在這里聲明一個就是牛腿也就是牛股的數(shù)目,這個實體變量是int型,表示一個整數(shù),我們當然不希望有4.5個牛腿。我們來看第6行第6行的括弧和在第4行最后的括弧用來表示實體變量的定義區(qū)間,編譯器認為在這兩個括弧之間的定義是實體變量的定義.當然,如果你的類沒有實體變量,那么這兩個括弧之間允許什么都沒有。和Java以及C++不一樣,Objective-C要求在括弧里面不能有方法也就是函數(shù)的定義1sB么Objective-C里面的方法的定義放在什么地方呢,請看第7行.第7行的第一個字母是ー個減號.這個減號就是告訴編譯器,減號后面的方法,是實體方法(instancemethod)。實體方法的意思就是說,這個方法在類沒有被實體化之前,是不能運行的。我們在這里看到的是減號,在有減號的同時也有加號,我們把帶加號的方法稱為類方法(classmethod),和實體方法相對應,類方法可以脫離實體而運行.關于類方法,我們將在后面的章節(jié)里面講解。大家也許可以想起來在C++和Java里面同樣也有類似的區(qū)分,不是么.在Objective-C里面方法的返回類型需要用圓括號包住,當編譯器看到減號或者加號后面的括號了之后,就會認為這是在聲明方法的返回值。你也可以不聲明返回值,Objective-C的編譯器會給沒有寫顯式的返回值函數(shù)加上一個默認的返回值,它的類型是!d,關于id類型我們將在后面講解,不過筆者不推薦不寫返回值的類型。在第7行我們定義了這個方法的名字是saySomething,當然Cattle說的話我們?nèi)祟愂锹牪欢?筆者只是想讓它在我們的控制臺里面輸出ー些我們可以看得懂得字符串。方法的聲明最后,需要分號來標識,這一點保持了和C沒有任何區(qū)別。我們再來看看第8行,第8行和第7行多了":(int)count"。其中冒號放在方法的后面是用來表示后面是用來定義變量的,同樣變量的類型使用括號給包住,如果不寫變量的類型的化,編譯器同樣認為這是ー個id類型的。最后的count,就是變量的名字.如果有不只一個變量怎么辦?答案就是在第一個變量后面加冒號,然后加園括號包住變量的類型,接著是變量的名字.好了,我們在這里總結(jié)ー下,類的定義方法如下:?interface類的名字:父類的名字{實體變量類型實體變量名字;)-(返回值類型)方法名字;+(返回值類型)方法名字;-(返回值類型)方法名字:(變量類型)變量名字標簽1:(變量類型)變量1名字;@end...的意思在本系列入門講座里面,...表示省略了一些代碼的意思。3.4I類的定義我們在前ー節(jié)講述了類的聲明,我們下ー步將要看一下類的定義。請同學們打開"Cattle.m”文件:l#import"Cattle.h"34@implementationCattle5-(void)saySomething6(7NSLog(@"Hello,Iamacattle,Ihave%dlegs.",legsCount);8}9-(void)setLegsCount:(int)count10{lllegsCount=count;13@end14Cattle.m文件的第一行就import了Cattle.h文件,這一點和C的機制是ー樣的,關于#import的說明請參照第二章。我們來看第4行和第13行,和頭文件里面的@ー樣,我們這里類的定義也是使用的編譯導向。編譯器會把從@implementation到@end之間的部分看作是類的定義。@implementation的后面有一個空格,空格的后面是我們的類的名字Cattle,這是在告訴編譯器,我們要定義Cattle類了。第4行和第13行之間是我們在頭文件里面定義的實體方法或者類方法的定義部分,當然我們的類如果沒有任何的實體方法和類方法的話,我們也許要寫上@implementation和@end,把中間留為空就可以了。第5行是我們定義的saySomething的實現(xiàn),我們可以發(fā)現(xiàn)第5行的內(nèi)容和頭文件Cattle.h的第7行是一致的。筆者個人認為在編寫實體方法和類方法的定義的時候,為了避免手工輸入產(chǎn)生的誤差,可以從頭文件當中把聲明的部分拷貝過來,然后刪除掉分號,加上兩個花括弧。我們知道地6行到第8行是方法的定義的部分,我們再來看看第7行。第7行和第二章的Hell。,World輸出有些相似只不過多了一個%d還有實體變量legsCount,這個寫法和C語言里面的printf是類似的,輸出的時候會使用legsCount來替代字符串里面的%d。第9行的內(nèi)容和Cattle.h的第8彳亍一致的,這個不需要再解釋了。我們來看看第11行,第11行是在說,把參數(shù)count的數(shù)值賦值給實體變量!egsCount,我們可以通過使用setLegsCount方法來控制Cattle對象里面legsCount的數(shù)值。這部分內(nèi)容的關鍵點為@implementation和@end,理解了這個東西,其余的就不難理解了.我們來總結(jié)ー下,類的定義部分的語法:(?implementation類的名字-(方法返回值)方法名字(方法定義}-(方法返回值)方法名字:(變量類型)變量名字方法定義)@end的實例化我們在3.3和3.4節(jié)里面分別聲明和定義了一個Cattle的類。雖然定義好的類,但是我們是不能直接使用這個類的。因為類的內(nèi)容需要被調(diào)入到內(nèi)存當中我們稱之為內(nèi)存分配(Allocation),然后需要把實體變量進行初始化(Initialization),當這些步驟都結(jié)束了之后,我們的類就被實例化了,我們把實例化完成的類叫做對象(Object)。好的,我們知道了我們在類的實例化過程當中需要做哪些工作,我們接著來看看我們已經(jīng)搞定的Cattle類的定義和聲明是怎樣被實例化的。l#import<Foundation/Foundation.h>2#import"Cattle.h"34intmain(intargc,constchar*argv[]){5NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];67idcattle=[Cattlenew];8[cattlesetLegsCount:4];9[cattlesaySomething];10ll[pooldrain];12return0;同學們請看第7行的第一個單詞id.id是英文identifier的縮寫,我們在很多地方都遇到過id,比如說在博客園里面,我們都使用id來登陸系統(tǒng)的,我們的id就代表著系統(tǒng)的ー個用戶。由于id在ー個系統(tǒng)當中是唯一的,所以系統(tǒng)獲得我們的id之后就知道我們是誰了.Objective-C也是ー樣的道理,使用id來代表ー個對象,在Objective-C當中,所有的對象都可以使用id來逬行區(qū)分。我們知道一個類僅僅是ー些數(shù)據(jù)外加上操作這些數(shù)據(jù)的代碼,所以id實際上是指向數(shù)據(jù)結(jié)構(gòu)的ー個指針而已,相當于void*.第7行的第二個單詞是cattle,就是我們給這個id起的ー個名字。當然,你可以起系統(tǒng)保留的名字以外的任何名字,不過為了維持代碼的可讀性,我們需要一個有意義的名字,我們這里使用頭文字為〃寫的cattle.第7行的[Cattlenew]是創(chuàng)建對象,new實際上是alloc和init的組合在Objective-C里面創(chuàng)建對象是ー個為對象分配內(nèi)存和初始化的過程.new,alloc還有init定義在Cattle的超類NSObject里面,筆者將要在第7章里面詳細的解釋一下如何創(chuàng)建對象.在第7章之前我們都是用new來創(chuàng)建對象.Objective-C里面的方法的使用和其他語言有些不同,Objective-C使用消息(Message)來調(diào)用方法.所以筆者認為在講解第7行等號右邊的部分之前,需要首先向大家介紹ー個我們的新朋友,消息(Message).所謂的消息就是一個類或者對象可以執(zhí)行的動作.消息的格式如下:[對象或者類名字方法名字:參數(shù)序列];首先我們觀察到有兩個中括弧,最右邊的括弧之后是ー個分號,當編譯器遇到了這個格式之后會把中間的部分當作一個消息來發(fā)送。在上文的表達式當中,包括中括弧的所有部分的內(nèi)容被稱作消息表達式(Messageexpression),"對象或者類名字”被稱作接收器(Receiver),也就是消息的接受者,"方法名字:參數(shù)序列"被稱為ー個消息(Message),"方法名字"被稱作選擇器(Selector)或者關鍵字(Keyword)。Objective-C和C語言是完全兼容的,C語言里面的中括弧用于表示數(shù)組,但是數(shù)組的格式明顯和消息的發(fā)送的格式是不ー樣的,所以我們可以放心,編譯器不會把我們的消息發(fā)送當作一個數(shù)組。我們來回憶一下C語言里面函數(shù)的調(diào)用過程,實際上編譯器在編譯的時候就已經(jīng)把函數(shù)相對于整個執(zhí)行包的入口地址給確定好了,函數(shù)的執(zhí)行實際上就是直接從這個地址開始執(zhí)行的。Objective-C使用的是ー種間接的方式,Objective-C向?qū)ο蠡蛘哳?具體上是對象還是類的名字取決于方法是實體方法還是類方法)發(fā)送消息,消息的格式應該和方法相同。具體來說,第?行等號右邊的部分[Cattlenew]就是說,向Cattle類發(fā)送一個new的消息。這樣當Cattle類接收到new的時候,就會查找它可以相應的消息的列表,找到了new之后就會調(diào)用new的這個類方法,分配內(nèi)存和初始化完成之后返回一個id,這樣我們就得到一?對象。Objective-C在編譯的過程當中,編譯器是會去檢查方法是否有效的,如果無效會給你ー個警告。但是編譯器并不會阻止你執(zhí)行,因為只有在執(zhí)行的時候オ會觸發(fā)消息,編譯器是無法預測到執(zhí)行的時候會發(fā)生什么奇妙的事情的。使用這樣的機制給程序毫無疑問將給帶來極大的靈活性,因為我們和任意的對對象或者類發(fā)送消息,只要我們可以保證執(zhí)行的時候類可以準確地找到消息并且執(zhí)行就可以了,當然如果找不到的話,運行會出錯。任何事物都是一分為二的一一任何事物都是一分為二的,在我們得到了靈活性的時候我們損失的是執(zhí)行的時間.Objective-C的這種方式要比直接從函數(shù)的入口地址執(zhí)行的方式要消耗更多的執(zhí)行時間,雖然編譯器對尋找的過程作過一定的優(yōu)化。有的同學會覺得奇怪,我們在Cattle里面并沒有定義new,我們可以向Cattle發(fā)送這個類方法么?答案是可以,因為new在NSObject里面,實際上響應new消息的是NSObject,實際上new類似于一個宏,并不是一個“原子"的不可再分的方法,關于詳細的情況,我們將在后續(xù)的章節(jié)里面講解。有了第7行的講解,那么第8行的內(nèi)容就不難理解了,第8行實際上是想cattleヌ慘發(fā)送一個setLegsCount的消息,參數(shù)是4,參照Catttle.m,我們可以發(fā)現(xiàn)這個時候我們希望實體變量legsCount是4。第8行就更簡單了,就是說向cattle對象發(fā)送ー個saySomething的消息,從而實現(xiàn)了控制臺的輸出。3.6,本章總結(jié)通過本章的學習,同學們應該掌握如下概念.如何聲明一個類.如何定義一個類.實體變量的定義.類方法和實體方法的定義.id是什么.NSObject的奇妙作用.如何從類開始初始化對象.消息的調(diào)用4,繼承本系列講座有著很強的前后相關性,如果你是第一次閱讀本篇文章,為了更好的理解本章內(nèi)容,筆者建議你最好從本系列講座的第1章開始閱讀,請點擊這里。上一章筆者介紹了一下在〇bjective-C里面的類的基本構(gòu)造和定義以及聲明的方法。我們知道在面向?qū)ο蟮某绦蚶锩?有一個很重要的需求就是代碼的重復使用,代碼的重復使用的重要方法之一就是繼承。我們在這一章里面バ各要仔細的分析一下繼承的概念以及使用的方法.有過其他面向?qū)ο笳Z言的同學,對這一章的內(nèi)容應該不會感到陌生。,本章的程序的執(zhí)行結(jié)果在本章里面,我們將要重復使用第3章的部分代碼。我們在第3章構(gòu)筑了一個叫做Cattle的類,我們在這一章里面需要使用Cattle類,然后基于Cattle類,我們需要構(gòu)筑ー個子類,叫做Bull類.Bull類里面,我們追加了一個實例變量,名字叫做skinColor,我們也將^追加2個實例方法,分別getSkinColor還有setSkinColor,我們?nèi)缓笮枰囊幌挛覀兊膍ain函數(shù),然后在main函數(shù)里面讓我們的Bull做一下重要講話。第4章程序的執(zhí)行結(jié)果如圖4-1所示:ヽ04-HelloInheritance-DebuggerConsole10.5IDebug|i386OverviewBuildandGoTasksRestartPause10.5IDebug|i386OverviewBuildandGoTasksRestartPauseActivate[Sessionstartedat2009-04-0414:15:47*0900.]2009-04-0414:15:47.09604-HelloInheritance[620:10b]Hello,Iamacattle,Ihave4legs.2009-04-0414:15:47.09704-HelloInheritance[620:10b]Hello,Iamaredbull,Ihave4legs.2009-04-0414:15:47.09804-HolloInheritance[620:10b]Hello,Iamablackbull,Ihave4legs.TheDebuggerhasexitedwithstatus0.TheDebuggerhasexitedwithstatus0.QSucceededんQSucceededん圖4-1,本章程序的執(zhí)行結(jié)果,實現(xiàn)步驟第一步,按照我們在第二章所述的方法,新建一個項目,項目的名字叫做04-HelloInheritance,如果你是第一次看本篇文章,請到這里參看第二章的內(nèi)容。第二步,把鼠標移動到項目瀏覽器上面的"Source"上面,然后在彈出的菜單上面選擇"Add",然后在子菜單里面選擇"ExsitingFiles",如圖4-2所示ヽ04-HelloInheritanceGroups&FilesIIIイFileName,へCode▼T"04-HelloInheritances!同04-HelloInheritance.m?NewFile...10.5IDebugIi386OverviewSearcOpenWithFinder正ActionQjStringMatchingBuildandGoTasksInfo?C71Exter?_Prodi>3Targets>/Executal?ふErrorsai▼QFindRes?LJ1Bookma?::SCM■Project!>國lmplem<?NIBFilesRevealinFinderGetInfoRenameTouchUntouchDeleteNewGroupNewTarget...NewCustomExecutable...NewBuildPhaseExistingFiles...ExistingFrameworks...IAddExistingFilesto“Source二..INoEditorUngroupGroupPreferences圖4-2(向項目追加文件第三步,在文件選擇菜單里面,選擇第3章的項目文件夾"03-HelloClass”,打開這個文件夾之后,用鼠標和蘋果電腦的COMMAND鍵,選澤文件"Cattle.h"和"Cattle.m",然后按下"Add"按鈕,如圖4-3所示.如果你沒有下載第3章的代碼,請點擊這里下載。10.5rDebug|J386やOverview Action2204-HelloInheritanceBuildancCoTasksInfoStringMatchingScareGroups&Files▼油04-HelloInheritar?QlSource?,DocumentatioiL.ExternalFram(( ProductsTargets/ExecutablesほErrorsandWarnirQFindResultsL,J1Bookmarks二.SCM■ProjectSymbols>向ImplementationF?風NIBFiles三?皿丨a03-HelloClassf)&search▼DEVICES flnName一▲イDateModifiedFl03-HelloClass.12009年3月30日20:07□iDiskSi03-HelloClass.m2009年3月30日20:31ー、System?Firefox±0]03-HelloClass.xcodeprojh03-HelloClass-Prefix.pch2009年3月30日20:372009年3月30日20:07[3Cattle.h2009年3月30日20:10ロMier...±BCattle.m2009年3月30日20:23PLA?理《0▼MEDIA月MusicaI7LPhotosLf 宀<?[(NewFolder) (Cancel)(Addヽ /I圖4-3,選擇文件第四步,在働口文件的選項對話框里面,讓Topyitemsintodestinationgroup'sfolderCifneeded)"的單選框變?yōu)楸贿x擇的狀態(tài)。這樣就保證了我們在第三步里面選擇的文件被拷貝到了本章的項目里面,可以避免我們不小心更改"Cattle.h"和"Cattle.m"對已經(jīng)生效的第3章程序產(chǎn)生影響,雖然我們在本章里面不更改這2個代碼.第五步,把鼠標移動到項目瀏覽器上面的"Source"上面,然后在彈出的菜單上面選擇"Add",然后在子菜單里面選擇"NewFiles",然后在新建文件對話框的左側(cè)選擇
"CocoaTouchQasses"I然后在右側(cè)窗口選擇"NSObjectsubclass",選擇"Next",在"NewFile"對話框里面的"FileName"欄內(nèi)輸入"Bull.m"。在這里筆者沒有給出圖例,在這里新建文件的步驟和第3章的第二步到第四步相同,只是文件名字不一樣。第一次看到本篇文章的同學可以參照第3章。第六步,打開BuILh做出如下修改,并且保存。#import<Foundation/Foundation.h>#import-Cattle.h"@interfaceBull:Cattle{NSString*skinColor;)-(void)saySomething;-(NSString*)getSkinColor;-(void)setSkinColor:(NSString*)color;@end第七步,打開Bull.m做出如下修改,并且保存#import"Bull.h"@implementationBull
-(void)saySomethingNSLog(@MHello/Iama%@bull/Ihave%dlegs.",[selfgetSkinColor]JegsCount);)-(NSString*)getSkinColor(returnskinColor;)-(void)setSkinColor:(NSString*)color(skinColor=color;)@end第八步,打開04-HelloInheritance.m文件,做出如下修改,并且保存#import<Foundation/Foundation.h>#import"Cattle.h"#importnBull.h"intmain(intargc,constchar*argv[]){NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
idcattle=[Cattlenew];[cattlesetLegsCount:4];[cattlesaySomething];idredBull=[Bullnew];[redBuIIsetLegsCount:4];[redBullsetSkinColor:@"red"];[redBullsaySomething];Bull*blackBull=[Bullnew];[blackBullsetLegsCount:4];[blackBullsetSkinColor:@"black"];[blackBullsaySomething];[pooldrain];returnO;)第九步,選擇屏幕上方菜單里面的“Run”,然后選擇“Console〃,打開了Console對話框之后,選擇對話框上部中央的"BuildandG〇〃,如果不出什么意外的話,那么應該出現(xiàn)入圖4?1所示的結(jié)果。如果出現(xiàn)了什么意外導致錯誤的話,那么請仔細檢查一下你的代
碼.如果經(jīng)過仔細檢査發(fā)現(xiàn)還是不能執(zhí)行的話,可以到這里下載筆者為同學們準備的代碼.如果筆者的代碼還是不能執(zhí)行的話,請告知筆者。?子類Subclass和超類Superclass讓我們首先回憶一下第3章的Cattle.h,在Cattle.h里面我們有如下的代碼片斷:@interfaceCattle:NSObject{這段代碼是在告訴編譯器,我們的Cattle是繼承的NSObject,在這段代碼當中,NSObject是超類,Cattle是子類。通過這樣寫,我們曾經(jīng)免費的得到了NSObject里面的ー個方法叫做new.idcattle=[Cattlenew];在面向?qū)ο蟮某绦蛟O計當中,如果在子類當中繼承了超類的話,那么超類當中已經(jīng)生效的部分代碼在子類當中仍然是有效的,這樣就大大的提高了代碼的效率。基于超類我們可以把我們需要追加的一些功能放到子類里面去,在本章里面,我們決定基于Cattle類,重新生成ー個子類Bull:l#import<Foundation/Foundation.h>2#import"Cattle.h"34@interfaceBull:Cattle{5NSString*skinColor;6}7-(void)saySomething;
8-(NSString*)getSkinColor;9-(void)setSkinColor:(NSString*)color;10@end上段代碼里面的第2行,是通知編譯器,我們這個類的聲明部分需要Cattle.h文件.這個文件我們已經(jīng)很熟悉了,是我們在第3章曾經(jīng)構(gòu)筑過的,在本章里面,我們不會改變里面的任何內(nèi)容.第4行,就是在通知編譯器,我們需要聲明一個類名字叫做Bull,從Cattle里面繼承過來。第5行,我們追加了一個實例變量skinColor,用來保存Bull的顏色。第7行,我們重載了在Cattle類里面已經(jīng)有的(void)saySomething實例方法。重載(void)saySomething方法的主要原因是,我們認為Bull說的話應該和Cattle有所區(qū)別。第8行到第9行,我們?yōu)锽ull類聲明了兩個新的方法(NSString*)getSkinColor和(void)setSkinColor:(NSString*)color,分別用來設定和讀取我們的實例變量skinColor.好的,我們總結(jié)一下繼承的時候的子類的格式。?interface類的名字:父類的名字{實體變量類型實體變量名字;)-(返回值類型)重載的方法名字;+(返回值類型)重載的方法名字;-(返回值類型)其他的方法名字:(變量類型)變量名字:(變量類型)變量名字;
@end,self和super我們再來打開"BuILm",在saySomething的定義的部分,我們發(fā)現(xiàn)了如下的代碼:NSLog(@"Hello,Iama%@bull,Ihave%dlegs.",[selfgetSkinColor],legsCount);我們在這句話當中,發(fā)現(xiàn)的第一個新朋友是%@,這是在告訴編譯器,需要把%@用ー個后面定義的字符串來替換,在這里我們給編譯器提供的字符串是[selfgetSkinColor]。看到這里,同學們又會發(fā)現(xiàn)ー個新的朋友self.在類的方法定義域之內(nèi),我們有的時候需要訪問這個類自己的實例變量,或者是方法。在類被實例化之后,我們就可以使用ー個指向這個類本身的ー個指針,在Java或者C++里面的名字叫做this,在〇bjective-C里面,這個名字是self,self本身是ー個id類型的ー個指針變量。我們在第3章里面講解過,方法的調(diào)用格式如下:[對象或者類名字方法名字:參數(shù)序列];在類的方法定義域里面,當我們需要調(diào)用類的其他方法的時候,我們需要指定對象或者類的名字,我們的方法是ー個實例方法所以我們需要一個指向自己的對象,在這里我們需要使用self.我們假設,如果方法聲明里面的參數(shù)序列里面有一個參數(shù)的名字和類的實例變量發(fā)生重復的情況下并且由于某種原因我們無法更改參數(shù)和實體變量的名字的話,我們應該如何應對呢?答案是使用self,格式如下
selfー〉變量名字通過這樣寫,我們可以取得到類的變量的數(shù)值。當然如果沒有名字沖突的話,我們完全可以省略self。,Xcode也足夠的聰明能夠識別我們的實例變量,并且把我們代碼里面的實例變量更改為相應的醒目的顏色。如果我們在類的方法里面需要訪問超類的方法或者變量(當然是訪問對子類來說是可視的方法或者變量),我們需要怎樣寫呢?答案是使用super,super在本質(zhì)上也是id的指針,所以,使用super訪問變量和方法的時候的書寫格式,和self是完全一樣的。"Bull.m"里面的其他的代碼,沒有什么新鮮的東西,所以筆者就不在這里贅述了。,超類方法和子類方法的執(zhí)行我們來看一下04-HelloInheritance.m的下面的代碼片斷l(xiāng)idredBull=[Bullnew];2[redBullsetLegsCount:4];3[redBullsetSkinColor:@"red"];4[redBullsaySomething];56Bull*blackBull=[Bullnew];7[blackBullsetLegsCount:4];8[blackBullsetSkinColor:@"blackn];9[blackBullsaySomething];第1行的代碼在第3章里面講解過,我們來看看第2行的代碼。
第2行的代碼實際上是向redBul!發(fā)送ー個setLegsCount消息,參數(shù)為4?我們沒有在Bull里面定義setLegsCount方法,但是從控制臺的輸出上來看,setLegsCount明顯是得到了執(zhí)行。在執(zhí)行的時候,我們給redBul!發(fā)送setLegsCount消息的時候(runtime會在Bull的映射表當中尋找setLegsCount,由于我們沒有定義所以runtime找不到的.runtime沒有找到指定的方法的話,會接著需要Bull的超類,也就是Cattle,值得慶幸的是runtime在Cattle里面找到了setLegsCount,所以就被執(zhí)行了。由于runtime已經(jīng)尋找到了目標的方法并且已經(jīng)執(zhí)行了,所以它就停止了尋找。我們假設runtime在Cattle里面也沒有找到,那么它會接著在Cattle的超類NSObject里面尋找,如果還是找不到的話,由于NSOBject是根類,所以它會報錯的。關于具體內(nèi)部是ー個怎樣的機制,我們將在后面的章節(jié)里面講解。第3行的代碼,是設定skinColor.第4行的代碼是給redBul!發(fā)送saySomething的消息.按照第2行的runtime的尋找邏輯,它首先會在Bull類里面尋找saySomething,這一次runtime很幸運,它一次就找到了,所以就立即執(zhí)行.同時runtime也停止了尋找的過程,所以,Cattle的saySomething不會得到執(zhí)行的.在第6行里面,我們定義了一個blackBull,但是這一次我們沒有使用id作為blackBull的類型,我們使用了Bull*.從本質(zhì)上來說,使用id還是Bull?是沒有任何區(qū)別的.但是,我們來想象,當我們的程序存在很多id類型的變量的話,我們也許就難以區(qū)分究竟是什么類型的變量了.所以,在沒有特殊的理由的情況之下,我們最好還是顯式的寫清楚類的名字,這樣可以方便其他人閱讀.由于Bul!從Cattle繼承而來,我們也可以把地6行代碼改為Cattle*blackBull=[Bullnew];f本章總結(jié)感謝大家閱讀到這里!我們在本章學習了:.超類,子類的概念以及如何定義和聲明。.selffnsuper的使用方法以及使用的時機。3,超類和子類的方法的執(zhí)行。5,Class類型,選擇器Selector以及指針函數(shù).本系列講座有著很強的前后相關性,如果你是第一次閱讀本篇文章,為了更好的理解本章內(nèi)容,筆者建議你最好從本系列講座的第1章開始閱讀,請點擊這里。.上一章筆者介紹了在〇bjective-C里面繼承的概念。有了繼承的知識我們可以重復的使用很多以前生效的代碼,這樣就大大的提高了代碼開發(fā)的效率。在本章,筆者要向同學們介紹幾個非常重要的概念(Class類型選擇器Selector以及指針函數(shù)。.我們在實際上的編程過程中,也許會遇到這樣的場景,那就是我們在寫程序的時候不能確切的知道我們需要使用什么類,使用這個類的什么方法。在這個時候,我們需要在我們的程序里面動態(tài)的根據(jù)用戶的輸入來創(chuàng)建我們在寫程序不知道的類的對象,并且調(diào)用這個對象的實例方法。Objective-C為我們提供了Class類型,選擇器Selector以及指針函數(shù)來實現(xiàn)這樣的需求,從而大大的提高了我們程序的動態(tài)性能。.在〇bjective-C里面,一個類被正確的編譯過后,在這個編譯成功的類里面,存在ー個變量用于保存這個類的信息。我們可以通過一個普通的字符串取得這個Class,也可以通過我們生成的對象取得這個Class.Class被成功取得之后,我們可以把這個Class當作一個已經(jīng)定義好的類來使用它..Selector和Class比較類似不同的地方是Selector用于表示方法。在〇bjective-C的程序進行編譯的時候,會根據(jù)方法的名字(包括參數(shù)列表)確定一個唯一的身份證明(實際上就是ー個整數(shù)),不用的類里面的相同名字相同聲明的方法的身份證明是ー樣的。這樣在程序執(zhí)行的時候,runtime就不用費カ的進行方法的名字比較來確定是執(zhí)行哪一個方法了,只是通過ー個整數(shù)的尋找就可以馬上定位到相應的方法,然后找到相應的方法的入口地址,這樣方法就可以被執(zhí)行了。.筆者在前面的章節(jié)里面敘述過,在〇bjective-C里面消息也就是方法的執(zhí)行比C語言的直接找到函數(shù)入口地址執(zhí)行的方式,從效率上來講是ヒ匕較低下的。盡管Objective-C使用了Selector等招數(shù)來提高尋找效率,但是無論如何尋找的過程I都是要消耗一定的時間的。好在〇bjective-C是完全兼容C的,它也有指針函數(shù)的概念。當我們需要執(zhí)行效率的時候,比如說在一個很大的循環(huán)當中需要執(zhí)行某個功能的時候,我們可以放棄向?qū)δ骋粋€對象發(fā)送消息的手段,用指針函數(shù)取而代之,這樣就可以獲得和C語言ー樣的執(zhí)行效率了。.說到這里,可能有的同學已經(jīng)有些茫然了。這些概念有些令人難以理解,但是它們確實是Objective-C的核心的功能。掌握了這些核心的功能之后,同學們可以很輕松的看懂蘋果的SDK里面的很多東西含義,甚至可以自己動手寫ー些蘋果沒有為我們提供的功能。所以建議大家仔細研讀本章的內(nèi)容,如果有什么問題,可以發(fā)個帖子大家可以共同探討。.從筆者的觀點上來看,對于有Java或者C++或者其他面向?qū)ο蟮恼Z言的經(jīng)驗的同學來說,前面的從第1到第4章
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 爬模施工方案
- 樁基正循環(huán)施工方案
- 工業(yè)廠房吊裝施工方案
- 樓道污水改道施工方案
- 巖礁施工方案模板
- 外墻圓弧石材施工方案
- 二零二五年度創(chuàng)業(yè)投資公司股權(quán)退出協(xié)議
- 二零二五年房產(chǎn)借名購買房產(chǎn)權(quán)屬變更協(xié)議
- 二零二五年度房地產(chǎn)項目建筑勞務派遣合同
- 二零二五年度旅游酒店經(jīng)營權(quán)整體轉(zhuǎn)讓合同樣本
- 義務教育《地理》課程標準(2022年版)
- 原子雜化軌道理論
- 充填開采之 矸石充填術(shù)
- 醫(yī)院醫(yī)療設備采購流程圖
- 單細胞蛋白論文
- 021[學士]某六層框架宿舍樓畢業(yè)設計(含計算書、圖紙)
- (完整版)高層鋼結(jié)構(gòu)住宅施工方案(非常詳細)
- 人力外包項目實施方案
- BQB480-2014無取向電工鋼
- 校園及設備設施安全隱患排查情況登記表
- 解析幾何期末考試試卷
評論
0/150
提交評論