《編寫高質(zhì)量iOS與OS X代碼的52個有效方法》--第五章 第36條
(ps:此乃讀書筆記,加深記憶,僅供大家參考)
第36條 不要使用retainCount
NSObject協(xié)議中定義了下列方法,用于查詢對象當前的保留計數(shù):
- (NSUInteger)retainCount
然而ARC已經(jīng)將此方法廢棄了。若在不啟用ARC的環(huán)境下編程,那么扔可調(diào)用此方法,所以還是必須講清楚為何不應使用此方法。
這個方法看上去似乎挺合理的、挺有用的。但問題在于,保留計數(shù)的絕對值一般都與開發(fā)者所應留意的事情完全無關。即便是在調(diào)試時才調(diào)用此方法,通常也還是無所助益的。
此方法之所以無用,其首要原因在于:它所返回的保留計數(shù)只是某個給定時間點上的值。該方法并未考慮到系統(tǒng)會稍后把自動釋放池清空,因而不會將后續(xù)的釋放操作從返回值里減去,這樣的話,此值就未必能真實反映實際的保留計數(shù)了。
有下面這段代碼:
NSString *stirng = @"Some string";
NSLog(@"string retainCount = %lu", [stirng retainCount]);
NSNumber *numberI = @1;
NSLog(@"numberI retainCount = %lu", [numberI retainCount]);
NSNumber *numberF = @3.14f;
NSLog(@"numberF retainCount = %lu", [numberF retainCount]);
在64位Mac OS X 10.8.2系統(tǒng)中,用Clang4.1編譯后,這段代碼輸出的消息如下:
string retainCount = 18446744073709551615
numberI retainCount = 9223372036854775807
numberF retainCount = 1
第一個對象的保留計數(shù)是2^64 - 1,第二個對象的保留計數(shù)是2^63 - 1.由于二者皆為“單例對象”(singleton object),所以其保留計數(shù)都很大。系統(tǒng)會盡可能把NSStirng實現(xiàn)成單例對象。如果字符串像本例所舉的這樣,是個編譯常量(compile-time constant),那么就可以這樣來實現(xiàn)了。在這用情況下,編譯器會把NSString對象所表示的數(shù)據(jù)放到應用程序的二進制文件里,這樣的話,運行程序時就可以直接用了,無須再創(chuàng)建NSString對象。NSNumber也類似,它使用了一種叫做“標簽指針”(tagged pointer)的概念來標注特定類型的數(shù)值。這種做法不使用NSNumber對象,而是把與數(shù)值有關的全部消息都放在指針值里面。運行期系統(tǒng)會在消息派發(fā)(參見第11條)期間檢測到這種標簽指針,并對它執(zhí)行相應操作,使其行為看上去和真正的NSNumber對象一樣。這種優(yōu)化只在某些場合使用,比如范例中的浮點數(shù)對象就沒有優(yōu)化,所以其保留計數(shù)就是1。
另外,像剛才所說的那種單例對象,其保留計數(shù)絕對不會變。這種對象的保留及釋放操作都是“空操作”(no-op)。
那么,只為了調(diào)試而使用retainCount方法行不行呢?即便只為調(diào)試,此方法也不是很有用。以下列代碼為例:
id object = [self createObject];
[opaqueObject doSomethingWithObject:object];
NSLog(@"retainCount = %lu", [object retainCount]);
object的保留計數(shù)是多少呢?這個計數(shù)可以是任意值?!癲oSomethingWithObject:”方法也許會將對象加到多個collectin中,而這些collection均會保留此對象。這個方法還可能會多次保留并自動釋放此對象,而其中某些自動釋放操作要留待系統(tǒng)稍后清空自動釋放池時才執(zhí)行。因此,保留計數(shù)的實際值就不是那么有用了。
要點
- 對象的保留計數(shù)看似有用,實則不然,因為任何給定時間點上的“絕對保留計數(shù)”(absolute retain count)都無法反映對象生命期的全貌。
- 引入ARC之后,retainCount方法就正式廢止了,在ARC下調(diào)用該方法會導致編譯器報錯。