1. 繼承
類和對象協(xié)同工作才能使程序實現(xiàn)功能锌仅。處理類和對象的關系時狱意,尤其要重視OOP的兩個方面秩贰。第一個方面是繼承曹抬,創(chuàng)建一個新類時疮蹦,通常需要根據(jù)它與現(xiàn)有類的區(qū)別來定義硬梁。使用繼承可以定義一個具有父類所有功能的新類娘摔,即它繼承了父類的功能纲堵。另一個和類有關的OOP技術是復合薛夜,也就是在對象中可以再引用其他對象航邢。對象引用其他對象時,可以引用其他對象提供的特性器瘪,這就是復合。
1.1為何使用繼承
UML(Unified Modeling Language, 統(tǒng)一建模語言)是一種用圖表來表示類、類的內(nèi)容以及它們之間關系的常見方式面哼。UML使用末端帶有箭頭的豎線表示繼承關系。
編程時如果出現(xiàn)很多的重復內(nèi)容扫步,就意味著這是一個失敗的架構魔策。OOP中的繼承表明一個類從另一個類—它的父類或超類(superclass)—中獲取了某些特性。
1.2繼承的語法格式
某些編程語言(例如C++)具有多繼承性河胎,也就是一個類可以直接從兩個或多個類繼承而來闯袒。但是Objective-C不支持多繼承。如果你嘗試在Objective-C中使用多繼承(多繼承的形式類似于以下語句@interface Circle : NSObject, PrintableObject) 是無法通過編譯器審核的游岳。
只有代碼精簡政敢,Bug才無處藏身。
在方法的定義中不寫任何內(nèi)容或返回一個虛值都是可以通過編譯的胚迫。
移植和優(yōu)化代碼的方式稱為重構喷户。進行重構時,會通過移植某些代碼來改進程序的架構晌区,而不必改變代碼的行為和運行結果摩骨。通常開發(fā)周期包括向代碼中添加某些特性通贞,然后通過重構刪除所有重復的代碼。有時在面向對象的程序中添加新特性之后恼五,程序反而變得更簡單昌罩。
超類是繼承的類。父類是超類的另一種表達方式灾馒。子類是執(zhí)行繼承的類茎用。孩子類是子類的另一種表達方式。如果要想改變方法的實現(xiàn)睬罗,需要重寫(override)繼承的方法轨功。代碼運行時,Objective-C會確保調用的是重寫過的方法容达。
1.3 繼承的工作機制
1.3.1 方法調度
當代碼發(fā)送消息時古涧,Objective-C的方法調度機制將在當前的類中搜索相應的方法。如果無法在接收消息的類文件中找到相應的方法花盐,它就會在該對象的超類中進行查找羡滑。必要時這種機制將會在繼承鏈的每一個類重復地執(zhí)行此操作,一直找到最頂層的超類(NSObject)中算芯。如果在最頂層的NSObject類中也沒有找到該方法柒昏,則會出現(xiàn)一個運行時錯誤,同時還會出現(xiàn)一個編譯時(Compile-time)警告信息熙揍。
調度程序通過指針來查找正確的代碼职祷。
1.3.2 實例變量
在創(chuàng)建一個新類時,其對象首先會從它的超類繼承實例變量届囚,然后根據(jù)自身情況來添加自己的實例變量有梆。
NSObject類聲明了一個名為isa的實例變量,該變量保存一個指向對象當前類的指針奖亚。使用更具體種類的對象來代替一般類型淳梦,這種能力被稱為多態(tài)性。每個方法調用都獲得了一個名為self的隱藏參數(shù)昔字,它是一個指向接收消息的對象的指針,通過self參數(shù)來尋找所需要的實例變量首繁。self指向繼承鏈中第一個類中的第一個實例變量作郭,所以,self一般指向的是isa弦疮。
編譯器使用“基地址加偏移”的機制實現(xiàn)奇妙的功能夹攒。有了對象的基地址,即第一個實例變量的首個字節(jié)在內(nèi)存中的位置胁塞,再在該地址上加上偏移地址咏尝,編譯器就可以查找其他實例變量的位置压语。每個實例變量與對象的基地址都有一個偏移位置。
1.4重寫方法
在制作全新的子類時编检,經(jīng)常會添加自己的方法胎食。有時你會添加一個能夠向類中引入特有功能的新方法,有時你會替換或改進某個超類定義的現(xiàn)有方法允懂。你也可以選擇不添加新特性厕怜,而是創(chuàng)建一個子類并通過它重寫繼承自超類的行為。
Objective-C提供了一種方法蕾总,讓你既可以重寫方法的實現(xiàn)粥航,又能調度超類中的實現(xiàn)方式。當需要超類實現(xiàn)自身的功能生百,同時在之前或之后執(zhí)行某些額外的工作時递雀,這種機制非常有用。為了調用繼承的方法在父類中的實現(xiàn)蚀浆,需要使用super作為方法調用的目標映之。Super既不是參數(shù)也不是實例變量,而是由Objective-C編譯器提供的一種神奇的功能蜡坊。當你向super發(fā)送消息時杠输,實際上是在請求OC向該類的超類發(fā)送消息。如果超類中沒有定義該消息秕衙,OC會向平常一樣繼續(xù)在繼承鏈上一級中查找蠢甲。
調用繼承的方法可以確保獲得方法實現(xiàn)的所有特性。繼承是在兩個類之間建立關系的一種方式据忘,可以避免許多重復的代碼鹦牛。
復合(讓不同的對象協(xié)同工作的一種方式)— 建立類之間關系的另外一種方式。
復合是通過包含作為實例變量的對象指針實現(xiàn)的勇吊。只有對象間的組合才能叫做復合曼追。諸如int、float汉规、enum和struct等基本類型只被認為是對象的一部分礼殊。
如果在類中沒有包含實例變量,便可以省略掉接口定義中的花括號针史。
2.1 自定義NSLog()
NSLog()可以使用%@格式說明符來輸出對象晶伦。
NSLog()處理%@說明符時,會詢問參數(shù)列表中相應的對象以得到這個對象的描述啄枕。從技術上來講婚陪,也就是NSLog()給這個對象發(fā)送了description消息,然后對象的description方法生成一個NSString并將其返回频祝。NSLog()就會在輸出結果中包含這個字符串泌参。在類中提供description方法就可以自定義NSLog()會如何輸出對象脆淹。在自定義的description方法中,你可以選擇返回一個字面量值NSString , 也可以構造一個用來描述該對象各類信息的字符串沽一。
在Cocoa中盖溺,NSArray類管理的是對象的集合,它的description方法提供了數(shù)組自身的信息锯玛,例如數(shù)組中對象的個數(shù)和每個對象所包含的描述咐柜。對象的描述是通過向數(shù)組中的每個對象分別發(fā)送description消息來獲得的。
每一個類實例對象都會為指向它的實例變量的指針分配內(nèi)存攘残,真正包含在類實例對象中的并不是它的實例變量拙友,只是內(nèi)存中存在的其他對象的引用指針。
使用new創(chuàng)建新對象時歼郭,系統(tǒng)其實在后臺執(zhí)行了兩個步驟:第一步遗契,為對象分配內(nèi)存,即對象獲得一個用來存放實例變量的內(nèi)存塊病曾;第二步牍蜂,自動調用init方法,使該對象進入可用狀態(tài)泰涂。
為了讓超類將所有需要的初始化工作一次性完成鲫竞,你需要調用[super init]。init方法返回的值(id類型數(shù)據(jù)逼蒙,即泛型對象指針)就是被初始化的對象从绘。將[super init]返回的結果賦給self是OC的慣例。這樣做的目的是為了防止超類在初始化過程中返回的對象與一開始創(chuàng)建的不一致是牢。
2.2 存取方法
存取方法是用來讀取或改變某個對象屬性的方法僵井。為對象中的變量賦值的方法稱為setter方法。mutator方法是用來更改對象狀態(tài)的驳棱。getter方法為代碼提供了通過對象自身訪問對象屬性的方式批什。
如果要對其他對象中的屬性進行操作,應該盡量使用對象提供的存取方法社搅,絕對不能直接改變對象里面的值驻债。存儲方法是程序間接工作的另一個例子。(通過對象自身訪問對象屬性或者對對象屬性進行設置)
存取方法總是成對出現(xiàn)的罚渐。一個用來設置屬性的值却汉,另一個用來讀取屬性的值。有時只有一個getter方法(用于只讀屬性荷并,例如磁盤上文件的大小)或者只有一個setter方法(例如設置密碼)也是合理的。
對于存取方法的命名青扔,Cocoa有自己的慣例源织。setter方法根據(jù)它所更改的屬性的名稱來命名翩伪,并加上前綴set。getter方法則以其返回的屬性名稱命名谈息。
2.2.1 設置對象屬性的存取方法
在OC中所有對象間的交互都是通過指針實現(xiàn)的缘屹。
防御式編程是一種很好的編程思想。防御式編程能夠在開發(fā)早期發(fā)現(xiàn)錯誤侠仇。例如用通用代碼來檢查數(shù)組的索引下表是否超出范圍轻姿。數(shù)組越界是程序開發(fā)中常見的一種錯誤。數(shù)組的下表范圍(0~數(shù)組長度-1)逻炊,若使用超出這個范圍內(nèi)的索引值便會訪問到內(nèi)存中的隨機值互亮,由此產(chǎn)生的Bug會導致程序crash。
重構(重構程序余素,改進內(nèi)部結構豹休,并不影響它的外部行為)。
2.3 復合還是繼承桨吊?
繼承的類之間建立的關系為“is a”(是一個)威根。如果可以說“X是一個Y”, 那就可以使用繼承。復合的類之間建立的關系為“has a”(有一個)视乐。如果可以說“X有一個Y”,那么就可以使用復合洛搀。應當在適當?shù)臅r機使用繼承和復合特性。
復合是OOP的基礎概念佑淀,我們通過這種技巧來創(chuàng)建引用其他對象的對象留美。存取方法,既為外部對象提供了改變其屬性的途徑渣聚,同時又能保護實例變量本身独榴。 存取方法和復合是密不可分的,因為我們通常都會為復合的對象編寫存取方法奕枝。有兩種類型的存取方法:setter方法和getter方法棺榔,前者告訴對象將屬性改為什么,后者要求對象提供屬性的值隘道。對于返回屬性值的存取方法症歇,名稱中不能使用get這個詞。
《Objective-C基礎編程》讀書筆記3—面向對象編程2
最后編輯于 :
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來序六,“玉大人任连,你說我怎么就攤上這事±鳎” “怎么了随抠?”我有些...
- 文/不壞的土叔 我叫張陵,是天一觀的道長繁涂。 經(jīng)常有香客問我拱她,道長,這世上最難降的妖魔是什么爆土? 我笑而不...
- 正文 為了忘掉前任椭懊,我火速辦了婚禮,結果婚禮上步势,老公的妹妹穿的比我還像新娘氧猬。我一直安慰自己,他們只是感情好坏瘩,可當我...
- 文/花漫 我一把揭開白布盅抚。 她就那樣靜靜地躺著,像睡著了一般倔矾。 火紅的嫁衣襯著肌膚如雪妄均。 梳的紋絲不亂的頭發(fā)上,一...
- 文/蒼蘭香墨 我猛地睜開眼寄症,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了矩动?” 一聲冷哼從身側響起有巧,我...
- 正文 年R本政府宣布命锄,位于F島的核電站堰乔,受9級特大地震影響,放射性物質發(fā)生泄漏脐恩。R本人自食惡果不足惜镐侯,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驶冒。 院中可真熱鬧苟翻,春花似錦、人聲如沸骗污。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽需忿。三九已至诅炉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屋厘,已是汗流浹背涕烧。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- 一.條件語句 1.條件語句體應該總是被大括號包圍來避免錯誤溯香,即使可以不用鲫构。 推薦: 不推薦: 不推薦: 2.不要使...
- 工廠方法模式 定義創(chuàng)建對象的接口,讓子類決定實例化哪一個類玫坛。工廠方法使得一個類的實例化延遲到其子類结笨。 生成器模式 ...