黑馬程式設計師 OC類的研究和記憶體管理初識

2021-06-29 13:45:50 字數 4207 閱讀 7331

(一)oc類的研究:

1.類的本質:

在oc中,類其實也是乙個物件。這個物件是class型別的(class裡面有*),稱作類物件。而由類物件建立出來的這個

類 型別的物件叫做例項

物件。就是說,假如建立乙個car類,並且通過方法建立car物件:car *c  = 

[ [ car alloc ] init ]

,**實現完成後,編譯器會先利用class型別

建立car類物件,然後再用car類物件建立car型別的物件。

2.獲取記憶體中得類物件:

可以通過物件方法獲取記憶體中的類物件 class d = [ c  class ];

可以通過類方法獲取記憶體中得類物件 class d1 = [ car  class ];

3.執行思路:

oc程式執行時,會把類,並且只會把這個類物件載入到記憶體一次。而物件卻是無數多的,現在記憶體中只有乙個car類對

象,類物件裡面放著

car類方法的生命。然後通過分配儲存空間和初始化後,car類物件可以擁有無數car型別的物件,

這些car型別的物件都擁有乙個繼承自

nsobject父類的isa指標,指標指向自己型別的類物件,也就是car類物件。用於呼叫car類物件的方法。

通過上述方法找到類物件後,d d1數值肯定就是相等的,因為記憶體中當且僅有乙個類物件的。這時候d d1就代表這個類

物件,可以使用類方法 [

[ d  alloc ] init ],當然,類名本身也表示類物件。

4.類的載入過程:

當整個程式載入到記憶體中時,會先載入父類,再載入子類。哪怕是main主函式中沒有用到這個類,都要進行載入。類只會被載入一次,在類被

載入的時候,會呼叫乙個系統的+ (void)load方法,這個方法是自動載入的。

當main函式中用到哪個類時(第一次使用這個類),這時候會進行更深層的載入,會呼叫乙個+(void)initialize方法。

下面進行總結:

當程式啟動時,會載入所有類和分類,而且載入後會呼叫每個分類的+load方法,只會呼叫一次。

當第一次使用乙個類時,就會呼叫當前類的+initialize方法。

先載入父類,再載入子類(先呼叫父類的+load方法,再呼叫子類的+load方法)。

先初始化父類,在初始化子類(先呼叫父類的+initialize方法,在呼叫子類的+initialize方法)。

當分類和類中都有+initialize方法時候,根據規則,則會呼叫分類中得+initialize方法。

通過這些方法,可以進行監聽。當類第一次使用時做一些操作,就可以重寫+initialize方法。

5.description方法(nsobject自帶):

在nslog輸出乙個%@型別的物件時,會碰到兩種情況,如果%@是乙個nsstring *型別,則輸出相應的字串。如果%@是乙個物件,或者是

乙個類物件,那麼就會擁有乙個輸出規則--自動呼叫description。

①輸出遇到類物件: 自動呼叫+description。

②輸出遇到物件:自動呼叫-description。

而description是有返回值的,它的返回值是nsstring *,nslog遇到%@輸出後,會呼叫description,拿到返回值然後輸

出在螢幕上。所以,當

我們想輸出整個類的所有屬性時,乙個乙個用nslog訪問太麻煩,萬一成員變數很多就大大的降

低了效率,這時候我們可以選擇重寫父類nso

bject的方法description,讓其return我們想要的值就可以了。

下面我們通過**來分析一下工作原理:

person.h

#import

@inte***ce person :nsobject

@propertyintage;

@property

nsstring

*name;

@end

person.m

#import "person.h"

@implementationperson

-(nsstring *)description

+(nsstring *)description

@end

main();

#import

#import "person.h"

int main()

count:

2015-04-0317:41:09.939o[1989:508218]

人的年齡是100,姓名是

dsa

2015-04-0317:41:09.940o[1989:508218] abc

由上**可以看出,+description預設輸出類物件名稱。-description預設輸出類名+記憶體位址。在重寫後,他們在被nslog呼叫時返回了相應的

返回值。這樣就實現了一次性輸出所有屬性的功能。

6.列印增強

%s---__file__---列印檔案路徑(oc nslog不允許有中文,可以使用printf)

%d---__line__---列印當前行號。

7.sel資料型別:

