本節書摘來自華章出版社《編寫高品質代碼:改善objective-c程式的61個建議》一 書中的第2章,作者:劉一道,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
在objective-c中,利用指針寫代碼,特别對于指針掌握不熟練的人,經常會遭遇到空指針和野指針的困擾,造成應用出現一些莫名其妙的崩潰。是以,有必要在寫objective-c代碼時,高度警惕空指針和野指針的襲擊。
兵法上講究“知己知彼,百戰不殆”,那麼就從什麼是空指針和野指針來入手,認識這兩個經常搞襲擊的常客。
認識空指針和野指針
沒有存儲任何記憶體位址的指針就稱為空指針(null指針)。空指針就是被指派為0的指針,在沒有被具體初始化之前,其值為0。也就是說,一個指針變量配置設定一個null值的情況下,沒有确切的位址被配置設定。
下面兩個都是空指針:
null指針是一個常數與幾個标準庫中定義的一個零值。考慮下面的程式:
上面的代碼編譯和執行時,它會産生以下結果:
大部分的作業系統程式不允許被保留,因為該記憶體由作業系統來通路記憶體位址0處。然而,存儲器位址0具有特殊的意義,它的信号指針不指向一個可通路的存儲器位置。但是,按照慣例,如果一個指針包含空值(零),它被假定為指向什麼。
要檢查空指針,可以使用一個if語句,具體如下:
野指針不是null指針,而是指向“垃圾”記憶體(不可用記憶體)的指針。野指針是非常危險的。
空指針和野指針的差別及防禦政策
接下來用一個簡單的例子對比一下野指針和空指針的差別,同時,介紹如何防止空指針和野指針的産生。
(1)首先,打開xcode的記憶體管理調試開關,它能幫助使用者檢測垃圾記憶體,如圖2-1和圖2-2所示。
(2)自定義student類,在main函數中添加下列代碼:
運作程式,你會發現第7行報錯了,是一個野指針錯誤,如圖2-3所示。
(3)接下來分析一下報錯原因。
① 執行完第1行代碼後,記憶體中有個指針變量stu,指向了student對象。
假設student對象的位址為0xff43,指針變量stu的位址為0xee45,stu中存儲的是student對象的位址0xff43,即指針變量stu指向了這個student對象,如圖2-4所示。
②接下來是第3行代碼:
這行代碼的意思是:給stu所指向的student對象發送一條setage:消息,即調用這個student對象的setage:方法。目前來說,這個student對象仍存在于記憶體中,是以這句代碼沒有任何問題。
③接下來是第5行代碼:
這行代碼的意思是:給stu指向的student對象發送一條release消息。在這裡,student對象接收到release消息後,會馬上被銷毀,所占用的記憶體會被回收。
student對象被銷毀了,位址為0xff43的記憶體就變成了“垃圾記憶體”,然而,指針變量stu仍然指向這一塊記憶體,如圖2-5所示,這時stu就成為野指針。
④最後執行了第7行代碼:
這句代碼的意思仍然是:給stu所指向的student對象發送一條setage:消息。但是在執行完第5行代碼後,student對象已經被銷毀了,它所占用的記憶體已經是垃圾記憶體,如果你還去通路這一塊記憶體,那就會報野指針錯誤。這塊記憶體已經不可用了,也不屬于你了,你還去通路它,肯定是不合法的。是以,這行代碼報錯了!
(4)如果改動一下代碼,就不會報錯了,如下所示:
注意第7行代碼,stu變成了空指針,stu就不再指向任何記憶體了,如圖2-6所示。因為stu是個空指針,沒有指向任何對象,是以第9行的setage:消息是發不出去的,不會造成任何影響。當然,肯定也不會報錯。
要點
(1)空指針(null指針),是指沒有存儲任何記憶體位址的指針。野指針,是指向“垃圾記憶體”(不可用記憶體)的指針。
(2)利用野指針發消息是很危險的,會報錯。也就是說,如果一個對象已經被回收了,就不要再去操作它,不要再嘗試給它發消息。
(3)利用空指針發消息是沒有任何問題的,也就是說代碼是沒有錯誤的。