1.const (常量)
const的作用和宏是很類似的伪煤,當(dāng)有字符串常量的時(shí)候,蘋(píng)果推薦我們使用const宾袜,蘋(píng)果經(jīng)常把常用字符串定義成const狰右。
const僅僅用來(lái)修飾右邊的變量(基本數(shù)據(jù)變量p,指針變量*p秸讹,對(duì)象變量)
被const修飾的變量是只讀的且是全局的檀咙。
const 與宏的區(qū)別
1.編譯時(shí)刻 : const: 編譯時(shí)刻 , 宏:預(yù)編譯
2.編譯檢查: const 會(huì)檢查錯(cuò)誤 , 宏: 不會(huì)檢查錯(cuò)誤
3.宏的好處: 可以定義代碼
4.宏的壞處: 編譯時(shí)間過(guò)長(zhǎng), 因此常用的字符串通常使用 const修飾
注意:很多博客說(shuō)宏使用的多了會(huì)造成內(nèi)存不斷增加,每次都會(huì)分配一個(gè)內(nèi)存, 打印地址可以驗(yàn)證
const 作用:
1.僅僅是用來(lái)修飾右邊的變量(只能修飾變量:基本變量,指針變量,對(duì)象變量)
2.const修飾的變量表示只讀
int * const p; // p:只讀 *p:變量
const int *p1; // *p1:只讀 p1:變量
int const *p2; // *p2:只讀 p2:變量
int const * const p3; // *p3:只讀 p3:只讀
const int * const p4; // *p4:只讀 p4:只讀
2.static
static作用
1.修飾局部變量
* 延長(zhǎng)這個(gè)局部變量的生命周期,只要成員運(yùn)行,局部變量就會(huì)一直存在
* 局部變量只會(huì)分配一次內(nèi)存,為什么?用 static修飾的代碼,只會(huì)在程序一啟動(dòng),就會(huì)執(zhí)行,以后就不會(huì)再執(zhí)行
2.修飾全局變量
* 只會(huì)修改全局變量的作用域,表示會(huì)只能是當(dāng)前文件使用
static修飾變量注意點(diǎn)
用于定義一個(gè)內(nèi)部全局變量
為了提高數(shù)據(jù)的安全性, 不讓別人在其它文件中修改我們的全局變量
只要用static修改的全局變量就是內(nèi)部全局變量, 只能在當(dāng)前文件中使用
如果多個(gè)文件中存在同名的內(nèi)部全局變量, 相互不會(huì)影響
如果既有外部全局變量也有內(nèi)部全局變量, 那么會(huì)優(yōu)先訪問(wèn)內(nèi)部全局變量
3.extern
作用:
extern主要是用來(lái)引用全局變量,它的原理就是先在本文件中查找璃诀,本文件中查找不到再到其他文件中查找弧可。
用于聲明一個(gè)外部全局變量,聲明變量是其他文件的外部變量劣欢。
不能定義變量
聲明只需要在使用變量之前聲明就可以了
聲明和定義的區(qū)別:(聲明不會(huì)開(kāi)辟存儲(chǔ)空間,定義會(huì)開(kāi)辟存儲(chǔ)空間)
注意:UIKIT_EXTERN == extern
總結(jié):
在iOS開(kāi)發(fā)中請(qǐng)盡量多使用const僻焚、enum來(lái)代替宏定義(#define),隨著項(xiàng)目工程的逐漸增大,過(guò)多的宏定義還可能影響項(xiàng)目的編譯速度扰付。
為何不將上面常量直接導(dǎo)入pch文件?
蘋(píng)果不建議使用pch颊埃,pch的原理是將其中定義的宏或全局常量/變量等copy到每個(gè)執(zhí)行文件(.m文件), 如果在其中定義全局常量, 則會(huì)報(bào)重復(fù)定義全局常量錯(cuò)誤.iOS項(xiàng)目中經(jīng)常會(huì)用到一些常量字符串,如果單獨(dú)的在一個(gè).m中使用牧抵,可以用宏定義笛匙,可以用static + const 來(lái)規(guī)定一個(gè)字符串侨把,比如最常用的cell的reuserID,一般我們很少會(huì)用到宏來(lái)修飾妹孙,因?yàn)楹瓴蛔鰴z查秋柄,不會(huì)報(bào)編譯錯(cuò)誤,而且預(yù)編譯的時(shí)候蠢正,會(huì)延長(zhǎng)編譯時(shí)間骇笔,蘋(píng)果也不推薦我們大量的使用宏。
查閱到很多第三方庫(kù)和類似的蘋(píng)果的用法嚣崭,可以看到笨触,很多加以區(qū)分的const字符串都會(huì)寫(xiě)到一個(gè)專門使用的類中,比如MJRefresh的MJRefreshConst.h 和 MJRefreshConst.m有鹿,這種寫(xiě)法有很多好處旭旭,其中之一就是:在規(guī)定全局變量,并且在其他地方引用的時(shí)候葱跋,容易造成字符串重復(fù)的問(wèn)題持寄,特別是在協(xié)同開(kāi)發(fā)的過(guò)程中。因此娱俺,管理人員都是會(huì)規(guī)定好一個(gè)類來(lái)專門的管理這些 只讀字符串 稍味,也就是MJRefreshConst 或者是上面的Const,這樣的話荠卷,在引用過(guò)程中模庐,直接import這個(gè)類就可以使用了,避免了很多不必要的麻煩油宜。
使用注釋加以區(qū)分的話掂碱,能夠把這些字符串分類管理,更加提高團(tuán)隊(duì)工作效率慎冤。
用法總結(jié):
1. 在函數(shù)外疼燥,直接定義對(duì)象,不需要額外添加修飾符蚁堤,對(duì)象可被修改醉者; 一般形式的全局變量
2. 只用static修飾,對(duì)象可以被修改披诗,但是生命周期在APP運(yùn)行期撬即; 用static修飾就是靜態(tài)變量(也叫全局靜態(tài)變量),不用static修飾的就是全局非靜態(tài)變量呈队;
修飾局部變量:讓局部變量只初始化一次剥槐;局部變量在程序中只有一份內(nèi)存;并不會(huì)改變局部變量的作用域宪摧,僅僅是改變了局部變量的生命周期(只到程序結(jié)束才沧,這個(gè)局部變量才會(huì)銷毀)
修飾全局變量:全局變量的作用域僅限于當(dāng)前文件
3. 用const修飾:一般不定義在本文件內(nèi)迈喉,字符串可以被修改,也可以不被修改(主要)温圆;用const修飾的就是常量;全局非靜態(tài)/靜態(tài)常量
4. 用static孩革,const一起修飾:全局靜態(tài)常量岁歉,在本文件內(nèi)字符串可以被修改,也可以不被修改(主要)膝蜈;
常用的三種:
1. static 修飾全局靜態(tài)變量锅移,比如cell的標(biāo)識(shí)符
2. static+const在本文件內(nèi)使用,修飾不可變字符串饱搏,全局靜態(tài)常量
3. const在單獨(dú)一個(gè)文件內(nèi)使用非剃,修飾字符串,變成不可變的常量推沸。
*/
4. 宏
宏的常見(jiàn)用法(常見(jiàn)字符串抽成宏,常見(jiàn)代碼抽成宏)當(dāng)有字符串常量的時(shí)候备绽,蘋(píng)果推薦我們使用const,蘋(píng)果經(jīng)常把常用字符串定義成const
宏與const的區(qū)別:
編譯時(shí)刻:宏是預(yù)編譯(編譯之前處理)鬓催,const是編譯階段肺素。
編譯檢查:宏不做檢查,不會(huì)報(bào)編譯錯(cuò)誤宇驾,只是替換倍靡,const會(huì)編譯檢查,會(huì)報(bào)編譯錯(cuò)誤课舍。
宏的好處:宏能定義一些函數(shù)塌西,方法。 const不能筝尾。
宏的壞處:使用大量宏捡需,容易造成編譯時(shí)間久,每次都需要重新替換忿等。
注意:swift中, 蘋(píng)果已經(jīng)將宏殺掉, 所以項(xiàng)目開(kāi)發(fā)中, 須用const代替宏.
宏定義:
//注意:
//1.宏名和參數(shù)列表之間不能有空格栖忠,否則空格后面的所有字符串都作為替換的字符串。
//2.帶參數(shù)的宏在展開(kāi)時(shí)贸街,只作簡(jiǎn)單的字符和參數(shù)的替換庵寞,不進(jìn)行任何計(jì)算操作。所以在定義宏時(shí)薛匪,一般用一個(gè)小括號(hào)括住字符串的參數(shù)捐川。并且計(jì)算結(jié)果最好也括起來(lái)防止錯(cuò)誤。
#define NAME @"henry" //不帶參數(shù)的宏定義 (格式: #define 標(biāo)示符 字符串(“字符串”可以是常數(shù)逸尖、表達(dá)式古沥、格式串等瘸右。)宏名的有效范圍是從定義位置到文件結(jié)束。如果需要終止宏定義的作用域岩齿,可以用#undef命令太颤。)
#define average(a, b) (a+b)/2 //帶參數(shù)的宏定義:(對(duì)帶參數(shù)的宏,在調(diào)用中,不僅要宏展開(kāi),而且要用實(shí)參去代換形參。格式:#define 宏名(形參表) 字符串)
//條件編譯后面的條件表達(dá)式中不能識(shí)別變量,它里面只能識(shí)別常量和宏定義
#define SCORE 67
#if SCORE > 90
//("優(yōu)秀\n");
#elif SCORE > 60
//NSLog("良好\n");
#else
//NSLog("不及格\n");
#endif
#ifdef MACRO_Define // 如果已定義MACRO_Define這個(gè)宏
//代碼塊1
#else
//代碼塊2
#endif
5. 結(jié)構(gòu)體盹沈,枚舉(typeof與typedef)
typeof 是一個(gè)一元運(yùn)算龄章,放在一個(gè)運(yùn)算數(shù)之前,運(yùn)算數(shù)可以是任意類型乞封∽鋈梗可以理解為:我們根據(jù)typeof()括號(hào)里面的變量,自動(dòng)識(shí)別變量類型并返回該類型肃晚。
typeof 常見(jiàn)運(yùn)用于Block中锚贱,避免循環(huán)引用發(fā)生的問(wèn)題。
用法:
//定義一個(gè)和self相同數(shù)據(jù)類型的bself 关串,并賦值為self拧廊,在block中使用
__weak typeof (self) weakSelf = self;
注意: typeof 括號(hào)中的值和等于后面的值是相同的類型。
__weak typeof(self.contentView) ws = self.contentView;
typedef:定義一種類型的別名悍缠,而不只是簡(jiǎn)單的宏替換卦绣。
typedef 常用于命名(枚舉和Block)
用法1-結(jié)構(gòu)體
//結(jié)構(gòu)體
typedef struct Myrect {
float width;
float height;
}myRect;
用法2-枚舉
//枚舉值 它是一個(gè)整形(int) 并且,它不參與內(nèi)存的占用和釋放,枚舉定義變量即可直接使用,不用初始化.
//在代碼中使用枚舉的目的只有一個(gè),那就是增加代碼的可讀性.
typedef NS_ENUM (NSUInteger,direction){
left=0,
right=1,
top =2,
down =3
};
typedef NS_ENUM (NSUInteger,direction_2){
left2 = 0,
right2 = 1 << 0,
top2 = 1 << 1,
down2 = 1 << 2
};
用法3-Block
//1.重新起個(gè)名字
typedef void(^PassValueBlock)(NSString *);
@interface BlockViewController : BaseViewController
//2.聲明block屬性
@property(nonatomic,copy)PassValueBlock passValueBlock;