1. 使用 #import 相對(duì)c的 include 是防止頭文件的重復(fù)導(dǎo)入
2. NSLog 相對(duì)于 printf 會(huì)自動(dòng)換行 顯示當(dāng)前時(shí)間與項(xiàng)目的基本信息
3. ?OC中的對(duì)象方法用 - 開頭表示 ?類方法用 + 開頭表示, 對(duì)象方法只能通過對(duì)象來調(diào)用 也就是說 通過指針來調(diào)用 ?類方法只能通過類來調(diào)用
4. 使用對(duì)象方法,創(chuàng)建一個(gè)對(duì)象開辟一個(gè)存儲(chǔ)空間 ? 如果不想使用方法都需要?jiǎng)?chuàng)建對(duì)象開辟存儲(chǔ)空間,可以把方法定義為類方法。 ? 類方法不需要去創(chuàng)建存儲(chǔ)空間 優(yōu)化性能 ?
5. 對(duì)象方法可以直接訪問屬性(成員變量)類方法不可以
6. 類方法的優(yōu)點(diǎn) 調(diào)用類方法的效率會(huì)比調(diào)用對(duì)象方法要高
7. 類方法和對(duì)象方法可以相互調(diào)用 對(duì)象方法可以直接調(diào)用類方法, 類方法中可以間接調(diào)用對(duì)象方法?
8. 創(chuàng)建對(duì)象: 1. 開辟存儲(chǔ)空間 2. 初始化所有屬性 3. 返回指針地址?
9. 存儲(chǔ)空間 : 代碼區(qū) ?堆區(qū) 棧區(qū) ?在堆區(qū)初始化對(duì)象 在棧區(qū)存放對(duì)象的地址
10. 創(chuàng)建對(duì)象的時(shí)候返回的地址其實(shí)就是類的第0個(gè)屬性的地址 ?,但是類的第0個(gè)屬性其實(shí)是isa屬性(自動(dòng)創(chuàng)建)isa是一個(gè)指針,占八個(gè)字節(jié)
11. 類對(duì)象是系統(tǒng)幫我們創(chuàng)建的,里面保存了當(dāng)前的所有方法,實(shí)例對(duì)象是我們通過new方法自己創(chuàng)建的。
12. 寫在類聲明的大括號(hào)中的變量,我們稱之為成員變量(或者屬性,實(shí)例變量),成員變量只能通過對(duì)象來訪問,成員變量不能離開類,離開類之后就不是成員變量,成員變量不能再定義的時(shí)候進(jìn)行初始化, ?存儲(chǔ)在堆里面,存儲(chǔ)在堆中的數(shù)據(jù),不會(huì)被自動(dòng)釋放,只能程序員手動(dòng)釋放
13.寫在函數(shù)或者代碼塊中的變量,我們稱之為局部變量,作用域:從定義的那一行開始,一直到遇到大括號(hào)或者return,作用域變量可以先定義在初始化,也可以定義的時(shí)候同時(shí)初始化, 存儲(chǔ)在棧里面, ?存儲(chǔ)棧中的數(shù)據(jù)有一個(gè)特點(diǎn),系統(tǒng)會(huì)自動(dòng)給我們釋放
14. 寫在函數(shù)和大括號(hào)外部的變量,我們稱之為全局變量,作用域:從定義的那一行開始,一直到文件末尾,局部變量可以先定義在初始化,也可以定義的同時(shí)初始化,存儲(chǔ)在靜態(tài)區(qū)中,程序一啟動(dòng)的時(shí)候就會(huì)分配存儲(chǔ)空間,直到程序結(jié)束才釋放. 存儲(chǔ)在當(dāng)前對(duì)象對(duì)應(yīng)的存儲(chǔ)空間中
15. 函數(shù)和方法的區(qū)別:函數(shù)屬于整個(gè)文件,方法屬于某一個(gè)類,方法只能通過對(duì)象或類調(diào)用, 函數(shù)可以直接調(diào)用,雖然函數(shù)屬于整個(gè)文件,但是如果把函數(shù)寫在類的聲明中會(huì)不識(shí)別,不能把函數(shù)當(dāng)做方法來調(diào)用,也不能把方法當(dāng)做函數(shù)來調(diào)用
16. 方法:屬性方法,類方法 ? ?方法可以沒有聲明只有實(shí)現(xiàn), 方法也可以只有聲明沒有實(shí)現(xiàn),第二種情況:編譯時(shí)不會(huì)報(bào)錯(cuò),運(yùn)行會(huì)報(bào)錯(cuò) unrecoginized selector sent to class'0x12132' 發(fā)送了一個(gè)不能識(shí)別的消息
17. 函數(shù)中不能直接訪問成員變量, 成員變量和方法不能用static關(guān)鍵字修飾,不要和c語言混淆
18. 封裝:屏蔽內(nèi)部實(shí)現(xiàn)的細(xì)節(jié),僅僅對(duì)外提供共有的方法/接口 好處:保證數(shù)據(jù)的安全性,對(duì)傳入的數(shù)據(jù)進(jìn)行隔離。一般情況下不會(huì)對(duì)外直接暴露成員變量,都會(huì)提供一些共有的方法進(jìn)行復(fù)制,成員變量都被封裝起來
19. 由于經(jīng)常需要定義一些方法來操作成員變量,而每個(gè)方法都必須有一個(gè)有意義的名稱,所有就有了getter-setter方法(為了取名方便)程序員的一種規(guī)范
20. setter方法的作用:設(shè)置成員變量的值,setter方法一定是對(duì)象方法,一定沒有返回值,一定以set開頭,并且set后面跟上需要設(shè)置的成員變量的名稱去掉下劃線,并且首字母大寫,一定有參數(shù)(為成員變量設(shè)置set和get方法)
21. getter方法:獲取成員變量的值,getter一定是對(duì)象方法,一定有返回值,而且返回值一定和獲取的成員變量的類型一致,方法名稱就是獲取的成員變量的名稱去掉下劃線即可,一定沒有參數(shù)
22. 成員變量以下劃線開頭的好處,就是可以用于區(qū)分局部變量和成員變量
23. 如果給屬性提供了getter和setter方法,那么訪問屬性就可以用點(diǎn)語法進(jìn)行訪問了
24. 點(diǎn)語法的本質(zhì)就是調(diào)用setter和getter方法,點(diǎn)語法是一個(gè)編譯器的特性,會(huì)在程序編譯成二進(jìn)制的時(shí)候?qū)Ⅻc(diǎn)語法自動(dòng)轉(zhuǎn)化成setter和getter方法。
25. 如果點(diǎn)語法在等號(hào)左邊,那么系統(tǒng)會(huì)自動(dòng)轉(zhuǎn)換成setter方法,如果點(diǎn)語法在等號(hào)右邊,或者沒有等號(hào),那么編譯器就會(huì)自動(dòng)轉(zhuǎn)換為getter方法
26. 點(diǎn)語法一般用于給成員變量賦值,如果不是給成員變量賦值一般情況下不建議使用,但也可以使用。
27. ? self 會(huì)自動(dòng)區(qū)分類方法和對(duì)象方法,如果在類方法中使用self調(diào)用對(duì)象 方法,那么會(huì)直接報(bào)錯(cuò)。
28. super 是編譯器的指令符號(hào),如果調(diào)用父類的方法的時(shí)候?yàn)榱吮苊舛嘤啻a ? 用super去調(diào)用父類的方法。。。。如果想在子類中調(diào)用父類的方法用super ?, ?如果用self會(huì)先在子類中去找,如果出現(xiàn)和父類的方法重名,會(huì)出現(xiàn)死循環(huán)。super應(yīng)用環(huán)境:已經(jīng)重寫父類的方法,想保留父類的功能。
29. 程序中多態(tài):父類指針指向子類的對(duì)象,沒有繼承就沒有多態(tài)。 多態(tài)指一種事物的多種表現(xiàn)形態(tài)。多態(tài)具有動(dòng)態(tài)類型,在編譯的時(shí)候編譯器只會(huì)檢查當(dāng)前類型對(duì)應(yīng)的類中有沒有需要調(diào)用的方法,在運(yùn)行時(shí),系統(tǒng)會(huì)自動(dòng)判斷真實(shí)類型。 如果想調(diào)用子類特有的方法必須強(qiáng)制類型轉(zhuǎn)換為子類才能調(diào)用。優(yōu)點(diǎn):提高了代碼的擴(kuò)展性。
30. 實(shí)例變量修飾符:
@public 1. 可以在其他類中訪問被public修飾的成員變量 2. 也可以在本類中訪問被public修飾的成員變量 3. 可以在子類中訪問父類別public修飾的成員變量
@private 1. 不可以在其他類中訪問被private修飾的成員變量 2. 可以在本類中訪問被private修飾的成員變量 3.不可以在子類中訪問父類別private修飾的成員變量
@protected 1. 不可以在其他類中訪問被protected修飾的成員變量 2. 可以在本類中訪問被protected修飾的成員變量 3.可以在子類中訪問父類別private修飾的成員變量
@package 介于public與private之間的,如果是在其他包中訪問那么就是就是private的,如果實(shí)在當(dāng)前代碼所在的包中訪問就是public的
實(shí)例變量修飾符作用域:從出現(xiàn)的位置開始,一直直到下一個(gè)修飾符出現(xiàn),如果沒有遇到下一個(gè)實(shí)例變量修飾符,那么就是修飾后面所有的實(shí)例變量。
31. %@是用來打印對(duì)象的,其實(shí)是用于打印字符串。(打印一個(gè)類,和一個(gè)對(duì)象的地址)只要給類發(fā)送class消息,就會(huì)返回當(dāng)前類的類對(duì)象?
32. 只要利用%@打印某個(gè)對(duì)象,系統(tǒng)內(nèi)部默認(rèn)就會(huì)調(diào)用父類的description減號(hào)方法,調(diào)用該方法,該方法會(huì)返回一個(gè)字符串,字符串的默認(rèn)格式 <類的名稱:對(duì)象的地址> ? 用%@打印某個(gè)類,就會(huì)調(diào)用父類的(nsobject)的加號(hào)開頭的description ?兩種情況都可以重新父類的description方法。如果通過%@打印對(duì)象,就會(huì)調(diào)用減號(hào)開頭的,如果通過%@打印類就會(huì)調(diào)用加號(hào)開頭的。
33. self寫在對(duì)象方法中就代表當(dāng)前調(diào)用該方法的對(duì)象。訪問屬性的三種方法:1. p.age 2. p->age 3. [p age];
34. 在description方法中盡量不要使用self來獲取成員變量,因?yàn)槿绻憬?jīng)常在description方法中使用self可能不小心就寫成了%@,self ? ? ? ?如果在description方法中利用%@輸出self會(huì)造成死循環(huán)。
35. 私有變量和私有方法{
實(shí)例變量(成員變量)既可以在@interface中定義,也可以在@implementation中定義,寫在@implementation中定義的默認(rèn)就是私有變量被@private修飾,并且在其他類中無法查看, ?在interface中定義的在其他類中都可以查看,只不過有的不可以進(jìn)行操作而已。
在OC中沒有真正的私有方法,因?yàn)镺C是消息機(jī)制。
}
36. @property: 是一個(gè)編譯器指令,告訴xcode需要執(zhí)行什么命令,用property替換一些代碼 ,在xcode4.4之前,可以使用@property來代替getter/setter方法的聲明,也就是說我們只需要寫上@property就不要寫getter/setter方法的色。 ?編譯器只要看到@property就知道我們要生成一個(gè)屬性getter/setter的方法的聲明 @property int age 用這種格式來替換age的set和get方法
37. @synthesize基本使用:是一個(gè)編譯器指令,它可以簡(jiǎn)化我們getter/setter方法的實(shí)現(xiàn)。實(shí)現(xiàn)在聲明后面寫上大括號(hào)代表被實(shí)現(xiàn). 1.在@synthesize age;后面告訴編譯器,需要實(shí)現(xiàn)哪一個(gè)@property生成的聲明。2. 告訴synthesize,需要將傳入的值賦值給誰和返回的值給使用者 @synthesize age = _age; 如果@synthesize age;是這種形式的賦值,則系統(tǒng) 默認(rèn)會(huì)賦值給和@synthesize后面寫的名稱相同的成員變量. 但是@property會(huì)默認(rèn)賦值給_age帶有下滑線的age.
38. 在xcode4.4之后,對(duì)@property進(jìn)行了增強(qiáng)。只要利用一個(gè)@property就可以同時(shí)生成setter/getter的聲明和實(shí)現(xiàn)? . ?@property會(huì)默認(rèn)賦值給_age帶有下滑線的age. @property有一個(gè)弊端,它只會(huì)生成最簡(jiǎn)單的getter/setter方法,不會(huì)對(duì)傳入的值進(jìn)行判斷.如果想對(duì)傳入的數(shù)據(jù)進(jìn)行過濾,那么我們就必須重寫getter/setter方法。 如果重寫setter方法,那么property就只會(huì)生成getter方法,如果重寫了getter方法,那么property就只會(huì)生成setter方法。@property自動(dòng)幫我們生成的成員變量是一個(gè)私有的成員變量(_age),也就是說在.m中生成的,而不是在.h中生成的。如果重寫了setter/getter方法,那么property就不會(huì)自動(dòng)幫我們生成私有的成員變量,下劃線開頭的age.(舉例age).
39. property修飾符:{
如果給一個(gè)屬性提供了getter/setter方法,那么我們稱這個(gè)屬性為可讀可寫屬性,如果只提供了getter方法,那么成這個(gè)屬性為只讀屬性,如果只提供了setter方法,那么我們稱這個(gè)屬性為只寫屬性,如果都沒有提供,那么我們稱這個(gè)屬性為一個(gè)私有屬性。
readonly 不生成setter方法,只生成getter方法,readwrite既生成setter方法,有生成getter方法。
格式:@property(屬性修飾符) 數(shù)據(jù)類型 變量名稱;默認(rèn)修飾符readwrite
自定義getter方法名稱:
@property(getter = abc)int height;
}
readonly為只讀屬性,如果想修改其值,?這個(gè)時(shí)候我們可以用KVC來給聲明為readonly的屬性重新賦值。?
[對(duì)象 setValue:"value" forKey:NSStringFromSelector(@selector("屬性名"))];
/// 就會(huì)變成新值
nslog(@"%@",對(duì)象.屬性名);
40. id 數(shù)據(jù)類型:是一個(gè)動(dòng)態(tài)數(shù)據(jù)類型。
默認(rèn)情況下所有的數(shù)據(jù)類型都是靜態(tài)數(shù)據(jù)類型,靜態(tài)數(shù)據(jù)類型的特點(diǎn):在編譯時(shí)就知道變量的類型,知道變量中有哪些屬性和方法。在編譯的時(shí)候就可以訪問這些屬性和方法,并且如果是通過靜態(tài)數(shù)據(jù)類型定義變量,如果訪問了不屬于靜態(tài)數(shù)據(jù)類型的屬性和方法,那么編譯器就會(huì)報(bào)錯(cuò)。
動(dòng)態(tài)類型的特點(diǎn): 在編譯的時(shí)候編譯器并不知道變量的真實(shí)類型,只有在運(yùn)行的時(shí)候才知道他們的真實(shí)類型,并且如果通過動(dòng)態(tài)數(shù)據(jù)類型定義變量,如果訪問了不屬于這種數(shù)據(jù)動(dòng)態(tài)類型的方法和屬性,編譯器不會(huì)報(bào)錯(cuò).
id 相當(dāng)于 id = NSObject * ? ?屬于萬能指針。他們兩個(gè)的區(qū)別:id是動(dòng)態(tài)類型,NSObject屬于靜態(tài)類型。通過靜態(tài)數(shù)據(jù)類型定義變量,不能調(diào)用子類特有的方法,通過動(dòng)態(tài)數(shù)據(jù)類型定義變量,可以調(diào)用子類特有的方法。 ?通過動(dòng)態(tài)數(shù)據(jù)類型定義的變量,可以調(diào)用私有的方法。
弊端:由于動(dòng)態(tài)數(shù)據(jù)類型可以調(diào)用任意方法,所以可能調(diào)用不屬于自己的方法,而編譯時(shí)又不會(huì)報(bào)錯(cuò),所以可能導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。id 一般用于多態(tài)??梢詼p少代碼量,避免調(diào)用子類特有的需要強(qiáng)制轉(zhuǎn)換。為了避免數(shù)據(jù)類型引發(fā)的運(yùn)行時(shí)的錯(cuò)誤,一般情況下如果使用動(dòng)態(tài)數(shù)據(jù)類型定義一個(gè)變量,在調(diào)用這個(gè)變量的方法之前會(huì)進(jìn)行一次判斷,判斷當(dāng)前變量是否能夠調(diào)用這個(gè)方法。(使用iskindOfClass:【NSObject class】進(jìn)行判斷)isMemberOfClass 也可以 ? 兩者的區(qū)別:isKindOfClass 用于判斷是否屬于本類或子類 ? isMemberOfClass 只用于判斷是否屬于本類。
[Student isSubClassOfClass:[Person class]] ?用于判斷 student是否是person子類
41. new方法 1.開辟存儲(chǔ)空間(調(diào)用+alloc方法) ? 2.初始化所有的屬性 調(diào)用-init 方法(成員變量)3. 返回對(duì)象的地址 ?new 相當(dāng)于【alloc init】
alloc做了什么事情:1. 開辟存儲(chǔ)空間 2. 將所有的屬性設(shè)置為0 ? ?3. 返回當(dāng)前實(shí)例變量的地址 ? init做的事情:1. 初始化成員變量,但是默認(rèn)情況下init的實(shí)現(xiàn)是什么都沒有做. 2. 返回初始化后的實(shí)例對(duì)象地址。
注意:alloc和init返回的存儲(chǔ)空間是同一個(gè) ?打印地址 %p?
42. 構(gòu)造方法:init開頭的方法。用于初始化一個(gè)對(duì)象,讓某個(gè)對(duì)象一創(chuàng)建出來就擁有某些屬性和值。重寫init方法,在init方法中初始化成員變量,注意:重寫init方法必須按照蘋果規(guī)定的格式重寫,如果不按照規(guī)定會(huì)引發(fā)一些位置的錯(cuò)誤。-(instancetype)init{_age = 10}
蘋果固定格式:1.不能先初始化父類,在初始化子類 2. 必須判斷父類是否初始化成功,只有父類初始化成功才能繼續(xù)初始化子類 3. 返回當(dāng)前的地址
-(instancetype)init{
self = [super init];//初始化父類,只要父類初始化成功,就會(huì)返回對(duì)應(yīng)的地址,如果初始化失敗,就會(huì)返回nil==0==假==初始化失敗
? ? ? ? ?if(self != nil){//判斷是否初始化成功
? ? ? ? ? ? ? ? //初始化子類, ? ? ? ?設(shè)置初始化的值
? ? ? ? ? ?_age = 10;
? ? ? }
? ? ? //返回地址
? ? return self;
}
43. instancetype和id的區(qū)別:他們都是萬能指針,指向一個(gè)對(duì)象,但是,instancetype在編譯的時(shí)候能判斷這個(gè)對(duì)象是什么類型,id在編譯的時(shí)候不能判斷對(duì)象的真是類型。另外一個(gè)區(qū)別:id可以用來定義變量,可以作為形參,可以作為返回值,而instancetype只能作為返回值。 ?自定義構(gòu)造方法,盡量使用instancetype,在編譯的時(shí)候就能檢查錯(cuò)誤
44. 自定義構(gòu)造方法:其實(shí)就是自定義一個(gè)init方法。 ? 一定是對(duì)象方法,一定返回id或者instancetype ,一定以init開頭
-(instancetype)initWithAge:(int)age{if[self = [super init]] _age = age; return self;}(With的W必須要大寫)
一個(gè)類可以有0個(gè)或多個(gè)自定義構(gòu)造方法。
自定義構(gòu)造方法的繼承。 ?在子類中super 父類的init方法 ? 屬性名稱不要以new開頭,方法名也是。
45. 類工廠方法(也稱快速創(chuàng)建方法):類工廠方法是一種用于分配,初始化實(shí)例并返回一個(gè)它自己的實(shí)例的方法,類工廠方法很方便,因?yàn)樗麄冊(cè)试S您只使用一個(gè)步驟就能創(chuàng)建對(duì)象 ? 。 ? 例如:new
自定義類工廠方法:1,一定是+號(hào)開頭 2,返回值一般是instancetype類型或id 3,方法名稱以類名開頭,首字母小寫。
+(instancetype)persionWithAge:(int)age
{
Persion *p = [[Person alloc]init];? p.age = age;? ? return p;//注意:在類工廠方法中一定不要使用類名來創(chuàng)建對(duì)象,要使用self來創(chuàng)建對(duì)象。self在方法中就代表類對(duì)象? Persion *p = [[self alloc]init];
}
類的本質(zhì):類其實(shí)也是一個(gè)對(duì)象,這個(gè)對(duì)象會(huì)在這個(gè)類第一次被使用的時(shí)候創(chuàng)建,只要有了類對(duì)象,將來就可以通過類對(duì)象來創(chuàng)建實(shí)力對(duì)象,實(shí)例對(duì)象中有一個(gè)isa指針,指向創(chuàng)建自己的類對(duì)象。 ?類對(duì)象中保存了當(dāng)前所有的對(duì)象方法,當(dāng)給一個(gè)實(shí)力對(duì)象方法消息的時(shí)候,會(huì)根據(jù)實(shí)例對(duì)象中的isa指針去對(duì)應(yīng)的類對(duì)象中查找。類對(duì)象代表類,Class類型,對(duì)象方法屬于類對(duì)象 ? 如果詳細(xì)的接收者是類名,則類名代表類對(duì)象,所有類的實(shí)例都由類對(duì)象生成。
獲取類對(duì)象:Class c = [對(duì)象/實(shí)例對(duì)象 class];//一個(gè)類在內(nèi)存中只有一份類對(duì)象。
類對(duì)象的使用場(chǎng)景:【c alloc】init];[c text];
1. 用于創(chuàng)建實(shí)例對(duì)象,2,用于調(diào)用類方法。
46. 只要程序啟動(dòng)就會(huì)將類的代碼加載到內(nèi)存中,放到代碼區(qū)。 ?load方法會(huì)在當(dāng)前類被加載到內(nèi)存的時(shí)候調(diào)用,有且僅會(huì)調(diào)用一次 ? ? 會(huì)自動(dòng)被調(diào)用
47. +(void)initialize{} 當(dāng)前類第一次被使用的時(shí)候就會(huì)調(diào)用(創(chuàng)建類對(duì)象的時(shí)候)只會(huì)被調(diào)用一次
48. SEL 類型作用,配合對(duì)象類來檢查對(duì)象或類中有沒有實(shí)現(xiàn)某一個(gè)方法
SEL sel = @selector(text);
BOOL flag = [Person respondsToSelector:sel];//對(duì)用類方法
Person *p = [Person new]; ? BOOL flag = [p respondsToSelector:sel];//調(diào)用類方法
49. 內(nèi)存管理:創(chuàng)建一個(gè)對(duì)象,定義一個(gè)變量,調(diào)用一個(gè)函數(shù)或方法,都會(huì)增加app的內(nèi)存占用。 ? 所謂內(nèi)存管理就是分配內(nèi)存(增加內(nèi)存占用)和清除內(nèi)存(減小內(nèi)存占用)
內(nèi)存管理的范圍:任何繼承了NSObject的對(duì)象,對(duì)其他非對(duì)象類型無效(char,float,double,struct,enum等)
只有oc對(duì)象才需要進(jìn)行內(nèi)存管理的本質(zhì)原因:oc對(duì)象存儲(chǔ)于堆里面 ? 非oc對(duì)象一般放在棧里面(棧內(nèi)存會(huì)被系統(tǒng)自動(dòng)回收)
50. dealloc ?重寫dealloc,在這里釋放相關(guān)資源, ?一旦重寫了dealloc就必須調(diào)用【super dealloc】,并且放在寫在代碼最后. ? ?
注意:不能直接調(diào)用dealloc方法,一旦對(duì)象被回收了,它占用的內(nèi)存就不在可用,堅(jiān)持使用會(huì)導(dǎo)致程序崩潰(出現(xiàn)野指針錯(cuò)誤)
51. 在ARC模式下是編譯器幫你釋放內(nèi)存的 java是系統(tǒng)幫你清理內(nèi)存的 ?一個(gè)引用計(jì)數(shù)器占用4個(gè)字節(jié)
52. 野指針和空指針:
只要一個(gè)對(duì)象被釋放了,我們就稱為僵尸對(duì)象,稱這個(gè)指針為野指針,只要給一個(gè)野指針發(fā)送消息就會(huì)報(bào)錯(cuò)。(用棧區(qū)中的指針去訪問堆區(qū)中的對(duì)象就會(huì)崩潰 ?, ?找不到可以使用的對(duì)象)一般情況下,在對(duì)象被釋放后,會(huì)把指針設(shè)置為空指針,給空指針發(fā)送一個(gè)消息不會(huì)崩潰、(nil ?0) ? p = nil;
53. 分類是用于給原有類添加方法的,不能添加屬性 ?, ?分類中的@property ?只會(huì)生成setter、getter方法的聲明,不會(huì)生成實(shí)現(xiàn)以及私有的成員變量 ?, ?可以在分類中訪問原有類的.h中的屬性
54. 類擴(kuò)展:類擴(kuò)展是分類的一個(gè)特例, ?對(duì)比分類來說,就少了一個(gè)分類名稱,因此也有人稱他為“匿名分類” ?extension
55. property修飾符:retain會(huì)自動(dòng)幫我們生成set方法內(nèi)存管理的代碼, assign:不會(huì)幫我們生成set方法內(nèi)存管理的代碼,僅僅只會(huì)生成普通的getter/setter方法,默認(rèn)什么都不會(huì)就是assgin. ? ?相同類型的修飾符不能再一起使用 ?比如retain和assign
atomic ?和 nonatomic 用于多線程中 ?,atomic性能低,nonatomic性能高一般情況下不會(huì)用atomic。 ? 在ios開發(fā)中,只要寫property ?后面就跟上nonatomic ? 來提高性能。
56. @class ?和 @“import” ?的區(qū)別:
由于import是一個(gè)預(yù)編譯指令,他會(huì)將“”中的文件拷貝到import所在的位置,并且import有一個(gè)特點(diǎn),只有“”中的文件發(fā)生了變化,那么import就會(huì)重新拷貝一次(做更新操作) ?@class僅僅是告訴編譯器,有一個(gè)這個(gè)類,不會(huì)做任何的拷貝操作。 ?注意:由于@class僅僅是告訴編譯器后面的名稱就是一個(gè)類,所以編譯器并不知道這個(gè)類中有哪些屬性和方法,所以在.m中使用類的使用,需要import這個(gè)類才可以使用哦. ?相互使用類的時(shí)候,可以用@class(避免相互拷貝,產(chǎn)生報(bào)錯(cuò))
57. block ?用來保存一段代碼 ?block是一個(gè)變量, ?是變量結(jié)尾就要有;結(jié)束符號(hào)
block注意事項(xiàng):1.block中可以訪問外面的變量。2,block中可以定義和外界同名的變量,并且如果在block中定義了和外界同名的變量,在block中訪問的是block中的變量,3,默認(rèn)情況下,不可以在block中修改外界變量的值,因?yàn)閎lcok中的變量那個(gè)和外界的變量并不是同一個(gè)變量,如果block中訪問到了外界的變量,block會(huì)將外界的變量拷貝一份到堆內(nèi)存中。 因?yàn)閎lock中使用的外界變量是copy的,所以在調(diào)用之前修改外界變量的值,不會(huì)影響到block中copy的值。 ?如果想在block中修改外界變量的值,必須在外界變量前面加上__block ,加完之后,如果在block中修改變量的值,會(huì)影響外界變量的值。內(nèi)外部的兩個(gè)變量的地址是不一樣的,只是指針之間值得傳遞。
為什么不加__block就不能修改外界變量的值,為什么加了之后就可以修改外面的值:加上就是地址傳遞,所以可以在block中修改外界變量的值,不加的話是值傳遞;。
默認(rèn)情況下block存儲(chǔ)在棧中,如果對(duì)block進(jìn)行一個(gè)copy操作,block會(huì)轉(zhuǎn)移到堆中,如果block在棧中,block中訪問了外界的對(duì)象,那么不會(huì)對(duì)對(duì)象進(jìn)行retain操作, ?但是如果block在堆中, ?block中訪問了外界的對(duì)象,那么會(huì)對(duì)外界的對(duì)象進(jìn)行一次retain。
58. Protocol ?協(xié)議:是用來創(chuàng)建方法的,只有方法的聲明,沒有方法的實(shí)現(xiàn)。
協(xié)議和繼承的區(qū)別:1.繼承之后默認(rèn)就有實(shí)現(xiàn),而protocol只有聲明沒有實(shí)現(xiàn)。 2.相同類型可以使用繼承,但是不同而理性的類只能使用protocol。3.protocol可以用于存儲(chǔ)方法的聲明,可以將多個(gè)類中共同的方法抽取出來,以后讓這些類遵守協(xié)議方法即可。
父類遵守了某個(gè)協(xié)議,那么子類也會(huì)自動(dòng)遵守這個(gè)協(xié)議。 ? ? 在oc中一個(gè)類可以遵守一個(gè)或多個(gè)協(xié)議,oc中只能繼承一個(gè)父類。?
OC中的協(xié)議有可以遵守其他協(xié)議,只要一個(gè)協(xié)議遵守了其他協(xié)議,那么這個(gè)協(xié)議中就會(huì)自動(dòng)包含其他協(xié)議的聲明。
NSObject是一個(gè)基類,任何其他類最終都要繼承它 ?有一個(gè)NSObject的協(xié)議,它是一個(gè)基協(xié)議,最根本最基礎(chǔ)的協(xié)議。
@required:被它修飾的協(xié)議方法必須實(shí)現(xiàn),不實(shí)現(xiàn)編譯器會(huì)發(fā)出警告
@optional:被它修飾的不一定要實(shí)現(xiàn)。
59. 協(xié)議的應(yīng)用場(chǎng)景,可以將協(xié)議寫在數(shù)據(jù)類型的右邊,那么對(duì)象必須遵守某個(gè)協(xié)議。 ? ?例如:Person<Protecol> *p = [Person new];
聲明屬性的時(shí)候?qū)傩杂疫呉部梢允褂谩?/p>
在運(yùn)用協(xié)議的時(shí)候,注意事項(xiàng):雖然在接受某一個(gè)對(duì)象的時(shí)候,對(duì)這個(gè)對(duì)象進(jìn)行了類型限定,限定它必須實(shí)現(xiàn)某個(gè)協(xié)議,但是并不意味著這個(gè)對(duì)象就真正的實(shí)現(xiàn)了該方法,所以每次在調(diào)用對(duì)象的協(xié)議方法時(shí)應(yīng)該進(jìn)行一次驗(yàn)證。例如:
if([self.wife respondsToSelector:@selector(cooking)]){
[self.wife cooking];//如果有這個(gè)方法,就執(zhí)行里面的操作
}
60. 設(shè)計(jì)模式:設(shè)計(jì)模式是一套被反復(fù)使用,多數(shù)人知曉的,經(jīng)過分類編目的,代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié),使用設(shè)計(jì)模式是為了可重用代碼,讓代碼更容易被他人理解,保證代碼的可靠性。
代理設(shè)計(jì)模式:比如我們買一包紙,不需要去制造廠去買,去超市去買,超市就是一種代理模式。
代理模式的應(yīng)用場(chǎng)合:例如對(duì)象A和B,當(dāng)A對(duì)象想監(jiān)聽B對(duì)象的一些變化時(shí),可以使用代理設(shè)計(jì)模式,當(dāng)B對(duì)象發(fā)生一些事情,想通知A對(duì)象的時(shí)候,可以使用代理設(shè)計(jì)模式。
協(xié)議的編寫規(guī)范:1.一般情況下,當(dāng)前協(xié)議屬于誰,我們就將協(xié)議定義到誰的頭文件中 2,協(xié)議的名稱一般以他屬于的那個(gè)類的類名開頭,后面跟上protocol或者delegate 3,協(xié)議中的方法名稱一般以協(xié)議的名稱Protocol之前的作為開頭 4,一般情況下,協(xié)議中的方法,會(huì)將出發(fā)該協(xié)議的對(duì)象傳遞出去 5、一般情況下,一個(gè)類中的代理屬于的名稱叫做 delegate 6、當(dāng)有一個(gè)類中要稱為另外一個(gè)類的代理的時(shí)候,一般情況下在.h中用@protocol協(xié)議名稱,告訴當(dāng)前類這是一個(gè)協(xié)議 ? 在.m中用#import導(dǎo)入一個(gè)協(xié)議的聲明
61. Fundation簡(jiǎn)介
框架:眾多應(yīng)用程序的結(jié)合,框架是由許多類,方法,函數(shù),文檔在按照一定的邏輯組織起來的集合,以便使研發(fā)程序變得更容易。在OSX下mac大概有80個(gè)框架為所有程序開發(fā)奠定基礎(chǔ)的框架稱為Fondation框架。
Fundation框架中大約有125個(gè)可用的頭文件。是其他框架開發(fā)的基礎(chǔ),包含了許多常用的數(shù)據(jù)類型:結(jié)構(gòu)體,枚舉,類。
Fundation框架中的類都是以NS為前綴(Next Step的縮寫 ?是85年喬布斯離開蘋果公司創(chuàng)立的NeXT公司)這個(gè)框架是以前在NeXT公司寫NeXT的框架。
對(duì)電腦文件顯隱:defaults write com.apple.finder AppleShowAllFiles -bool True ? 在終端中進(jìn)行顯示和隱藏的操作 , ?操作后一定要重新啟動(dòng)Finder
62. 字符串基本概念:
創(chuàng)建字符串的方法:1.通過字符串常亮創(chuàng)建 2,通過alloc init創(chuàng)建 3,通過類工廠方法創(chuàng)建/ stringWithFormart ? 不同的創(chuàng)建方法所存儲(chǔ)的位置不一樣 ? 第一種存儲(chǔ)在常量去 ?下面兩種存儲(chǔ)在堆區(qū)
但是如果是通過alloc initWithString方法除外,因?yàn)檫@個(gè)方法是通過copy返回一個(gè)字符串對(duì)象給我們,而copy又分為深拷貝和淺拷貝,如果是深拷貝會(huì)創(chuàng)建一個(gè)新的對(duì)象,如果是淺拷貝不會(huì)創(chuàng)建一個(gè)新的對(duì)象,而是直接返回被拷貝的對(duì)象的地址給我們,二initWithString正好是淺拷貝,所以無論是在什么平臺(tái),什么編譯器都是指向同一塊存儲(chǔ)空間。
63. 字符串的讀取和寫入:
1、NSString *str = [NSString stringWithContentOfFile:path encoding:NSUTF8StringEncoding error:&error];
2、BOOL flag = [str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
64. 分類是用于給所有類添加方法的,他只能添加方法,不能添加屬性(成員變量),分類中的@property,只會(huì)生成setter/getter方法的聲明,不會(huì)生成實(shí)現(xiàn)以及私有的成員變量??梢栽诜诸愔性蓄愔?h中的屬性
65. 對(duì)url的讀寫,如果url中有中文,需要用【NSURL fileURLWithPath:@"fsfsd"】;進(jìn)行編碼讀寫
66. 字符串進(jìn)行比較:str isEqualToString:str2 ? 或者 ?str == str2 ? 前者是比較內(nèi)容是否相等,后者是比較地址手否相同。
第三種方法用switch進(jìn)行判斷:
str compare: str2 ? 有三種結(jié)果,是一個(gè)枚舉值,NSOrderAscending ? NSOrderedSame ? NSOrderedDescending ? 升序 ? 相等 ?降序 ?另外一種方法是忽略大小寫就行比較的 ?caseInsensitveCompare ?和第三種方法 比較的方法是一樣的。
67. 字符串搜索:判斷以什么開頭,判斷以什么結(jié)尾 ?hasPrefix ? hasSuffix ? . ? ?還有一個(gè)字符串包含:rangeOfString:返回值是NSRange ?這個(gè)包含字符串的起始位置和長(zhǎng)度,如果沒有要查詢的結(jié)果,返回的長(zhǎng)度為0,字符串的其實(shí)位置為NSNotFound
68. 只要是OC提供的結(jié)構(gòu)體一般都是NSMakeXXX ? ? ?{x,x } ?
int和NSInteger其實(shí)是差不多的,但更推薦使用NSInteger,因?yàn)槭褂肗SInteger,這樣就不用考慮設(shè)備是32位還是64位了。
NSUInteger是無符號(hào)的,即沒有負(fù)數(shù),NSInteger是有符號(hào)的,所以NSUInteger類型不能給它賦負(fù)值。比如for循環(huán)的時(shí)候,a=-1的時(shí)候,是能進(jìn)入循環(huán)的。
69. 字符串截?。?.動(dòng)態(tài)獲取截取的起始位置,2,動(dòng)態(tài)獲取截取的長(zhǎng)度 。 ?
str = @"<head>麥迪文</head>";
NSUInteger location = [str rangeOfString:@">"].location + 1;
NSUInteger length = [str rangeOfString:@"<" options:NSBackwardSearch].location - location;//從字符串后面往前找
NSRange range = NSmakeRange(location,length);
70. 字符串截?。骸緎tr stringByReplacingOccurrencesOfString:@"xx"】;
替換首位:str = @"sfdsfdsfdsf";
NSCharacterSet *set = [NSCharacterSet whitespaceCharacterSet];?
newStr = [str stringByTrimmingChatactersInSet:set];
71. 字符串轉(zhuǎn)換:【str uppercaseString】轉(zhuǎn)換成大寫 ? 【str lowercaseString】轉(zhuǎn)換成小寫;
將字符串首字母轉(zhuǎn)換為大寫 ? 【str capitalizedString】;
【str deleteCharactersInRange:range】;//刪除指定的字符串
72. NSMutableString: 繼承于NSString ??
對(duì)于不可變字符串,每次改變內(nèi)容的時(shí)候都是創(chuàng)建一個(gè)新的對(duì)象。地址會(huì)改變
可變字符串:每次修改都是添加到同一個(gè)地址位置。
73. NSArray ?
NSArray *arr = [NSArray arrayWithObject:@"2",@"2",nil];//nil ?是一個(gè)結(jié)束符
快速創(chuàng)建數(shù)組:NSArray *arr = @[@“1”,@“3”]; // 和上面的意義一樣
查找數(shù)組中是否包含了某一個(gè)元素 ?
【arr containsObject:@"33"】;//返回值布爾值
oc中經(jīng)常使用的三種遍歷:1.for循環(huán)的基本遍歷 2.forin遍歷 (for循環(huán)的增強(qiáng)版)3. 利用oc數(shù)組的迭代器遍歷也就是block遍歷
[arr enumerateObjectsUseingBlock:........];//返回值有三個(gè)參數(shù):1,元素(obj),2,索引(idx) 3,*stop (用于控制循環(huán)停止在某一個(gè)地方)
如果使用oc數(shù)組存儲(chǔ)對(duì)象,可以調(diào)用oc數(shù)組的方法讓數(shù)組中所有的元素都執(zhí)行指定的方法
【arr makeObjectPerformSelector:@selector(say)】;//say是一個(gè)對(duì)象或者類方法
makeObjectPerformSelector:@selector(say:) withObject:@"ss"】;//需要傳遞給調(diào)用方法的參數(shù)
注意點(diǎn):如果數(shù)組中保存的不是相同類型的數(shù)據(jù),并且沒有相同的方法,那么會(huì)報(bào)錯(cuò).
對(duì)數(shù)組進(jìn)行排序:[arr sortArrayUsingSelector:@selector(compare:)];
//注意:想使用compare方法對(duì)數(shù)組中的元素進(jìn)行排序,那么數(shù)組中的元素必須是Fondation框架中的對(duì)象,也就是說不能是自定義的對(duì)象。
如果想調(diào)用自定義對(duì)象:需要使用
【arr sortedArrayWithOptions:NSSortStable usingComparator:....】;
返回obj1和obj2對(duì)象 ?進(jìn)行比較 ?return obj1>obj2 ?或者相反
&&&&&&&冒泡排序
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"12",@"84", @"35", @"70", @"85", @"99", nil];
NSInteger count = [array count];
for (int i = 0; i < count; i++) {
for (int j = 0; j < count - i - 1; j++) {
// if ([[array objectAtIndex:j] intValue] > [[array objectAtIndex:(j + 1)] intValue]) {? //這里在用[array objectAtIndex:j]時(shí)候必須intValue
//? ? ? ? ? ? ? ? if([[array objectAtIndex:j] compare:[array objectAtIndex:j + 1]] == -1){? //這里整體必須有一個(gè)返回值,-1,0,1,因?yàn)閏ompare的返回值NSComparisonResult是一個(gè)枚舉類型的值,所以要返回一個(gè)值
if([[array objectAtIndex:j] compare:[array objectAtIndex:j + 1] options:NSNumericSearch] == 1){? //同上potions? NSNumericSearch = 64,
[array exchangeObjectAtIndex:j withObjectAtIndex:(j + 1)];? //這里可以用exchangeObjectAtIndex:方法來交換兩個(gè)位置的數(shù)組元素。
}
}
}
for (NSString *i in array) {
NSLog(@"%@", i);
}
74. NSArray和NSString轉(zhuǎn)換
將數(shù)組中的元素進(jìn)行連接起來:【arr compontentsJoinedByString:@"-"】;
通過一個(gè)字符串生成一個(gè)數(shù)組:也叫作字符串切割
str = @"33*44*55*56";
[str componentSwparatedByString:@"*"];
75. NSArray文件讀寫:
arr = @[@"2",@"3"];
BOOL flag = [arr writeToFile:@"路徑.plist" atomically:YES];//將數(shù)組寫入到文件中,其實(shí)如果講一個(gè)數(shù)組寫入到文件中會(huì)后,本質(zhì)是戲?qū)懭肓艘粋€(gè)XML文件 ?, ?在iOS開發(fā)中一般情況下我們會(huì)將XML文件的擴(kuò)展名保存為plist
從文件中讀取一個(gè)數(shù)組:
arr = [NSArray arrayWithContentOfFile:@"路徑"];
注意:write方法只能寫入數(shù)組中保存的元素都是Fundation中的方法,不能寫入自定義的元素。
76. NSMutableArray:
其實(shí)可變的數(shù)組,字符串,字典都是不可變數(shù)組,字符串,字典的子類。
注意:不能通過@【】來創(chuàng)建一個(gè)可變數(shù)組,因?yàn)橛聾【】創(chuàng)建出來的是一個(gè)不可變的數(shù)組,如果把一個(gè)不可變數(shù)組當(dāng)做一個(gè)可變數(shù)組開使用,會(huì)引發(fā)一個(gè)運(yùn)行時(shí)的錯(cuò)誤。
77. NSDictionary:
對(duì)字典進(jìn)行forIn遍歷 ?對(duì)打印出所有的key
最方便的遍歷使用block進(jìn)行遍歷
字典保存的數(shù)據(jù)是無序的
78. NSMutableDictionary:
不能使用@{}來創(chuàng)建可變字典 ?如果是不可變數(shù)組,那么key不能相同
NSArray是通過下標(biāo)來訪問元素,NSDictionary是通過key值來訪問元素(因?yàn)樗菬o序的)
79. 常用結(jié)構(gòu)體:
NSPoint和CGPoint NSSize和CGSize NSRect和CGRect ?這三個(gè)結(jié)構(gòu)體是OC中常用的。這是三個(gè)結(jié)構(gòu)體,只是有三個(gè)別名。
在蘋果開發(fā)中,蘋果推薦我們使用CG開頭的結(jié)構(gòu)體,也就是說NS開頭的結(jié)構(gòu)體一般不用.
80. NSNumber:
數(shù)組和字典都只能存放對(duì)象類型的數(shù)據(jù),基本數(shù)據(jù)類型存放會(huì)報(bào)錯(cuò)。如果想存儲(chǔ)基本數(shù)據(jù)類型,需要將基本數(shù)據(jù)轉(zhuǎn)換成對(duì)象類型:
例如: NSNumber *num = [NSNumber numberWithInt:age]; ? 或者使用快速轉(zhuǎn)換的方法:NSNumber *num = @(int); ?如果傳入的是常量則不需要使用圓括號(hào)。
81. NSValue:
NSValue是NSNumber的父類
如果想包裝基本數(shù)據(jù)類型以外的類型,可以使用NSValue。 ? NSValue中有很多方法,比如可以轉(zhuǎn)換常用的基本結(jié)構(gòu)體,如果想轉(zhuǎn)換自定義結(jié)構(gòu)體可以使用:
NSValue *value = [NSValue valueWithBytes:&p objCType:@encode(Person)];//Person是自定義的結(jié)構(gòu)體 ? ?&p是傳入的指針 @encode是把自定義結(jié)構(gòu)體對(duì)象轉(zhuǎn)化成指針。 ?如果想獲取自定義結(jié)構(gòu)體中的變量:【value getValue:&p】;//Person *p;
82. NSDate:
NSDate *now = [NSDate date];//獲取當(dāng)前的時(shí)間
NSTimeZone *zone = [NSTimeZone systemTimeZone]; ?//獲取當(dāng)前所處的時(shí)區(qū)
NSInteger seconds = [NSInteger secondsFromGMTForDate:now];//獲取當(dāng)前時(shí)區(qū)和指定時(shí)間的時(shí)間差
NSDate *newDate = [now dateByAddingInterval:seconds];//在now的基礎(chǔ)上增加了多少秒
newDate就是獲取的當(dāng)前時(shí)區(qū)的正確時(shí)間。
時(shí)間格式化:NSDateFormatter?
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dataFormatter = @"yyyy年MM月dd日 HH時(shí)mm分ss秒 z";
formatter.dataFormatter = @"yyyy-MM-dd HH-mm-ss";
利用時(shí)間格式化對(duì)象對(duì)時(shí)間進(jìn)行格式化:
NSString *str = [formatter stringFromDate:[NSdate date]];
//注意: 如果是從NSString格式化為NSDate,那么dateFormat的格式,必須和字符串中的時(shí)間格式一致,否則可能轉(zhuǎn)化失敗。
NSString *str = @"2016-12-12 07:30:20";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSDate *date = [foramtter dateFormString:str];
83. NSCalendar:
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSCalendarUnit type = NSCalendarUnitYear | NSCalendarMonth;
NSDateComponents cmps = [calendar components:type formDate:now];
nslog(@"%@%@",cmps,year,cmps.month);
比較兩個(gè)時(shí)間:
NSDateComponents *cmps = [calendar components:type fromDate:date toDate:now options:0];
84. NSFileManager:
NSFileManager *manager = [NSFileManager ?defauleManager];
BOOL flag = [manager fileExistsAtPath:@""];//判斷一個(gè)文件或者文件夾是否存在
BOOL dir = NO;//默認(rèn)為NO
BOOL flag = [manager fileExistsAtPath:@"" isDirectory:$dir];//判斷一個(gè)文件是否存在,并且判斷它是否是一個(gè)文件夾, ?第一個(gè)參數(shù)是路徑,第二個(gè)參數(shù)返回的是判斷這個(gè)路徑是否是一個(gè)文件夾。
獲取文件或文件夾的屬性:
[manager attributesOfItemAtPath:@"" error:nil];
獲取文件夾中所有的文件
【manager contentsOfDirectoryAtPath:@"" error:nil】;
也可以創(chuàng)建文件夾和文件方法,自己去找createFile.........
85. 集合中對(duì)象的內(nèi)存管理
1.如果將一個(gè)對(duì)象添加到一個(gè)數(shù)組中,那么數(shù)組會(huì)對(duì)對(duì)象進(jìn)行一個(gè)retain ??
2. 當(dāng)數(shù)組對(duì)象釋放之后,會(huì)給數(shù)組中所有的對(duì)象發(fā)送一條release消息
3. 當(dāng)數(shù)組移除一個(gè)對(duì)象之后,會(huì)給這個(gè)對(duì)象發(fā)送一條release消息
86. copy 基本使用:
NSString *str = @"uio";
NSMutableString *copy = [str mutableCopy];
只要是拷貝出來的對(duì)象,拷貝出來的對(duì)象中的內(nèi)容一致,一般情況下拷貝會(huì)生成一個(gè)新的對(duì)象,為什么會(huì)產(chǎn)生一個(gè)新的對(duì)象(因?yàn)榭截愐笮薷脑瓉淼膶?duì)象,不能影響到拷貝出來的對(duì)象 ? 修改拷貝出來的對(duì)象也不能影響到原來的對(duì)象,所以需要生成一個(gè)新的對(duì)象 ?由于以前的對(duì)象是一個(gè)不可變的對(duì)象,而通過nutableCopy拷貝出來的對(duì)象必須是一個(gè)可變的對(duì)象,所以必須生成一個(gè)新的對(duì)象)
如果通過不可變對(duì)象調(diào)用了copy方法,那么不會(huì)生成一個(gè)新的對(duì)象,原因:(因?yàn)樵瓉淼膶?duì)象是不能修改的,拷貝出來的對(duì)象也是不能修改的,既然兩個(gè)都不能修改,所以永遠(yuǎn)不能影響到另一個(gè)對(duì)象,那么已經(jīng)符合需求,所以O(shè)C為了對(duì)內(nèi)存進(jìn)行優(yōu)化,就不會(huì)生成一個(gè)新的對(duì)象)
正是因?yàn)檎{(diào)用copy方法:有時(shí)候會(huì)生成一個(gè)新的對(duì)象,有時(shí)候不會(huì)生成一個(gè)新的對(duì)象,所以:如果沒有生成新的對(duì)象,我們稱之為淺拷貝,本質(zhì)就是指針拷貝。如果生成了新的對(duì)象,我們稱之為深拷貝,本質(zhì)就是會(huì)創(chuàng)建一個(gè)新的對(duì)象。
對(duì)于內(nèi)存的管理: ?如果是淺拷貝:不會(huì)生成新的對(duì)象,但是系統(tǒng)就會(huì)對(duì)原來的對(duì)象進(jìn)行retain,所以需要對(duì)原來的對(duì)象進(jìn)行一次release。 ? 如果是深拷貝:會(huì)生成新的對(duì)象,系統(tǒng)不會(huì)對(duì)原來的對(duì)象進(jìn)行retain,但是因?yàn)樯闪诵碌膶?duì)象,所以我們需要對(duì)新的對(duì)象進(jìn)行release
87. ?對(duì)于property中的修飾符,如果修飾字符串的話,就用copy避免了修改原對(duì)象或新對(duì)象的值影響被拷貝對(duì)象中的內(nèi)容,如果用retain進(jìn)行修飾的話,修改了一個(gè)對(duì)象就會(huì)對(duì)原對(duì)象或者新對(duì)象的內(nèi)容產(chǎn)生影響。
88. copy的用途:1.防止外界修改內(nèi)部的數(shù)據(jù)。2. block默認(rèn)存儲(chǔ)在棧中,棧中的block訪問到了外界的對(duì)象,不會(huì)對(duì)對(duì)象進(jìn)行retain,block如果在堆中,如果在block中訪問了外界的對(duì)象,會(huì)對(duì)外界的對(duì)象進(jìn)行一次retain。 使用Block_copy(myBlock),就是將block轉(zhuǎn)移到堆中。 ? 3.如果使用copy保存block,這樣可以保住block中使用的外界對(duì)象的命,避免以后調(diào)用block的時(shí)候,外界的對(duì)象已經(jīng)釋放了。
89. copy block之后引發(fā)循環(huán)引用 ?如果對(duì)象中的block又用到了對(duì)象自己,那么為了避免內(nèi)存泄漏,應(yīng)該講對(duì)象修飾為__block
90. 自定義類實(shí)現(xiàn)Copy(讓自定義的對(duì)象能夠被copy)
1. 需要遵守NSCopying協(xié)議
2. 需要實(shí)現(xiàn)協(xié)議方法:-(id)copyWithZone:(NSZone *)zone{ ?};
91. 單例:
由于所有的創(chuàng)建方法都會(huì)調(diào)用allocWithZone:,所以只需要在該方法中控制當(dāng)前對(duì)象值創(chuàng)建一次即可。
設(shè)置一個(gè)靜態(tài)的對(duì)象 ?。 ? 使用代理每次創(chuàng)建對(duì)象的時(shí)候都是同一個(gè)地址。相當(dāng)于永遠(yuǎn)之創(chuàng)建同一個(gè)對(duì)象。 ? 只有程序銷毀的時(shí)候,這塊對(duì)象才會(huì)被釋放。
\ ?表示換行
單例的優(yōu)缺點(diǎn):
單例模式的優(yōu)缺點(diǎn)
1、時(shí)間和空間
比較上面兩種寫法:懶漢式是典型的時(shí)間換空間,也就是每次獲取實(shí)例都會(huì)進(jìn)行判斷,看是否需要?jiǎng)?chuàng)建實(shí)例,浪費(fèi)判斷的時(shí)間。當(dāng)然,如果一直沒有人使用的話,那就不會(huì)創(chuàng)建實(shí)例,則節(jié)約內(nèi)存空間。
餓漢式是典型的空間換時(shí)間,當(dāng)類裝載的時(shí)候就會(huì)創(chuàng)建類實(shí)例,不管你用不用,先創(chuàng)建出來,然后每次調(diào)用的時(shí)候,就不需要再判斷了,節(jié)省了運(yùn)行時(shí)間。
2、線程安全
(1)從線程安全性上講,不加同步的懶漢式是線程不安全的,比如,有兩個(gè)線程,一個(gè)是線程A,一個(gè)是線程B,它們同時(shí)調(diào)用getInstance方法,那就可能導(dǎo)致并發(fā)問題。如下示例:
public static? Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
程序繼續(xù)運(yùn)行,兩個(gè)線程都向前走了一步,如下:
public static? Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}