在寫項(xiàng)目 或 閱讀別人的代碼(一些優(yōu)秀的源碼)中,總能發(fā)現(xiàn)一些常見的關(guān)鍵字,隨著編程經(jīng)驗(yàn)的積累大部分還是知道是什么意思
的。

相信很多開發(fā)者跟我當(dāng)初一樣,只是基本的常用關(guān)鍵字定義屬性會(huì)使用,但在關(guān)鍵字概念上及具體的用法「應(yīng)用場(chǎng)景、優(yōu)化選擇」上卻依然有些模糊。
本文為「簡(jiǎn)書-白開水ln」作者原創(chuàng);你關(guān)注的人,決定了你看到的世界 ^_^.

目錄:

  1. 關(guān)鍵字 const/static/extern 的「釋義和用法」
    1、const
    2、static
    3、extern
    4、static與const聯(lián)合使用
    5、extern與const聯(lián)合使用
    6、const與宏的區(qū)別?「面試題」

  2. 期待 & 后續(xù)

關(guān)鍵字 const/static/extern 的「釋義和用法」

1、const
  • const 簡(jiǎn)介:之前常用的字符串常量。

  • const 作用:

  • const 僅僅用來修飾右邊的變量(基本數(shù)據(jù)變量p,指針變量*p)

  • const 修飾的(全局)變量是只讀的,不能修改。

  • const 基本使用:

- (void)viewDidLoad {
    [super viewDidLoad];    // 定義變量
    int a = 1;    // 允許修改值
    a = 20;    // const兩種用法
    // const:修飾基本變量p
    // 這兩種寫法是一樣的,const只修飾右邊的基本變量b
    const int b = 20; // b:只讀變量
    int const b = 20; // b:只讀變量
    // 不允許修改值,錯(cuò)誤
    b = 1;    // const:修飾指針變量*p,帶*的變量,就是指針變量.
    // 定義一個(gè)指向int類型的指針變量,指向a的地址
    int *p = &a;    int c = 10;    // 允許修改p指向的地址,  
    p = &c;    // 允許修改p訪問內(nèi)存空間的值
    *p = 20;//--------------------------- 面試題 ------------------------------//

    // const修飾指針變量訪問的內(nèi)存空間,修飾的是右邊*p1,
    // 兩種方式一樣
    const int *p1; // *p1:只讀  p1:變量
    int const *p1; // *p1:只讀  p1:變量
    
    // const修飾指針變量p1
    int * const p1; // *p1:變量 p1:只讀
    
    // 第一個(gè)const修飾*p1 第二個(gè)const修飾 p1
    // 兩種方式一樣
    const int * const p1; // *p1:只讀 p1:只讀
    int const * const p1;  // *p1:只讀 p1:只讀}
注意: 判斷p 和 *p是只讀還是變量,關(guān)鍵是看const在誰前面。
  • const 開發(fā)中應(yīng)用場(chǎng)景

@implementation ViewController// 定義只讀全局常量 => 代替宏NSString * const str  = @"123";// 當(dāng)一個(gè)方法的參數(shù),只讀.- (void)test:(NSString * const)name
{
}// 指針只讀,不能通過指針修改值- (void)test1:(int const *)a
{
}// 基本數(shù)據(jù)類型只讀- (void)test2:(int const)a
{
}@end
2、static
  • static 簡(jiǎn)介:可釋義為“靜態(tài)”的意思。

  • static 作用:

  • 修飾局部變量:

    • static修飾局部變量,延長(zhǎng)生命周期,跟整個(gè)應(yīng)用程序有關(guān)。

    • static修飾局部變量,只會(huì)分配一次內(nèi)存。

    • static修飾局部變量什么分配內(nèi)存?【程序一運(yùn)行就會(huì)給static修飾變量分配內(nèi)存】。

  • 修飾全局變量:

    • static修飾全局變量,會(huì)作修改用域(防止重復(fù)聲明全局變量),只能在當(dāng)前文件下使用。即當(dāng)前文件內(nèi)部才能訪問該全局變量。

  • static 基本使用:

  • 保證局部變量永遠(yuǎn)只初始化一次,在程序的運(yùn)行過程中永遠(yuǎn)只有一份內(nèi)存, 生命周期類似全局變量了,但是作用域不變。這句話怎么理解呢?還是以代碼例子來講解吧。

// 被`static`修飾局部變量-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{    //聲明一個(gè)局部變量i
    int i = 0; // 方式一
    static  int i = 0; // 方式二
    i ++;    NSLog(@"i=%d",i);
}

