天天看點

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

移動裝置的記憶體極其有限(iphone 4記憶體512m),每個app所能占用的記憶體是有限制的(幾十兆而已)。

當app所占用的記憶體較多時,系統會發出記憶體警告,這時得回收一些不需要再使用的記憶體空間。比如回收一些不需要使用的對象、變量等

管理範圍:任何繼承了nsobject的對象,對其他基本資料類型(int、char、float、double、struct、enum等)無效,和 java 不一樣,oc 開始的時候沒有垃圾自動回收機制。

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

每個oc對象都有自己的引用計數器,是一個四位元組的整數,表示“對象被引用的次數”,即有多少人正在使用這個oc對象

每個oc對象内部專門有4個位元組的存儲空間來存儲引用計數器(面試題)

引用計數器的作用

當使用alloc、new或者copy建立一個新對象時,新對象的引用計數器預設就是1,當一個對象的引用計數器值為0時,對象占用的記憶體就會被系統回收。換句話說,如果對象的計數器不為0,那麼在整個程式運作過程,它占用的記憶體就不可能被回收,除非整個程式已經退出。

引用計數器的操作

給對象發送一條retain消息(代表調用這個對象方法),可以使引用計數器值+1(retain方法傳回對象本身)

給對象發送一條release消息,可以使引用計數器值-1,沒有傳回值

可以給對象發送retaincount消息獲得目前的引用計數器值

對象的銷毀(ios6之前)

當一個對象的引用計數器值為0時,那麼它将被銷毀,其占用的記憶體被系統回收,

當一個對象被銷毀時,系統會自動向對象發送一條dealloc消息, 

一般會重寫dealloc方法,在這裡釋放相關資源,dealloc就像對象的臨終遺言,

一旦重寫了dealloc方法,就必須調用[super dealloc],并且放在最後面調用(類似 c++的析構函數,析構函數的調用順序和構造函數的調用順序完全相反),

不要直接調用dealloc方法, 

一旦對象被回收了,它占用的記憶體就不再可用,堅持使用會導緻程式崩潰(野指針錯誤)

xcode的設定,取消 arc

要想手動調用retain、release等方法,在建立項目的時候不要勾選arc(自動引用計數)

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

1.當需要使用int類型的變量的時候,可以像寫c的程式一樣,用int,也可以用nsinteger,但更推薦使用nsinteger,因為這樣就不用考慮裝置是32位的還是64位的。

2.nsuinteger是無符号的,即沒有負數,nsinteger是有符号的。

開啟僵屍對象監控

預設情況下,xcode是不會管僵屍對象的,使用一塊被釋放的記憶體也不會報錯。為了友善調試,應該開啟僵屍對象監控

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

記憶體管理原則

qq堂開房間原理:隻要房間還有人在用,就不會解散

隻要還有人在用某個對象,那麼這個對象就不會被回收

隻要你想用這個對象,就讓對象的計數器+1

當你不再使用這個對象時,就讓對象的計數器-1

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

誰建立,誰release

如果你通過alloc、new或[mutable]copy來建立一個對象,那麼你必須調用release或autorelease,換句話說,不是你建立的,就不用你去[auto]release

誰retain,誰release

隻要你調用了retain,無論這個對象是如何生成的,你都要調用release

總結

有始有終,有加就有減

曾經讓對象的計數器+1,就必須在最後讓對象計數器-1

你想使用(占用)某個對象,就應該讓對象的計數器+1(讓對象做一次retain操作),不想再使用(占用)某個對象,就應該讓對象的計數器-1(讓對象做一次release)

set方法的記憶體管理

如果有個oc對象類型的成員變量,就必須管理這個成員變量的記憶體。比如有個book *_book,而我們之前的做法并不嚴謹。

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

記憶體管理代碼規範:

 1.隻要調用了alloc,必須有release(autorelease),   對象不是通過alloc産生的,就不需要release

 2.set方法的代碼規範

 1> 基本資料類型:直接複制

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

 2> oc對象類型

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

 3.dealloc方法的代碼規範

 1> 一定要[super dealloc],而且放到最後面

 2> 對self(目前)所擁有的其他對象做一次release

什麼是碼農,這樣的重複代碼的編寫就是碼農的工作,so蘋果出了對策,ide 自動完成一些重複性代碼的編寫工作。

xcode 可以幫我們省掉編寫那些惡心代碼的工作。使用@property自動生成記憶體管理的代碼,但是 dealloc 方法還是要自己寫,這時候就有了 arc,ios5之後出的新特性。

@property參數

控制set方法的記憶體管理

retain : release舊值,retain新值(用于oc對象)

assign : 直接指派,不做任何記憶體管理(預設,用于非oc對象類型)

copy   : release舊值,copy新值(一般用于nsstring *)

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

readwrite 同時生成set方法和get方法(預設),這裡把 set 看成寫,get 看成讀取,就很好了解了。

readonly  隻會生成get方法(隻讀,就是隻是擷取,那麼就是 get)

atomic    性能低(預設)

nonatomic 性能高(寫程式要使用這個)

setter : 設定set方法的名稱,一定有個冒号:

getter : 設定get方法的名稱

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

使用場景;對于循環依賴關系來說,比方a類引用b類,同時b類也引用a類

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