我們以前在呼叫乙個方法[p  test]-->稱作傳送訊息機制。其實就是把要呼叫的方法封裝成sel資料型別傳送給類,發訊息發得就是sel資料型別。

乙個sel資料型別代表乙個方法。每乙個方法位址都會有乙個sel資料型別的資料相對應。

#import

#import "person.h"

int main()

如上為sel的傳送。呼叫了p的performselector方法把test2封裝成sel資料型別傳送給person類,呼叫成功。步驟是:

①把test2包裝成sel型別的資料。

②根據sel資料找到對應的方法位址。

③根據方法低值呼叫對應方法。

字串包裝sel:

nsstring *d =@"wjds";

sel f = nsselectorfromstring(d);

[d performselector:f];

(二)oc記憶體初識:

1.記憶體管理

為什麼要管理記憶體呢,因為不同的資料型別在記憶體中的儲存方式是不一樣的,一些區域性變數,如基本資料型別,結構體

,列舉,指標等型別

,都會存放在記憶體的棧中,而物件儲存在記憶體的堆中。oc系統中棧資料是自動**的。它擁有自

己的**塊作用域,當**塊執行完畢,就會

從記憶體中清除。但是堆空間是動態分配的,是不可能會主動**的。此時

需要程式設計師人工進行記憶體**。任何繼承了nsobject類的物件都要管

理記憶體 。

2引用計數器:

每乙個oc物件都有引用計數器(4位元組),表示被用的次數。當物件分配記憶體後(**表示為alloc,new),引用計數器預設值變為1.引用計

數器用三個物件方法。

person *p = [[person alloc] init];

[p retain];

[p release];

//    nsuinteger c =  [p retaincount];

[p release];

[p retain];

return0;

當計數器為0時,系統自動向物件傳送dealloc訊息。一般會選擇重寫dealloc方法,在這裡釋放相應的資源。dealloc就是物件的遺言。

3.殭屍物件:

當物件計數器為0時,稱這時候的物件為殭屍物件(不能再使用,所占用的記憶體已經被**的物件)。

4.野指標:

指向不可用記憶體的指標叫做野指標。當然,指向殭屍物件的指標也是野指標。

5.空指標:

不指向任何物件的指標,指標=nil ,null,0.空指標在oc語言中是允許的,比關切給空指標傳送訊息並不會報錯。

6機制分析:

當乙個物件剛被建立出來時候(new alloc表示分配記憶體空間給物件。而init不算建立物件,只是初始化)。物件引用計數器+1,然後當物件傳送

retain訊息,計數器+1,傳送release訊息,計數器-1.當物件呼叫完畢,不需要的時候,需要手動清除,此時release物件使計數器變為0,然後

物件自動傳送dealloc訊息,告知已「死亡」,此時這個物件是殭屍物件,還儲存在堆中,原來指向他的那個指標變成了野指標。

7.exc_bad_access----->100%記憶體出錯。訪問了一塊壞記憶體(不可用,被**的)。--->野指標常見錯誤。

黑馬程式設計師 OC 類和物件

類名 car 屬性 輪胎個數 時速 行為 跑 因為使用了nsobject import 完整地寫乙個函式 函式的宣告和實現 完整的寫乙個類 類的宣告和實現 類的宣告 宣告物件的屬性 行為 nsobject 的目的是 讓car這個類具備建立物件的能力 inte ce car nsobject 用來宣告...

黑馬程式設計師 OC 類和物件

一.物件導向和面向過程的思想 對比 oc是物件導向的,c是面向過程的。物件導向和面向過程只是解決問題的兩種不同思想 1 以用電腦聽歌為例子 a 面向過程 開啟電腦 關閉電腦 b 物件導向 不是相親的 物件 電腦 開機 關機 區別分析 面向過程關注的是解決問題需要哪些步驟 物件導向關注的是解決問題需要...

黑馬程式設計師 OC 記憶體管理

1.什麼是記憶體管理 管理範圍 任何繼承了nsobject的物件,對其他基本型別無效 2.物件的基本結構 每個oc物件都有自己的引用計數器,是乙個整數,表示 物件被引用的次數 即有多少個人正在使用oc物件 每個oc物件內部專門有4個位元組的儲存空間來儲存引用計數器 3.引用計數器的作用 當使用all...