一、const 的介紹和基本使用以及使用場景
1.1、const 簡介:經常使用的字符串常量,一般是抽成宏,但是蘋果不推薦我們抽成宏,推薦我們使用const常量。
-
1.2、const 作用:限制類型
- const 僅僅用來修飾右邊的變量(基本數據變量p,指針變量
*p
),被const修飾的變量是隻讀的。如下-
const 用法一 (修飾基本變量p)
不使用const修飾基本變量,允許修改值int a = 10; a = 12; NSLog(@"a=%d",a); 打印結果:a=12
使用const修飾基本變量
//這兩種寫法是一樣的,const只修飾右邊的基本變量 b const int b = 5; // b:只讀變量 int const b = 5; // b:只讀變量 // 由於b是隻讀的,b無法被修改,入下代碼會報錯 b = 3 // 報錯,b無法修改
-
const 用法二 (修飾指針變量
*p
,帶*
的變量,就是 指針變量)
不使用const修飾指針變量// 修飾指針變量 *p,帶 * 的變量,就是指針變量 // 定義一個指向int類型的指針變量,指向a的地址 a = 12; int *p = &a; int c = 7; p = &c; NSLog(@"p=%d",*p); 打印結果:p=8 // 由於 p 沒有被修飾,它訪問 內存空間的值 和 指向的地址 都可以被修改允許修改 *p = 11; NSLog(@"p=%d",p); 打印結果:p=11
使用
const
修飾指針變量,const
修飾指針變量訪問的內存空間,修飾的是右邊東西,如下 8 種情況來分析// 1、2、4 的效果一樣 都是修飾 const右邊的 *q,3修飾的是變量 q ,切記 const修飾的是右邊的 int const *q = 7; // 1 const int *q = 7; // 2 int * const q = 7; // 3 const int *q = 7; // 4 // 首先下面的 q 都被修飾,也就是q不能被賦值,然後 * const q 又被 const 修飾 int const * const q = 7; // 5 const int * const q = 7; // 6 const int * const q = 7; // 7 const int * const q = 7; // 8
提示:
-
1、2、4
的效果一樣 都是修飾 const右邊的*q
,3
修飾的是變量q
,切記const
修飾的是右邊的 - 首先下面的
q
都被修飾,也就是q
不能被賦值,然後* const q
又被const
修飾
-
-
- const 僅僅用來修飾右邊的變量(基本數據變量p,指針變量
-
1.3、const 的使用場景(場景一用的居多)
-
場景一:修飾全局變量,目的是:使外界無法修改變量,保持只讀,提高預編譯的速度和時間(蘋果建議使用 const),如下:
// 設置基礎的url,這樣來保證base_url的不變(封裝請求的類) NSString * const base_url = @"http://www.baodu.com/";
-
場景二:修飾方法中的參數,如下
-(void)constTest2{ [self test:@"你好!"]; int p = 1; [self test1:&p]; [self test2:2]; } // 當一個方法的參數,只讀. -(void)test:(NSString * const)string{ // 這句代碼是報錯的,被 const 修飾過後,string 是無法被修改的 string = @"234"; } // 指針只讀,不能通過指針修改值 - (void)test1:(int const *)a{ // *a = 11; } // 基本數據類型只讀 - (void)test2:(int const)a{ }
-
二、宏 的簡單使用
2.1、基本概念:宏是一種批量處理的稱謂。一般說來,宏是一種規則或模式,或稱語法替換 ,用於說明某一特定輸入(通常是字符串)如何根據預定義的規則轉換成對應的輸出(通常也是字符串)。這種替換在預編譯時進行,稱作宏展開。編譯器會在編譯前掃描代碼,如果遇到我們已經定義好的宏那麼就會進行代碼替換,宏只會在內存中copy一份,然後全局替換,宏一般分爲對象宏和函數宏,推薦博客。
2.2、宏的弊端:如果代碼中大量的使用宏會使預編譯時間變長。
-
2.3、常用宏舉例如下
/** 1、屏幕的寬高 */ #define JK_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width #define JK_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height /** 2、判斷是不是蘋果手機 */ #define JKIs_Iphone (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
-
2.4、const與宏的區別?
答:1.編譯時刻 宏:預編譯 const:編譯;2.編譯檢查 宏沒有編譯檢查,const有編譯檢查;3.宏的好處 定義函數,方法 const不可以;4.宏的壞處 大量使用宏,會導致預編譯時間過長
提示:
- 預編譯:在打開項目的時候上面會有一個加載項目的進度條就是預編譯
- 編譯:command+R和command+B都是編譯
- 網上的誤區:大量使用宏,會導致內存暴增(定義一個字符串的宏,賦值給多個變量,打印其內存地址,經過測試:宏定義的是常量,常量都放在常量區,只會生成一份內存,故網上說的都是不對的),如下圖
三、static 簡單使用
-
3.1、修飾局部變量
-
<1>、被static修飾局部變量,延長生命週期,跟整個應用程序有關,程序結束纔會銷燬,如下:在一個類的裏面打印下面的方法,只要程序不銷燬,
a
的值就不會被銷燬,會一直保持最後一次給a
賦的值-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ static int a = 0; ++a; NSLog(@"a=%d",a); }
-
<2>、被
static
修飾局部變量,只會分配一次內存,如下:從打印結果我們可以看到,a
的內存地址不會再變static int a = 0; ++a; NSLog(@"a = %d a的內存地址=%p",a,&a); 部分打印結果: a = 1 a的內存地址=0x10e758160 a = 2 a的內存地址=0x10e758160 a = 3 a的內存地址=0x10e758160 a = 4 a的內存地址=0x10e758160
提示:被static修飾局部變量什麼時候分配內存?程序一運行就會給static修飾變量分配內存
-
-
3.2、修飾全局變量,被static修飾全局變量,作用域會修改,也就是只能在當前文件下使用
#import "ViewController.h" static int b = 20; @interface ViewController () @end @implementation TestViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor purpleColor];; } @end
四、extern 簡單使用
-
4.1、聲明外部全局變量(只能用於聲明,不能用於定義),舉例如下:我們在類裏面定義的全局變量,在其他的類裏面使用的時候只要聲明一下就好
#import "ViewController.h" int x = 20; @interface ViewController () @end @implementation TestViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor purpleColor];; } @end
在其他類裏面使用一,如下:聲明一下即可
#import "TestViewController.h" @interface TestViewController () @end @implementation TestViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor purpleColor];; } extern int x; -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ NSLog(@"x的值是:%d",x); // 打印結果: x的值是:20 } @end
在其他類裏面使用二,如下:在
ViewController
類的.h
裏面聲明一下即可,如下:#import <UIKit/UIKit.h> @interface ViewController : UIViewController extern int x; @end
4.2、extern工作原理:先會去當前文件下查找有沒有對應全局變量,如果沒有,纔會去其他文件查找
五、static 與 const 聯合使用
5.1、回顧一下 static 與 const
const:修飾全局變量
static:修飾全局變量,修改作用域-
5.2、static 與 const 聯合使用
如果我們想這個BASE_URL
無法被其他類使用,那麼我們就在前面加上static
因爲 static 修飾全局變量,修改作用域,只能在UrlTest
裏面使用,再其他類裏面使用是不可以的,切記:這個BASE_URL
是在.m
裏面定義的#import "UrlTest.h" static NSString * const BASE_URL = @"http://www.baodu.com/"; @implementation UrlTest @end
六、extern 與 const 聯合使用
-
6.1、開發中使用場景:在多個文件中經常使用的同一個字符串常量,可以使用extern與const組合。原因入下:
- static與const組合:在每個文件都需要定義一份靜態全局變量。
- extern與const組合:只需要定義一份全局變量,多個文件共享。
提示:開發中便於管理所有的全局變量,通常搞一個Global文件,裏面專門定義全局變量,統一管理,要不然項目文件太多不好找。
-
6.2、extern的基本使用 :當我們在一個防止一個變量被修改的時候,我們在前面加上
const
,如下,僅僅是BASE_URL
無法被修改,在自己的.h
文件裏面extern
聲明一下即可,在其他類裏面通過 導入.h
文件,還是可以使用的BASE_URL
的-
UrlTest的.h文件 ( 聲明
BASE_URL
)#import "UrlTest.h" // 聲明 BASE_URL extern NSString * const BASE_URL; @implementation UrlTest @end
-
UrlTest的.m文件
#import "UrlTest.h" NSString * const BASE_URL = @"http://www.baodu.com/"; @implementation UrlTest @end
提示:定義全局的東西,遵循規定,頂一個以全局的文件來管理全局變量,以避免全局變量重複定義
-
-
6.3、extern 的高級使用 (模仿
YYKIT
的使用 ),其實它只是把蘋果的宏拿過來改改名字,看起來很牛逼,我們也可以牛逼一下,如下:-
蘋果的定義:
#ifdef __cplusplus #define UIKIT_EXTERN extern "C" __attribute__((visibility ("default"))) #else #define UIKIT_EXTERN extern __attribute__((visibility ("default"))) #endif
-
我們只需要把
UIKIT_EXTERN
改爲JKKIT_EXTERN
,那以後我們就可以使用我們自己定義的#ifdef __cplusplus #define JKKIT_EXTERN extern "C" __attribute__((visibility ("default"))) #else #define JKKIT_EXTERN extern __attribute__((visibility ("default"))) #endif
-
蘋果和我們自己定義的使用如下
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> #ifdef __cplusplus #define JKKIT_EXTERN extern "C" __attribute__((visibility ("default"))) #else #define JKKIT_EXTERN extern __attribute__((visibility ("default"))) #endif // 使用自己定義的 JKKIT_EXTERN NSString * const BASE_URL; // 使用蘋果定義的 UIKIT_EXTERN // UIKIT_EXTERN NSString * const BASE_URL; NS_ASSUME_NONNULL_BEGIN @interface UrlTest : NSObject @end NS_ASSUME_NONNULL_END
-