這種代碼直接編譯會報錯。當使用@class在兩個類互相聲明,就不會出現編譯報錯

用法概括

使用 @class 類名; 就可以引用一個類,說明一下它是一個類

和#import的差別

#import方式會包含被引用類的所有資訊,包括被引用類的變量和方法;

@class方式隻是告訴編譯器在a.h檔案中 b *b 隻是類的聲明,具體這個類裡有什麼資訊,這裡不需要知道,等實作檔案中真正要用到時,才會真正去檢視b類中資訊,如果有上百個頭檔案都#import了同一個檔案,或者這些檔案依次被#improt,那麼一旦最開始的頭檔案稍有改動,後面引用到這個檔案的所有類都需要重新編譯一遍,這樣的效率也是可想而知的,而相對來 講,使用@class方式就不會出現這種問題了。

在.m實作檔案中,如果需要引用到被引用類的實體變量或者方法時,還需要使用#import方式引入被引用類

循環retain

比如a對象retain了b對象,b對象retain了a對象,這樣會導緻a對象和b對象永遠無法釋放

解決方案

當兩端互相引用時,應該一端用retain、一端用assign

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

@class的作用:僅僅告訴編譯器,某個名稱是一個類

@class person; 僅僅告訴編譯器,person是一個類,不會把類的方法等引入

實際開發中引用一個類的規範是:

1> 在.h檔案中用@class來聲明類,比如,有100個類同時引用了 card 類,如果 card 修改了,那麼剩下的100個類也要重新引入編譯,效率不高,且還能解決雙端引用(循環引用)的出現錯誤問題。

2> 在.m檔案中用#import來包含類的所有東西

為了提高編譯的效率!頭檔案不使用#import,隻有一個特例,那就是在繼承裡,父類需要使用#import 引入到子類

兩端循環引用解決方案,這是特例,差別對待,以前說了,對象用 retain,非對象不需要記憶體管理,使用 assign 就行了,但是這裡特殊

1> 一端用retain

2> 一端用assign 

autorelease方法(半自動釋放)

autorelease

給某個對象發送一條autorelease消息時,就會将這個對象加到一個自動釋放池中

當自動釋放池銷毀時,會給池子裡面的所有對象發送一條release消息

調用autorelease方法時并不會改變對象的計數器

autorelease 方法傳回對象本身

autorelease實際上隻是把對release的調用延遲了,對于每一次autorelease,系統隻是把該對象放入了目前的@autoreleasepool中,當該pool被釋放時,該pool中的所有對象會被調用release

 使用 autorelease 方法防止了每次使用對象,都要在對象 release 之前使用的弊端,因為那樣總是小心翼翼的,怕出現野指針。但是出現了 arc 之後這些都不需要了。

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

ios 5.0後,以後一直使用這個了.

ios 5.0前

在程式運作過程中,可以建立多個自動釋放池,它們是以棧的形式存在記憶體中,oc對象隻需要發送一條autorelease消息,就會把這個對象添加到最近的自動釋放池中(棧頂的釋放池)

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

跟release的對比

以前:

book *book = [[book alloc] init];

[book release];

現在:

book *book = [[[book alloc] init] autorelease];

// 不要再調用[book release];但是這樣顯得代碼很長,臃腫,能不能建立對象的時候,直接就是放入自動釋放池裡呢?可以的:

一般可以為類添加一個快速建立對象的類方法

外界調用[book book]時,根本不用考慮在什麼時候釋放傳回的book對象,實際開發中常用。

開發中經常會提供一些類方法,快速建立一個已經autorelease過的對象,建立對象時不要直接用類名,用self,因為這樣寫,此類的子類都能調用這個方法,自動識别,self 指向調用這個方法的類,不會出錯。

一般來說,除了alloc、new或copy之外,其他的方法建立的對象都被聲明了autorelease

比如下面的對象都已經是autorelease的,不需要再release

一、計數器的基本操作

1> retain : +1

2> release :-1

3> retaincount : 獲得計數器

二、set方法的記憶體管理

1> set方法的實作

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

2> dealloc方法的實作(不要直接調用dealloc)

objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;
objective-c 文法快速過(6)記憶體管理原理記憶體管理基本原理(最重要)循環引用(著名的問題)@class的使用小結;

三、@property參數

1> oc對象類型

@property (nonatomic, retain) 類名 *屬性名;

@property (nonatomic, retain) car *car;

@property (nonatomic, retain) id car;

// 被retain過的屬性,必須在dealloc方法中release屬性

- (void)dealloc

{

    [_car release];

    [super dealloc];

}

2> 非oc對象類型(int\float\enum\struct)

@property (nonatomic, assign) 類型名稱 屬性名;

@property (nonatomic, assign) int age;

四、autorelease

1.系統自帶的方法中,如果不包含alloc、new、copy,那麼這些方法傳回的對象都是已經autorelease過的

[nsstring stringwithformat:....];

[nsdate date];

2.開發中經常寫一些類方法快速建立一個autorelease的對象

* 建立對象的時候不要直接使用類名,用self

辛苦的勞動,轉載請注明出處,謝謝……

http://www.cnblogs.com/kubixuesheng/p/4314322.html

繼續閱讀