1. 程式人生 > >iOS面試題整理---【initWithString、initWithFormat及stringWithFormat的區別】

iOS面試題整理---【initWithString、initWithFormat及stringWithFormat的區別】

original 根據 後來 mat sep 常量 參數 代碼 表示

[轉載]initWithString、initWithFormat及stringWithFormat的區別

其實這幾個方法看似沒啥區別,用的時候也很少在意,但最近無聊折騰了一下,卻發現有些端倪。這裏先說Apple的一個優化策略:Tagged Pointer,這裏引用大神的文章: iOS Tagged Pointer - 簡書。簡單來說就是運行時讓能用指針地址表達的值就用指針地址表達,不再單獨分配內存地址,上個代碼先:

技術分享圖片

以a的ascii碼為基礎,依次加一,然後根據新的ascii碼生成字符串a、b、c.....i、j,並打印他們的相關信息,打印結果如下:

技術分享圖片 打印結果

可以看到,通過stringWithFormat創建的字符串的類型是NSTaggedPointerString類型而不是__NSCFString或者__NSCFConstantString類型的。然後再看指針的地址,最後的兩位應該是標識位,倒數第一位應該是指定值的類型,倒數第二位表示值的長度,剩下的61到6a是遞增的,剛好符合上面代碼ascii碼的循環加一,61是“a”ascii碼的十六進制表示,這就說明了運行時使用了Tagged Pointer技術。為啥要說這些亂七八糟的東西?因為我之前不知道有Tagged Pointer這個高級的東東,在測試NSString相關方法的時候踩了一些坑,所以特此介紹,免得看這篇文章的同學被坑進去,在測試的時候盡量用中文或者長字符串,這樣就能夠讓系統在堆區中給字符串分配內存空間。??

接下來回到正題,在使用字面量聲明字符串的時候,字符串是放在常量區的,在編譯階段就已經確定,所以以下代碼的變量無論聲明多少都是引用常量區裏面的同一個字符串。

技術分享圖片 代碼

技術分享圖片 打印結果

然後來看看stringWithFormat和initWithFormat,一個是類方法,一個是實例方法,stringWithFormat的內存管理方式是autorelease,initWithFormat則需要手動釋放(ARC下不用處理,編譯器幫我們完成了)。一眼看去好像差別不大。但是

stringWithFormat

在下面的代碼中就有問題了:

技術分享圖片 代碼
技術分享圖片 內存監控

內存出現了暴增的現象,這是由於stringWithFormat會在內部對創建的字符串做一次autorelease處理,這就導致了對象的延遲釋放,因為這裏有個for循環,那麽autoreleasepool會等到runloop的當前循環結束後才會對釋放池中的每個對象發送release消息,而runloop的當前循環結束的前提是要等for循環執行完,所以for循環內創建的對象就會在for循環執行完之前一直存在在內存中,導致暴增。再來看看

initWithFormat:

技術分享圖片 代碼

這裏編譯器會有一個警告,提示你這是一個弱引用,會在單次循環結束後被釋放(這裏就已經能夠說明問題了),接著我們來看看內存監控:

技術分享圖片 內存監控

並沒有出現暴增的情況,也就是說initWithFormat創建的對象在ARC模式中,for的單次循環結束後就會release一次並被釋放(MRC下手動管理)。

那麽習慣使用stringWithFormat的同學就要註意點了,如果存在循環大量的創建字符串,要麽我們盡量使用initWithString,非要用stringWithFormat怎麽辦?其實在循環內加個@autoreleasepool就好了(保證每次for循環都對對象release一次),就像下面這樣:

技術分享圖片 代碼

最後,關於

initWithString

這個方法如果你傳的是字面量,那麽編譯器會提示你其實可以直接用字面量賦值,如果傳的是變量或常量,我猜內部應該是返回的一個拷貝給你(參數是類型是NSString的話就是淺拷貝,NSMutableString就是深拷貝),內部代碼我猜是這樣的:

技術分享圖片 代碼

放個測試代碼:

技術分享圖片 代碼 技術分享圖片 打印

主要看str2、str3、str4、str5,str2是字面量賦值的變量,所以值是在常量區,str3是用str2創建的,他們的地址是一樣的,說明str3也是引用了常量區的值。str4的值是分配在堆區的,str5跟str4的地址一樣,說明引用的是str4在堆中的值地址,所以我推測,initWithString內部只是做了一次copy。sorry,廢話有點多,就一個小的知識點,如果之前不知道,希望能幫到你,如果你對此非常了解並對我寫的有不同的觀點,希望能幫我指出不足或錯誤。

T

iOS面試題整理---【initWithString、initWithFormat及stringWithFormat的區別】