眼看就要過年了米苹,這兩天卻著著實實被全局變量坑了一把,APP開發(fā)者和我們SDK使用了相同的全局變量導致嵌碼沖突烙懦。還好只是公司內部APP嵌碼發(fā)現(xiàn)的問題驱入,沒有交付給大客戶。否則氯析,恐怕要被客戶和經(jīng)理批的狗血臨頭亏较,學藝不精也怨不了誰。今天就結合第三方以及自身的理解詳細分析一下iOS的包含的所有變量掩缓,上圖:
下面我命就詳細分析各個變量的使用:
一雪情、static靜態(tài)變量
靜態(tài)變量優(yōu)點:
1、節(jié)省內存你辣。靜態(tài)變量只存儲一處巡通,但供所有對象使用尘执。
2、它的值是可以更新的宴凉。
3誊锭、可提高時間效率。只要某個對象對靜態(tài)變量更新一次弥锄,所有的對象都能訪問更新后的值丧靡。
靜態(tài)變量static的使用
1、修飾局部變量
讓局部變量只初始化一次籽暇,局部變量在程序中只有一份內存温治,但是并不會改變局部變量的作用域,僅僅是改變了局部變量的生命周期(只到程序結束戒悠,這個局部變量才會銷毀)熬荆。
2、修飾全局變量
全局變量的作用域僅限于當前文件
3绸狐、static作用于函數(shù):e.g.: static void func(void);
使用static用于函數(shù)定義時卤恳,對函數(shù)的連接方式產(chǎn)生影響,使得函數(shù)只在本文件內部有效六孵,對其他文件是不可見的纬黎。這樣的函數(shù)又叫作靜態(tài)函數(shù)。使用靜態(tài)函數(shù)的好處是劫窒,不用擔心與其他文件的同名函數(shù)產(chǎn)生干擾本今,另外也是對函數(shù)本身的一種保護機制。
如果想要其他文件可以引用本地函數(shù)主巍,則要在函數(shù)定義時使用關鍵字extern冠息,表示該函數(shù)是外部函數(shù),可供其他文件調用孕索。另外在要引用別的文件中定義的外部函數(shù)的文件中逛艰,使用extern聲明要用的外部函數(shù)即可。
- 重點:也就是說搞旭,static定義的方法和或者變量最多也不會超出所在文件散怖,也就是所在類。如果要其他類引用次靜態(tài)方法肄渗,那么就必須要extern聲明引用镇眷。
static int age = 20;//全局變量
static NSString *name = @"zhang";
- (void)staticTest{
// static修飾局部變量,將全局變量變成局部變量翎嫡,但是在其他地方全局變量還是不變的
static int age = 0;
age++;
//所以此處輸入的是局部變量的值欠动,在其他部分調用全局age還是20.
NSLog(@"局部變量的age:%d",age);
}
常見的使用場景:
1)最常見的就是Cell復用的CellIdentifier設置都是定義為靜態(tài)的字符串。(就是為了節(jié)省內存和提高時間效率)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
2)單例創(chuàng)建
+ (AccountManager *)sharedManager
{
static AccountManager *sharedAccountManagerInstance = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedAccountManagerInstance = [[self alloc] init];
});
return sharedAccountManagerInstance;
}
extern修飾全局變量
- extern作用域為整個源程序,在Reachability.h中具伍,extern配合const設置了一個的全局且不可變的變量翅雏,如下:
#ifndef NS_ENUM
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#endif
//設置全局且不可變變量kReachabilityChangedNotification,在Reachability.m中賦值
extern NSString *const kReachabilityChangedNotification;
extern配合const設置要特別注意一點人芽,那就是變量的命名一定要有特殊性望几,在多人開發(fā)過程中防止定義相同導致的沖突,如下圖:
所以啼肩,使用全局變量要慎重橄妆,而且代碼要規(guī)范衙伶,避免不必要的坑祈坠。
extern與const聯(lián)合使用:
static與const組合:在每個文件都需要定義一份靜態(tài)全局變量。
extern與const組合:只需要定義一份全局變量矢劲,多個文件共享赦拘。extern作用:
只是用來獲取全局變量(包括全局靜態(tài)變量)的值,不能用于定義變量
extern工作原理:
先在當前文件查找有沒有全局變量芬沉,沒有找到躺同,才會去其他文件查找。
- (void)externAndConst{
/*
一般會先新建.h文件專門存放常量的引用丸逸,在iOS的網(wǎng)絡判斷Reachbility中就有蹋艺。
注意一定要在.h文件中定義,否則會報錯黄刚。
*/
// extern NSString *const kReachabilityChangedNotification;
// extern const int num;
//逼格更高的一種寫法捎谨,模仿系統(tǒng)UIKIT_EXTERN來替代extern
// UIKIT_EXTERN NSString *const kReachabilityChangedNotification;
// UIKIT_EXTERN const int num;
/*
在.m file中進行賦值專門存放static const修飾的變量,需要用的時候導入頭文件就可以了憔维。
定義整個程序都能訪問的常量
*/
const int num = 666;
NSString *const kReachabilityChangedNotification = @"kReachabilityChangedNotification";
}
在AFNetWorking中也有使用extern涛救,這里作為一個擴展,截圖如下:
三业扒、局部變量
此處的i就是局部變量检吆,僅僅作用在這個for循環(huán)方法內部。
for (int i = 0; i < array.count; i ++) {
NewsTableViewController *pulicVc = [[NewsTableViewController alloc]init];
pulicVc.title = array[i];
[self addChildViewController:pulicVc];
}
四程储、實例變量
下面為實例變量蹭沛,作用域為整個類。
@property (nonatomic,copy) NSString *number; //數(shù)量章鲤,被操作對象的某個序號指標摊灭,如:文章字數(shù)
@property (nonatomic,copy) NSString *objectName; //對象短名稱,如:文章標題
@property (nonatomic,copy) NSString *objectIDs; //對象IDs 統(tǒng)計列表中多個文章的ID時傳值
五咏窿、const變量值不可變
我們設置不可變參數(shù)noChange斟或,然后兩次賦值,如下圖所示集嵌,我們在賦值一次之后萝挤,第二次想要改變noChange的值的時候報錯:
1御毅、使用static const修飾變量和宏定義的比較
- 相同點:
a:都不能再被修改
b:一處修改,其他地方都改不了 - 不同點:
a:static const 修飾變量只有一份內存
b:宏定義只是簡單的替換怜珍,每次使用都需要創(chuàng)建一份內存端蛆。
2、結論:
使用static const修飾更加高效酥泛,在同一個文件內可以使用static const取代#define
static const聲明一個靜態(tài)的全局只讀常量
3今豆、使用場景:
在一個文件中經(jīng)常使用的字符串常量,可以使用static與const組合柔袁,可用于替換#define
const和宏的區(qū)別:
const簡介:之前常用的字符串常量呆躲,一般是抽成宏,但是蘋果不推薦我們抽成宏捶索,推薦我們使用const常量插掂。
- 編譯時刻:宏是預編譯(編譯之前處理),const是編譯階段腥例。
- 編譯檢查:宏不做檢查辅甥,不會報編譯錯誤,只是替換燎竖,const會編譯檢查璃弄,會報編譯錯誤。
- 宏的好處:宏能定義一些函數(shù)构回,方法夏块。 const不能。
- 宏的壞處:使用大量宏捐凭,容易造成編譯時間久拨扶,每次都需要重新替換。
/*
二茁肠、const 使用
*/
- (void)constTest{
/*
1患民、沒有const修飾的指針。指針p和*p都能夠被修改垦梆。
*/
// 定義一個指針變量
int *p = NULL;
// 定義2個int類型的變量
int a = 10;
int b = 30;
// p指向a
p = &a;
*p = 20;
// p指向b
p = &b;
*p = 40;
NSLog(@"%d %d", a, b);
/*
2匹颤、const修飾的*m,只能被賦值一次托猩,若再次被賦值印蓖,編譯器會報錯。
const int *m = NULL;
*m = 20;
*/
/*
3京腥、const修飾的m,被const修飾的n只能存一次地址赦肃,以后再也不能存其它地址了,否則編譯器報錯
const修飾的指針變量n
int * const n = NULL;
int c = 20;
n = &c; // 編譯器報錯,不能修改指針變量n
*/
/*
4他宛、const聲明字符串的用法船侧,只能賦值一次,再次賦值會出錯厅各。
*/
NSString *const name = @"sam";
}
//三镜撩、static&Const聯(lián)合使用
- (void)staticAndConst{
/*
1、static將一個全局變量變成局部變量
2队塘、const將一個局部變量變成局部常量
*/
// 定義了一個局部常量,只能被賦值一次袁梗,無法再次改變。
static const CGFloat ZMJRed = 0.4;
static const CGFloat ZMJGreen = 0.6;
static const CGFloat ZMJBlue = 0.7;
NSLog(@"---------ZMJRed:%f------ZMJGreen:%f------ZMJBlue:%f",ZMJRed,ZMJGreen,ZMJBlue);
}
//四憔古、static const 與#define 比較
- (void)staticConstAndDefine{
/*
1遮怜、使用static const修飾變量和宏定義的比較
相同點:
a:都不能再被修改
b:一處修改,其他地方都改不了
不同點:
a:static const 修飾變量只有一份內存
b:宏定義只是簡單的替換投放,每次使用都需要創(chuàng)建一份內存奈泪。
2、結論:
使用static const修飾更加高效灸芳,在同一個文件內可以使用static const取代#define
static const聲明一個靜態(tài)的全局只讀常量
3、使用場景:
在一個文件中經(jīng)常使用的字符串常量拜姿,可以使用static與const組合烙样,可用于替換#define
*/
/*
const和宏的區(qū)別:
const簡介:之前常用的字符串常量,一般是抽成宏蕊肥,但是蘋果不推薦我們抽成宏谒获,推薦我們使用const常量。
編譯時刻:宏是預編譯(編譯之前處理)壁却,const是編譯階段批狱。
編譯檢查:宏不做檢查,不會報編譯錯誤展东,只是替換赔硫,const會編譯檢查,會報編譯錯誤盐肃。
宏的好處:宏能定義一些函數(shù)爪膊,方法。 const不能砸王。
宏的壞處:使用大量宏推盛,容易造成編譯時間久,每次都需要重新替換谦铃。
*/
//1耘成、static const 修飾變量只有一份內存
static const CGFloat ZMJBlue = 0.4;
//2、只是用0.4替換ZMJRed define每次使用都會創(chuàng)建一份內存,所以效率不如static const
#define ZMJRed @"zhangsanlisi"
NSString *str = ZMJRed;
NSString *str1 = ZMJRed;
NSLog(@"---str:%p-------str1:%p",str,str1);
#warning 但是引用的define的時候并沒有創(chuàng)建內存啊瘪菌,莫名其妙
// 3件豌、開發(fā)中經(jīng)常拿到key修改值,因此用const修飾key,表示key只讀控嗜,不允許修改茧彤。
static NSString * const key = @"name";
// 4、如果 const修飾 *key1,表示*key1只讀疆栏,key1還是能改變曾掂。
static NSString const *key1 = @"name";
NSLog(@"修改前:%@",key);
key1 = @"zhangsanfang";
NSLog(@"相親們,修改后沒毛脖诙ァ:%@",key1);
// 2018-02-09 14:36:06.617239+0800 OCVariableDemo[4842:891035] --------static1:0x107083970-------static2:0x107083970
// 2018-02-09 14:36:06.617341+0800 OCVariableDemo[4842:891035] --------define:0x608000052000-------define:0x608000052000
}
六珠洗、volatile變量值隨時可變
volatile參數(shù)可以隨時改變,目前沒有找到使用的地方若专,以后遇到的話會補充上來噠许蓖。
參考知識點:http://blog.csdn.net/hdfqq188816190/article/details/51435268,感謝作者“崢吖”的分享调衰,本人在此基礎上做了些補充并寫了Demo供大家查閱膊爪,如有不足之處還望指出。
Demo鏈接:https://github.com/caiqingchong/BianLiang