打印輸出:
方法一2016-10-26 14:58:48.290 test[2760:170260] i=12016-10-26 14:58:49.044 test[2760:170260] i=12016-10-26 14:58:49.200 test[2760:170260] i=1方式二2016-10-26 15:07:34.276 test[2817:175155] i=12016-10-26 15:07:35.347 test[2817:175155] i=22016-10-26 15:07:35.761 test[2817:175155] i=3注解
方式一:因?yàn)槊看吸c(diǎn)擊進(jìn)入這個(gè)方法就會(huì)重新初始化一個(gè)全新的變量i = 0,加加了一次后值變?yōu)?,然后打印出結(jié)果為1,
出了這個(gè)方法后局部變量i就被釋放回收。
方式二:它不是每次進(jìn)去都被初始化賦值為0了么,怎么能累加呢。
這就是關(guān)鍵字static修飾的局部變量的作用,讓局部變量永遠(yuǎn)只初始化一次,一份內(nèi)存,生命周期已經(jīng)跟全局變量類似了,只是作用域不變。

iOS 中在一個(gè)文件聲明的全局變量,工程的其他文件也是能訪問的,但是我又不想讓其他文件訪問,這時(shí)就可以用static修飾它了,比較典型的是使用GCD一次性函數(shù)創(chuàng)建的單例,全局變量基本上都會(huì)用static修飾。

// 被`static`修飾全局變量@implementation LoginTool// static修飾全局變量,讓外界文件無法訪問static LoginTool *_sharedManager = nil;

+ (LoginTool *)sharedManager {     static dispatch_once_t oncePredicate;     dispatch_once(&oncePredicate, ^{
        _sharedManager = [[self alloc] init];
    });    return _sharedManager;
}
3、extern
  • extern 簡(jiǎn)介:可釋義為“外部”的意思。

  • extern 作用:只是用來聲明外部全局變量,注意 extern 只能聲明,不能用于定義。

  • extern 工作原理:先在當(dāng)前文件查找有沒有全局變量,沒有找到,才會(huì)去其他文件查找。

  • extern 基本使用

在 ViewController.m 文件中 定義個(gè)全局的常量int i = 15;

在 AppDelegate.m 文件中聲明extern int i;NSLog(@"%d",i); // 打印輸出 15
4、static與const聯(lián)合使用
  • static與const作用:聲明一個(gè)只讀的靜態(tài)變量

  • 需求:1、變量為只讀,防止修改 2、只在當(dāng)前文件下使用(非全局),可以使用static與const組合。

// iOS中staic和const常用使用場(chǎng)景,是用來代替宏,把一個(gè)經(jīng)常使用的字符串常量,定義成靜態(tài)全局只讀變量.// 開發(fā)中經(jīng)常拿到key修改值,因此用const修飾key,表示key只讀,不允許修改。static修飾后表示只能本文件訪問。static  NSString * const key = @"name";// 如果 const修飾 *key1,表示*key1只讀,key1還是能改變。static  NSString const *key1 = @"name";
5、extern與const聯(lián)合使用
  • 開發(fā)中使用場(chǎng)景:在 多個(gè)文件中 經(jīng)常使用的同一個(gè)字符串常量,可以使用externconst組合。

  • 原因:

  • 使用externconst組合:在每個(gè)文件都需要定義一份靜態(tài)全局變量(報(bào)重復(fù)定義錯(cuò)誤)。

  • 使用externconst組合:只需要定義一份全局變量,多個(gè)文件共享。

  • 全局常量正規(guī)寫法:全局變量不能定義在自己類中,開發(fā)中便于管理所有的全局變量,通常搞一個(gè)GlobeConst文件,里面專門定義全局變量,統(tǒng)一管理,要不然項(xiàng)目文件多不好找。

