優(dan)美(teng)的前奏
宏定義這個東東,估計大家在代碼中應該天天用吧。
在我剛剛做的一個項目中,各種往代碼裏碼“#define”這種預處理指令。
什麼動畫時長啊,cell高度啊,cell的個數啊,balabala,看得我這個心煩。
拿一個例子來講:
A程序猿定義了一個UITableViewCell的高度爲45。
#define HEIGHT_TABLEVIEWCELL 45;
B程序猿也定義了一個UITableViewCell的高度爲50。
#define HEIGHT_TABLEVIEWCELL 50;
然後B在他寫的.m文件中引用了A的文件,然後...然後...就沒有然後了。
總結一句話就是,TMD,太亂了。
經過查找資料,發現確實有人提出過問題,並且提出了“少用#define”的建議。
(很明顯沒有多少人遵循這一建議,大家還在開心的#define)
提出這一觀點的論據主要有以下兩點:
- 就是像我剛纔舉的例子一樣,如果B引用了A的文件,並且A、B兩人的文件中的預定義指令的名字相同,那麼就會產生衝突,結果就是A中的預定義指令把B中的預定義指令代替了。
- 沒有類型定義,就像#define HEIGHT_TABLEVIEWCELL 45;這句代碼中,我們只能從後邊的45來推測是int類型或者float類型。但是具體是哪一種,代碼中並不能體現出來。
所以基於以上兩點,我們應該儘量少的使用#define這種預定義指令。
那不使用#define,我們使啥捏?
這個問題問滴有水平!^^!
那就分爲兩種情況跟大家聊聊:
在一個“編譯單元”中使用
在Objective-C的語境下,“編譯單元”一詞通常指每個類的實現文件(以.m爲後綴名)。
也就是說,我們只在當前這一個.m文件中使用。
簡單使用
這種情況我們就可以使用static和const來修飾變量,例如 static const NSString *kClassName = @"DemoClass";
- static 能夠限制當前變量只能在此編譯單元中使用。
- const 能夠限制當前變量只要被定義之後就不能被修改。
參考以下代碼:
// DemoViewController.h
#import <UIKit/UIKit.h>
@interface DemoViewController : UIViewController
@end
// DemoViewController.m
#import "DemoViewController.h"
static const NSString *kClassName = @"DemoViewController";
@implementation DemoViewController
@end
命名規則
根據蘋果官方代碼我們可以發現,定義“編譯單元”內的常量都是以"k",作爲前綴。
在多個“編譯單元”中使用
簡單使用
若要在多個“編譯單元”中使用,此類常量需放在“全局符號表”(global symbol table)中,以便可以在定義該常量的編譯單元之外使用。
步驟稍微複雜一下,但是比把大象裝冰箱要簡單一點:
- 在.h文件中,使用extern、const關鍵字對變量進行聲明。
- 在.m文件中,對.h文件中聲明的變量進行定義。
參考以下代碼:
// DemoViewController.h
#import <Foundation/Foundation.h>
extern NSString *const DemoViewControllerClassName;
@interface DemoViewController : UIViewController
@end
// DemoViewController.m
#import "DemoViewController.h"
NSString *const DemoViewControllerClassName =
@"DemoViewController";
@implementation DemoViewController
@end
注意const關鍵字的位置。
命名規則
爲避免名稱衝突,最好是用與之相關的類名做前綴。
系統框架中一般都這樣做。例如UIKit就按照這種方式來聲明用作通知名稱的全局常量。
其中有類似UIApplicationDidEnterBackgroundNotification與UIApplicationWillEnterForegroundNotification這樣的常量名。
總之,經過這個項目蛋疼的經歷,大家還是在項目中儘量少的使用預定義指令。
另外附上咱家的微信公衆號的二維碼,沒事兒可以掃掃哈。
有啥事兒大家可以隨時留言交流。