封裝
本小節知識:
- 面向對象三大特性
- 什麼是封裝
- 爲什麼要進行封裝?
- 封裝的好處和原則
1.面向對象三大特性
- 封裝性
- 繼承性
- 多態性
2.什麼是封裝
- 封裝就是隱藏實現細節,僅對外公開接口;
- 類是數據與功能的封裝,數據就是成員變量,功能就類方法或對象方法;
對數據的封裝,也就是對成員變量的封裝 。
注意:成員變量都需要封裝起來。
原則:將不需要對外提供的內容都隱藏起來,把屬性都隱藏,提供公共的方法對其訪問
3.爲什麼要進行封裝?
如果希望成員變量能夠被外界訪問,則必須是@public的,也就是公開的,但我們不能控制外界如何賦值, 外界有可能賦值一些沒用的數據
不封裝的缺點:當一個類把自己的成員變量暴露給外部的時候,那麼該類就失去對該成員變量的管理權,別人可以任意的修改你的成員變量。
4.封裝的好處
- 將變化隔離;
- 提高安全性;
- 不可被外部任意修改;降低了數據被誤用的可能性;
- 提高代碼的靈活性。
問題:封裝的規範?
- 規範: 一般情況下不會對外直接暴露成員變量, 都會提供一些共有的方法進行賦值
1.setter方法
作用:用來設置成員變量,可以在方法裏面過濾掉一些不合理的值
命名規範:
1. 必須是對象方法 2. 返回值類型爲void 3. 方法名必須以set開頭,而且後面跟上成員變量名去掉”_” 首字母必須大寫 4. 必須提供一個參數,參數類型必須與所對應的成員變量的類型一致 5. 形參名稱和成員變量去掉下劃線相同
舉例:
如:如果成員變量爲int _age 那麼與之對應seter方法爲 -(void) setAge: (int) age;
優點:
1. 不讓數據暴露在外,保證了數據的安全性 2. 對設置的數據進行過濾
2.getter方法
- 作用:爲調用者返回對象內部的成員變量的值
- 命名規範:
objectivec
<ol><li>必須是對象方法</li>
<li>必須有返回值,返回值的類型和成員變量的類型一致</li>
<li>方法名必須是成員變量去掉下劃線</li>
<li>一定是沒有參數的
舉例:
如:如果成員變量爲int _age 那麼與之對應geter方法爲 - (int) age;
優點:可以讓我們在使用getter方法獲取數據之前,對數據進行加工;
3.getter/setter方法注意
在實際的開發中,不一定set和get方法都會提��供,如果內部的成員變量,比如學生的學號或計算出來的數據。這樣的數據只允許外界讀取,但是不允許修改的情況,則通常只提��供get方法而不��提供set方法
。成員變量名的命名以下劃線開頭,get方法名不需要帶下劃線
成員變量名使用下劃線開頭有兩個好處
- 與get方法的方法名區分開來
- 可以和一些其他的局部變量區分開來,下劃線開頭的變量,通常都是類的成員變量。當我看到以下劃線開頭變量,那麼他一定是成員變量
問題:成員變量以下劃線開頭有什麼好處?
- 用於和局部變量/全局變量/形參區分
- 方便程序編碼, 提高編碼效率
自定義代碼段
本小節知識點:
- 如何自定義代碼片段
- 如何導入代碼片段
1.如何自定義代碼片段
- 將代碼拖拽到code區域
- 配置快捷鍵等信息
- 使用自定義代碼段快捷鍵
2.如何導入代碼片段
將下載好的代碼片段拷貝到:`
/Users/你的用戶名/Library/Developer/Xcode/UserData/CodeSnippets文件夾裏
問題:自定義快捷鍵的格式是什麼?在代碼庫中的設置是怎麼樣的?
- 自定義快捷鍵的格式 <#name#>
點語法(重點)
本小節知識點:
- 【掌握】點語法的本質
- 【掌握】點語法注意
- 【掌握】點語法基本使用
1.點語法的本質
- 其實點語法的本質還是方法調用
- 當使用點語法時,編譯器會自動展開成相應的setter/getter方法;
- 當點語法使用在 “=“賦值符號左側的時候,點語法會被展開爲setter方法的調用;
- 其他情況(等號右側、直接使用)爲點語法展開爲getter方法的調用
2.點語法注意
- 點語法的本質是方法的調用,而不是訪問成員變量,當使用點語法時,編譯器會自動展開成相應的方法調用。
- 切記點語法的本質是轉換成相應的對setter和getter方法調用,如果沒有set和get方法,則不能使用點語法。
- 不要在getter 與 setter方法中使用本屬性的點語法來點自己,造成死循環
- (void) setAge:(int)age {
// 下面的代碼會引發死循環
self.age = age;
//self.gae 編譯器展開後 [self setAge:age]
}
- (int) age {
// 下面的代碼會引發死循環
return self.age;
//self.age 編譯器展開後 [self age]
}
3.點語法基本使用
- 點語法是一個編譯器的特性, 會在程序翻譯成二進制的時候將.語法自動轉換爲setter和getter方法
- 如果點語法在=號的左邊, 那麼編譯器會自動轉換爲setter方法
- 如果點語法在=號的右邊, 或者沒有等號, 那麼編譯器就會自動轉換爲getter方法
- 點語法一般用於給成員變量賦值, 如果不是給成員變量賦值一般情況下不建議使用, 但是也可以使用
Self關鍵字
本小節知識點:
- 類方法中的self
- 對象方法中的self
- 全局變量成員變量局部變量
- self總結
- self使用注意
- OC提��供了兩個保留字self和super
- OC語言中的self,就相當於C++、Java中的this指針。
1.類方法中的self
- 在整個程序運行過程中,
一個類有且僅有一個類對象
。 - 通過
類名
調用方法就是給這個類對象
發送消息。 - 類方法的self就是這個類對象
- 在類方法中可以通過self來調用其他的類方法
- 不能在類方法中去調用對象方法或成員變量,因爲對象方法與成員變量都是屬於具體的實例對象的。
2.對象方法中的self
- 在整個程序運行過程中,
對象可以有0個或多個
- 通過
對象
調用方法就是給這個對象
發送消息 - 對象方法中self就是調用這個方法的當前對象。
- 在對象方法中,可以通過self來調用本對象上的其他方法
- 在對象方法中,可以通過self來訪問成員變量
3.全局變量成員變量局部變量
- 全局變量:只要是有聲明它的地方都能使用
- 成員變量:只能在本類和其子類的對象方法中使用
- 局部變量:只能在本函數或方法中使用
- 從作用域的範圍來看:全局變量 > 成員變量 > 局部變量
- 當不同的作用域中出現了同名的變量,內部作用域的變量覆蓋外部作用域變量,所以同名變量的覆蓋順序爲:局部變量覆蓋成員變量,成員變量覆蓋全局變量
- 可以通過self->成員變量名的方式,區分成員變量和局部變量同名的情況
4.self總結
- 誰調用self所在的方法,那麼self就是誰
- self在類方法中,就是這個類的類對象,全局只有一個,可通過self調用本類中的其他類方法,但是不能通過self來調用對象方法或訪問成員變量
- self在對象方法中,就是調用這個方法的那個對象, 可以通過self調用本類中其他的對象方法,訪問成員變量,但不能通過self調用本類的類方法。
- 通過self調用方法的格式:[self 方法名];
- 通過self訪問成員變量格式:self->成員變量名
5.self使用注意
- 同時有對象方法和類方法存在的時候,self不會調錯
- self只能在方法中使用;不要使用self來調用函數,也不可以在函數內部使用self;
- 使用self調用本方法,導致死循環調用。
問題1:什麼是成員變量?什麼是對象方法?什麼是類方法?
成員變量:成員變量是一個實例對象的具體狀態特徵,並且這些狀態特徵是可以改變的,如張三的年齡,身高,體重等
對象方法:一個實例對象的行爲,比如張三具有喫的行爲,張三做出這樣行爲的時候,有可能會影響,自身的某些狀態特徵,比如張三喫可能會增加張三體重和身高。
類方法:類方法是某個類的行爲,可以直接通過類名調用;如果在類方法中需要使用某些數據,必須通過參數傳入;它不能訪問成員變量。
繼承的基本概念
本小節知識點:
- 繼承基本概念
- OC中的繼承關係
- OC中如何實現繼承
1.繼承基本概念
- 現實生活中的繼承;
- 交通工具類是一個基類(也稱做父類),通常情況下所有交通工具所共同具備的特性,如速度與額定載人的數量;
- 飛機類和汽車類的特性是由在交通工具類原有特性基礎上增加而來的,那麼飛機類和汽車類就是交通工具類的派生類(也稱做子類)。以此類推,層層遞增, 這種子類獲得父類特性的概念就是繼承。
2.OC中的繼承關係
B類繼承A類,那麼B類將擁有A類的所有屬性和方法,此時我們說A類是B類的父類,B類是A類的子類
C類繼承B類,那麼C類將擁有B類中的所有屬性和方法,包括B類從A類中繼承過來的屬性和方法,此時我們說B類是C類的父類,C類是B類的子類
注意:
- 基類的私有屬性能被繼承,不能在子類中訪問。
- OC中的繼承是單繼承:也就是說一個類只能一個父類,不能繼承多個父類
- 子類與父類的關係也稱爲isA(是一個)關係,我們說 子類isA父類,也就是子類是一個父類,比如狗類繼承動物類,那麼我們說狗isA動物,也就是狗是一個動物。在如汽車繼承交通工具,那麼們說汽車isA交工工具,也就是汽車是一個交通工具
- 繼承的合理性:引用《大話西遊》裏的一句話來描述繼承的。“人是人他媽生的,妖是妖他媽生的!”
3.OC中如何實現繼承
- 在聲明子類的時候,在子類名稱後面通過:父類名稱方式來實現繼承
@interface 子類名稱 : 父類名稱
......
@end
問題1:什麼是繼承?什麼是父類?什麼是子類?如何實現繼承?
- 子類獲得父類的特性就是繼承
- 被繼承的這個類我們稱之爲父類/ 超類
- 繼承了某個類的類我們稱之爲子類
在聲明子類的時候,在子類名稱後面通過:父類名稱方式來實現繼承
@interface 子類名稱 : 父類名稱 //其他語句 @end
當B類繼承A類, 那麼B類就擁有A類所有的屬性和方法(類方法/對象方法)
繼承的相關特性
本小節知識點:
- 方法重寫
- 繼承中方法調用的順序
- 繼承的注意事項
1.方法重寫
- 在子類中實現與父類中同名的方法,稱之爲方法重寫;
- 重寫以後當給子類發送這個消息的時候,執行的是在子類中重寫的那個方法,而不是父類中的方法。
如果想在子類中調用被子類重寫的父類的方法,可以通過super關鍵字
注意:在繼承中方法可以重寫, 但是屬性(成員變量)不能重寫
2.繼承中方法調用的順序
- 在自己類中找
- 如果沒有,去父類中找(逐級往上找)
- 如果父類也沒有,就還往上找,直到找到基類(NSObject)
- 如果NSObject都沒有就報錯了:
reason:-[Iphone signalWithNumber:]: unrecognized selector sent to instance 0x1003043c0
- 總之:如果找到了就執行這個方法,並且不再往後查找了,如果一直都到NSObject都沒找不到則報錯。
3.繼承的注意事項
子類不能定義和父類同名的成員變量,私有成員變量也不可以;因爲子類繼承父類,子類將會擁有父類的所有成員變量,若在子類中定義父類同名成員變量 屬於重複定義。
OC類支持單一繼承,不支持多繼承;也就是說一個類只能有一個直接父類
OC類支持多層繼承
問題1:方法重寫的使用場景?
使用場景:當從父類繼承的某個方法不適合子類,可以在子類中重寫父類的這個方法。
問題3:繼承的條件是什麼?
不要以爲繼承可以提高代碼的複用性, 以後但凡發現多個類當中有重複代碼就抽取一個父類 只要滿足一定的條件我們才能使用繼承;
條件: XXXX 是 XXX / 某某某 is a 某某某
問題4:繼承的優點是什麼?
提高代碼的複用性
可以讓類與類之間產生關係, 正是因爲繼承讓類與類之間產生了關係所以纔有了多態
問題5:繼承的缺點是什麼?
耦合性太強(依賴性太強)
Super關鍵字
本小節知識點:
- super基本概念
- super的作用
1.super基本概念
super是個編譯器的指令符號,只是告訴編譯器在執行的時候,去調誰的方法.
1. self是一個隱私參數; 2. super 並不是隱藏的參數,它只是一個“編譯器指示符”,它和 self 指向的是相同的消息接收者
2.super的作用
- 使用super一定會直接調用父類中的某個方法
- super在對象方法中,那麼就會調用父類的對象方法
- super在類方法中,那麼就會調用父類的類方法
問題:super使用場景?
答: 子類重寫父類的方法時想保留父類的一些行爲
多態基本概念
本小節知識點:
- 【瞭解】什麼是多態?
- 【掌握】多態的條件
- 【瞭解】多態的優點
1.什麼是多態?
什麼是多態:多態就是某一類事物的多種形態
貓: 貓-->動物 狗: 狗-->動物 男人 : 男人 -->人 -->高級動物 女人 : 女人 -->人 -->高級動物
程序中的多態:父類指針指向子類對象
2.多態的條件
- 有繼承關係
- 子類重寫父類方法
父類指針指向子類對象
狗 *g = [狗 new]; 動物 *a = [狗 new]; 貓 *c = [貓 new]; 動物 *a = [貓 new];
表現:當父類指針指向不同的對象的時候,通過父類指針調用被重寫的方法的時候,會執行該指針所指向的那個對象的方法
3.多態的優點
多態的主要好處就是簡化了編程接口。它允許在類和類之間重用一些習慣性的命名,而不用爲每一個新的方法命名一個新名字。這樣編程接口就是一些抽象的行爲的集合,從而和實現接口的類的區分開來。
多態也使得代碼可以分散在不同的對象中而不用試圖在一個方法中考慮到所有可能的對象。這樣使得您的代碼擴展性和複用性更好一些。當一個新的情景出現時,您無須對現有的代碼進行 改動,而只需要增加一個新的類和新的同名方法。
優點總結:提高了代碼的擴展性,複用性
多態的注意點
- 如果父類指針指向子類對象, 需要調用子類特有的方法, 必須先強制類型轉換爲子類才能調用
多態的實現
本小節知識點:
- 【掌握】如何實現多態
- 【瞭解】多態的原理
- 【掌握】多態的注意點
1.如何實現多態
- Animal是父類,子類有Cat 和 Dog,子類分別重寫了父類中的eat方法;實例化對象的時候可以用下面的方法:
Animal *animal = nil;
//實例化貓的對象
animal = [Cat new];
[animal eat];
//實例化狗的對象
animal = [Dog new];
[animal eat];
2.多態的原理
動態綁定:
- 動態類型能使程序直到執行時才確定對象的真實類型
- 動態類型綁定能使程序直到執行時才確定要對那個對象調用的方法
OC不同於傳統程序設計語言,它可以在運行時加入新的數據類型和新的程序模塊:動態類型識別,動態綁定,動態加載
- id類型:通用對象指針類型,弱類型,編譯時不進行具體類型檢查
3.多態的注意點
1)如果存在多態,父類是可以訪問子類特有的方法
假設 子類 Dog 有一個特有的方法bark [dog bark]; Animal *an2 = [Dog new]; [(Dog*)an2 bark]; //把父類的指針,強制類型轉換
2)如果不存在多態,父類是不可以訪問子類特有的方法的
Animal *an3 = [Animal new]; [(Dog*)an3 bark]; //錯誤的,不能強制轉換
實例變量修飾符
本小節知識點:
- 【理解】實例變量的作用域
- 【掌握】變量修飾符在子類中的訪問
- 【瞭解】實例變量作用域使用注意事項
1.實例變量的作用域
- 1)@public (公開的)在有對象的前��下,任何地方都可以直接訪問。
- 2)@protected (受保護的)只能在當前類和子類的對象方法中訪問
- 3)@private (私有的)只能在當前類的對象方法中才能直接訪問
- 4)@package (框架級別的)作用域介於私有和公開之間,只要處於同一個框架中相當於@public,在框架外部相當於@private
2.變量修飾符在子類中的訪問
- 1)@private私有成員是能被繼承,也不能被外部方法訪問。
- 2)@public 公有成員能被繼承,也能被外部方法訪問。
- 3)@protected 保護成員能夠被繼承,不能夠被外部方法訪問。
3.實例變量作用域使用注意事項
- (1)在@interface @end之間聲明的成員變量如果不做特別的說明,那麼其默認是protected 的。
- (2)一個類繼承了另一個類,那麼就擁有了父類的所有成員變量和方法,注意所有的成員變量它都擁有,只是有的它不能直接訪問。例如@private的
問題1:實例變量修飾符有那幾個關鍵字?被修飾的實例變量在本類/子類/其他類中是否能被訪問?
@public
1. 可以在其它類中訪問被public修飾的成員變量 2. 也可以在本類中訪問被public修飾的成員變量 3. 可以在子類中訪問父類中被public修飾的成員變量
@private
1. 不可以在其它類中訪問被private修飾的成員變量 2. 可以在本類中訪問被private修飾的成員變量 3. 不可以在子類中訪問父類中被private修飾的成員變量
@protected
1. 不可以在其它類中訪問被protected修飾的成員變量 2. 可以在本類中訪問被protected修飾的成員變量 3. 可以在子類中訪問父類中被protected修飾的成員變量 注意: 默認情況下所有的實例變量都是protected
@package
1. 介於public和private之間的 2. 如果是在其它包中訪問那麼就是private的 3. 如果是在當前代碼所在的包種訪問就是public的
問題2:如何判斷實例變量修飾符作用域?
- 從出現的位置開始, 一直到下一個修飾符出現,如果沒有遇到下一個實例變量修飾符, 那麼就會修飾後面所有的實例變量
description方法
本小節知識點:
- 【掌握】description基本概念
- 【掌握】description重寫的方法
- 【瞭解】description陷阱
1.description基本概念
NSLog(@”%@”, objectA);這會自動調用objectA的description方法來輸出ObjectA的描述信息.
description方法默認返回對象的描述信息(默認實現是返回類名和對象的內存地址)
description方法是基類NSObject 所帶的方法,因爲其默認實現是返回類名和對象的內存地址, 這樣的話,使用NSLog輸出OC對象,意義就不是很大,因爲我們並不關心對象的內存地址,比較關心的是對象內部的一些成變量的值。因此,會經常重寫description方法,覆蓋description方法 的默認實現
2.description重寫的方法
對象方法
/*對象方法:當使用NSLog輸出該類的實例對象的時候調用*/ -(NSString *) description { return [NSString stringWithFormat:@"狗腿數:%d,狗眼數%d\n",_legNum,_eyeNum]; }
類方法
/**類方法:當使用NSLog輸出該類的類對象的時候調用*/ +(NSString *) description { return @"+開頭的description方法"; }
3.description陷阱
千萬不要在description方法中同時使用%@和self,下面的寫法是錯誤的
- (NSString *)description { return [NSString stringWithFormat:@"%@", self]; //這樣會造成死循環,每次執行到%@的時候,由於是self都會調用description方法,不斷的返回去調用自己 }
同時使用了%@和self,代表要調用self的description方法,因此最終會導致程序陷入死循環,循環調用description方法
當[NSString stringWithFormat:@“%@”, self]; 使用它時,循環調用,導致系統會發生運行時錯誤。
當該方法使用NSLog(“%@”,self) 時候, 系統做了相關的優化,循壞調用3次後就會自動退出
問題1:使用%@打印一個對象,輸出的是什麼內容?%@的原理是什麼?
%@是用來打印對象的, description方法默認返回對象的描述信息(默認實現是返回類名和對象的內存地址). 其實%@的本質是用於打印字符串.
只要利用%@打印某個對象, 系統內部默認就會調用父類的description方法 調用該方法, 該方法會返回一個字符串, 字符串的默認格式 <類的名稱: 對象的地址>
問題2:重寫description方法注意點?
如果在description方法中利用%@輸出self會造成死循環
建議: 在description方法中儘量不要使用self來獲取成員變量 因爲如果你經常在description方法中使用self, 可能已不小心就寫成了 %@, self