1. 程式人生 > >iOS static、const和extern相關的問題

iOS static、const和extern相關的問題

static

static分兩種情況,修飾區域性變數和全域性變數。
我們首先要搞清楚生命週期和作用域的概念。
生命週期:這個變數能存活多久,它所佔用的記憶體什麼時候分配,什麼時候收回。
作用域:說白了就是這個變數在什麼區域是可見的,可以拿來用的。

static修飾區域性變數

在函式或者說程式碼塊內部宣告的變數叫區域性變數。

區域性變數

區域性變數是儲存在棧區的,它的生命週期是整個程式碼塊,作用域也是整個程式碼塊,一旦出了這個程式碼塊,儲存區域性變數的這個棧記憶體就會被回收,區域性變數也就被銷燬了。看一個例子:
在這裡插入圖片描述

列印結果:
在這裡插入圖片描述

這個其實很好理解,區域性變數a是在test方法的程式碼塊內宣告的,所以它的生命週期就是這個程式碼塊,當我們呼叫完一次test方法後,區域性變數a就被銷燬了,不存在了。在下一次呼叫test方法時又在棧區重新申請了記憶體。

當我們用static修飾區域性變數時,變數被稱為靜態區域性變數,這個靜態區域性變數和全域性變數,靜態全域性變數一樣,是儲存在靜態儲存區。**由於儲存在靜態儲存區,所以這塊記憶體直到程式結束才會銷燬。也就是說,靜態區域性變數的生命週期是整個源程式。但是它只在宣告它的程式碼塊可見,也就是說它的作用域是宣告它的程式碼塊。我們把區域性變數a用static修飾:
在這裡插入圖片描述

看一下列印結果:
在這裡插入圖片描述

當我們第一次呼叫test方法時,在靜態儲存區申請了一塊記憶體嗎,這塊記憶體名字叫a,裡面裝著數字0,然後把數字0加1,變成了1,當第二次呼叫test方法時,會去靜態儲存區查詢有沒有一塊記憶體叫a,如果有那就不用重新分配記憶體初始化,這裡找到了這塊叫a的記憶體,所以不用進行初始化,所以a裡面還是裝的1然後對1加1,得到了2.

static修飾全域性變數

當全域性變數沒有使用static修飾符時,其儲存在靜態儲存區,直到程式結束才銷燬。也就是其作用域是整個源程式。我們可以使用extern關鍵字來引用這個全域性變數。
Test.h:
在這裡插入圖片描述

ViewController.m:
在這裡插入圖片描述

static修飾,列印結果:
當全域性變數使用static修飾時,其生命週期沒有變,依舊是在程式結束時才銷燬。但是其作用域變了,以前是整個源程式,現在只限於申明它的這個檔案才可見,即使用extern引用也不行,比如我們把上面的例子中globalVar前面用static修飾,那麼程式就會報錯:
在這裡插入圖片描述

沒有static修飾,列印結果:
在這裡插入圖片描述

總結:

static修飾區域性變數

:將區域性變數的本來分配在棧區改為分配在靜態儲存區,也就改變了區域性變數的生命週期。
static修飾全域性變數:本來是在整個源程式的所有檔案都可見,static修飾後,改為只在申明自己的檔案可見,即修改了作用域。

const

const修飾變數主要強調變數是不可修改的。我們看一下下面程式碼段:
在這裡插入圖片描述

從結果可以看到變數a的值修改成功,那麼我們將變數a用const修飾試一試:
在這裡插入圖片描述

使用const修飾變數a之後,a的值就不能修改了,所以這裡修改就不成功了。

需要注意的一點是,const修飾的是其右邊的值,也就是const右邊的這個整體的值不能改變。

下面例子是const修飾*str這個整體,所以這個整體不能改變,這個整體是str指向的記憶體中的值。
在這裡插入圖片描述

下面例子是const修飾str的,所以str指向的地址不能改變,因此這裡的改變就產生了錯誤。
在這裡插入圖片描述

一般聯合使用static和const來定義一個只能在本檔案中使用的,不能修改的變數:
在這裡插入圖片描述

這樣定義相對於用#define來定義的話,優點就在於它指定了變數的型別,而#define是不能指定變數的型別的。

extern

extern主要是用來引用全域性變數,它的原理就是先在本檔案中查詢,本檔案中查詢不到再到其他檔案中查詢。

常把extern和const聯合使用在專案中建立一個檔案,這個檔案檔案中包含整個專案中都能訪問的全域性常量。比如我們在專案中建立的這個檔案為LMConst.h,LMConst.m。
LMConst.h:
在這裡插入圖片描述

LMConst.m:
在這裡插入圖片描述

pch檔案:
在這裡插入圖片描述

然後我們就可以直接在其他檔案中使用NOTIFICATION_NAME這個字串常量了:
在這裡插入圖片描述