在開發(fā)中,我們通常會(huì)單獨(dú)抽一個(gè)類來管理一些全局的變量或常量,下面來看看高逼格的一種做法:

//  GlobeConst.m#import "GlobeConst.h"// 定義整個(gè)項(xiàng)目中全局變量//--------------------------- 首頁 ------------------------------////NSString * const home_name = @"name";//--------------------------- 發(fā)現(xiàn) ------------------------------////NSString * const discover_name = @"name";//--------------------------- 圈子 ------------------------------////NSString * const circle_name = @"name";//--------------------------- 我的 ------------------------------////

//  GlobeConst.h#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>// 在開發(fā)中,我們通常會(huì)單獨(dú)抽一個(gè)類來管理一些全局的變量或常量,下面來看看【高逼格】的一種做法:#ifdef __cplusplus#define LNKIT_EXTERN        extern "C" __attribute__((visibility ("default")))#else#define LNKIT_EXTERN            extern __attribute__((visibility ("default")))#endif// 聲明整個(gè)項(xiàng)目中全局變量(把聲明放到.h中)//--------------------------- 首頁 ------------------------------////extern NSString * const home_name;//--------------------------- 發(fā)現(xiàn) ------------------------------//// 系統(tǒng)UIKIT_EXTERN NSString * const discover_name;//--------------------------- 圈子 ------------------------------//// 高逼格LNKIT_EXTERN NSString * const circle_name;//--------------------------- 我的 ------------------------------////

總結(jié):這樣,只要導(dǎo)入頭文件,就可以全局的使用定義的變量或常量。

6、const與宏的區(qū)別?「面試題」

從四點(diǎn)回答:

  • 編譯時(shí)刻:宏是預(yù)編譯(編譯之前處理);const 是編譯階段。

  • 編譯檢查:宏不做檢查,不會(huì)報(bào)編譯錯(cuò)誤,只是替換;const 會(huì)編譯檢查,會(huì)報(bào)編譯錯(cuò)誤。

  • 宏的好處:宏能定義一些函數(shù) 或 方法。 const 不能。

  • 宏的壞處:使用大量宏,容易造成編譯時(shí)間久,每次都需要重新替換。


  • 注意:很多Blog都說大量使用宏,會(huì)消耗大量?jī)?nèi)存,我這驗(yàn)證并不會(huì)生成很多內(nèi)存,宏定義的是常量,常量都放在常量區(qū),只會(huì)生成一份內(nèi)存。

  • 提示:蘋果不推薦我們抽成宏,推薦我們使用const常量,Swift已干掉了。

  • 代碼示例:

// 常見的常量:抽成宏#define LNAccount @"account"#define LNUserDefault [NSUserDefaults standardUserDefaults]// 字符串常量static NSString * const account = @"account";
- (void)viewDidLoad {
    [super viewDidLoad];    // 偏好設(shè)置存儲(chǔ)
    // 使用宏
    [LNUserDefault setValue:@"123" forKey:LNAccount];    // 使用const常量
    [[NSUserDefaults standardUserDefaults] setValue:@"123" forKey:account];
}

未完----------。待續(xù)
未完----------。待續(xù)
未完----------。待續(xù)

期待


  • 如果在閱讀過程中遇到 error,希望你能 Issues 我,謝謝。

  • 如果你想為【本文相關(guān)】分享點(diǎn)什么,也希望你能 Issues 我,我非常想為這篇文章增加更多實(shí)用的內(nèi)容,謝謝。

  • 「博客原文」對(duì)本文我會(huì)【不定時(shí)、持續(xù)更新、一些 學(xué)習(xí)心得與文章、實(shí)用才是硬道理】^_^.

About me


【我也是對(duì)所花費(fèi)時(shí)間的一個(gè)總結(jié)】

我只是個(gè)【有思想的伐碼猿??】加上【自己的學(xué)習(xí)總結(jié)??】寫出來的文章。

http://www.cnblogs.com/Plainboiledwater/p/6752443.html