内容简介:全局常量作为开发人员一定是一个比较熟悉的概念。全局常量的写法自然也比较多,最近在进行项目的常量重构时看到了各种各样的写法,其中所以在定义全局常量时,为了提高开发过程中的规范度和编译速度,宏定义并不是最佳选择。所以我重构的原则是:
写在前面
全局常量作为开发人员一定是一个比较熟悉的概念。全局常量的写法自然也比较多,最近在进行项目的常量重构时看到了各种各样的写法,其中 宏定义 占大部分,然而有很多使用宏定义是不规范的,而且宏定义只是在 预编译 阶段进行文本替换,不进行类型检查,从网上看到大量使用宏定义会拖慢编译速度。
所以在定义全局常量时,为了提高开发过程中的规范度和编译速度,宏定义并不是最佳选择。所以我重构的原则是:
能声明成外部常量的,尽量声明成外部常量,万不得已的才使用宏定义。
一、宏
计算机科学里的宏(Macro),是一种批量处理的称谓。一般说来,宏是一种规则或模式,或称语法替换 ,用于说明某一特定输入(通常是字符串)如何根据预定义的规则转换成对应的输出(通常也是字符串)。这种替换在预编译时进行,称作宏展开。
在我刚刚接触开发的时候,我学习到的定义全局常量的方法就是宏。由于宏只是做字符串的替换,它还是有它的优势的。我们可以使用它来一些 常量 、 函数 。
例子:
1、定义屏幕相关的常量。
/屏幕宽高,frame,bounds,size #define kBKScreenWidth [[UIScreen mainScreen] bounds].size.width #define kBKScreenHeight [[UIScreen mainScreen] bounds].size.height #define kBKScreenBounds [UIScreen mainScreen].bounds #define kBKScale [[UIScreen mainScreen] scale]
2、定义调试的log输出函数。
#pragma mark - DEBUG #ifdef DEBUG // 定义是输出Log #define DLog(format, ...) NSLog(@"Line[%d] %s " format, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__) #else // 定义是输出Log #define DLog(format, ...) #endif
从上面的示例可以看出宏定义的关键字是 #define
.
宏定义常量的公式:
#define constantA statementA
预编译的时候使用 constantA 部分的内容替换成 statementA 。
对于函数的定义则稍微复杂一些,有参数和无参数。无参数的函数是直接进行字符串的替换,有参数的还要进行参数的替换。
二、extern
使用 extern 关键字声明全局常量,这个应该算是最标准的做法了。这个是后面在网上的帖子中有看到,当然开源代码中也看到过,确定无疑是定义全局常量的最佳选择。
extern定义全局常量分为声明部分和赋值部分,分别放在 .h & .m 文件中。
代码示例:
- UserInfoModelConstants.h
extern NSString *const BKUSER_AGE_KEY ; extern NSString *const BKUSER_TELPHONE_KEY ; extern NSString *const BKUSER_ADDRESS_KEY ; extern NSString *const BKUSER_BRIEF_KEY ;
- UserInfoModelConstants.m
NSString *const BKUSER_AGE_KEY = @"XXXXX.userAge"; NSString *const BKUSER_TELPHONE_KEY = @"XXXXX.telphoneNO"; NSString *const BKUSER_ADDRESS_KEY = @"XXXXX.address"; NSString *const BKUSER_BRIEF_KEY = @"XXXXX.brief";
特别提示:
对于switch-case表达式中的常量推荐使用 枚举 或者 宏定义 。
三、UIKIT_EXTERN
对于 UIKIT_EXTERN 用法和 extern 完全一样。把extern替换成UIKIT_EXTERN即可。
下方是 UIKIT_EXTERN 的系统宏定义。
#ifdef __cplusplus #define UIKIT_EXTERN extern "C" __attribute__((visibility ("default"))) #else #define UIKIT_EXTERN extern __attribute__((visibility ("default"))) #endif
UIKIT_EXTERN,是经过处理的extern。
简单来说:就是将函数修饰为兼容以往C编译方式的、具有extern属性(文件外可见性)、public修饰的方法或变量库外仍可见的属性。
四、FOUNDATION_EXTERN
下方是 FOUNDATION_EXPORT 的宏定义,内部使用的就是 extern ,只不过多做了 C++ 的兼容。用法和extern也是一样的。
#if defined(__cplusplus) #define FOUNDATION_EXTERN extern "C" #else #define FOUNDATION_EXTERN extern #endif
五、FOUNDATION_EXPORT
FOUNDATION_EXPORT的宏定义如下:
#ifdef __OBJC__ #import <UIKit/UIKit.h> #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif
用法也和extern类似,不过这种方式见到的比较少,可以忽略。
六、static
static也可以声明全局常量,static 声明全局常量的方法相比上面的几种更简单一些。
示例代码:
static NSString *const makeCrashAlertTitle = @"制造一个 Crash ?"; static NSString *const fixCrashAlertTitle = @"提示"; static NSString *const fixCrashButtonTitle = @"修复"; static NSString *const cancelButtonTitle = @"取消"; static NSString *const createCrashButtonTitle = @"制造Crash!"; static NSString *const mainStoryboardInfoKey = @"UIMainStoryboardFile";
static声明常量的方式,一般用于少量的局部常量。
外部常量、宏、static声明的常量的区别。
方式 | #define | extern | static |
---|---|---|---|
原理 | 字符串替换 | 声明常量 | 声明常量 |
作用域 | 可以全局访问 | 可以全局访问 | 局部的、或者只有声明文件本身可以访问 |
是否开辟内存 | 不开辟 | 开辟 | 开辟 |
是否进行编译检查 | 否 | 是 | 是 |
七、总结
对于常量的声明一共有6种方式,那么我们应该怎么使用呢?
以下仅代表个人看法,不喜勿评!!!
- 能使用extern/UIKIT_EXTERN/FOUNDATION_EXTERN定义成外部常量的,尽量使用extern/UIKIT_EXTERN/FOUNDATION_EXTERN定义成外部常量。
- 不兼容 C++ 情况下,直接使用extern声明即可。
- #define一般主要用于定义一些函数,和extern替代不了的常量。
- 必须兼容C++的情况下,UIKIT_EXTERN/FOUNDATION_EXTERN这两种如何使用区分呢,从别的文章上看到的说明大概意思是这样的:你声明的变量如果是UIKIT框架中定义的,就使用
UIKIT_EXTERN
代替extern兼容C++;如果是声明的变量是FOUNDATION框架中定义的,就使用FOUNDATION_EXTERN
代替extern兼容C++。 - 至于 static 主要用于定义局部常量。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。