在iOS开发中经常遇到一些字段和类型的定义,例如配置生产和测试不同环境的参数等,这时候经常用到#define、const以及typedef。那么它们之间有什么区别呢?我们接下来一个一个具体了解下。

一、基本概念

1.1、#define

  #define并不是定义全局变量,而是宏定义。也就是说并不是真正意义上的定义变量,而是用来做文本替换。当程序开始运行时,编译器会先将代码中的MAX全部替换为100,然后再进行编译。由此可得,#define并不是在编译过程中进行,而是在预编译阶段进行。

#define MAX 100 

  宏的常见用法:

  • 常见的字符串抽成宏:比喻定义的常用颜色、字体字号等

    #define kWaterAlpha 0.04f  //水印的透明度
    
    #define kFlowRowSize 30  //流程每次拉去的数量
    
    #define ROW_SIZE 20  //一般刷新每次拉去的数量
  • 常见代码抽成宏:比喻单例模板等
    //宏定义常用的颜色
    #define XRGB(r,g,b) [UIColor colorWithRed:(0x##r)/255.0 green:(0x##g)/255.0 blue:(0x##b)/255.0 alpha:1]
    #define kBgColor XRGB(f4, f4, f4)
    #define kBlackFontColor XRGB(33, 33, 33)
    #define kGrayFontColor XRGB(99, 99, 99)
    #define kBlueFontColor XRGB(3d,9a,e8) //宏定义获取当前主界面rootViewController
    #define RootVC [UIApplication sharedApplication].delegate.window.rootViewController //宏定义获取当前的界面
    #define TopVC ([RootVC isKindOfClass:[UITabBarController class]]?[((UITabBarController *)RootVC).selectedViewController topViewController]:RootVC) //宏定义单例的定义和实现
    #define DECLARE_DEFAULT +(instancetype)defaultInstance; #define IMPLEMENT_DEFAULT(C) +(instancetype)defaultInstance{\
    static dispatch_once_t onceToken;\
    static C *_gInstance;\
    dispatch_once(&onceToken, ^{\
    _gInstance = [C new];\
    });\
    return _gInstance;\
    }

  关于#define的其他用法可以参见后面这篇博文:iOS开发中你真的会用#define么!!!?

1.2、const

  关键字const用来定义常量,如果一个常量被const修饰,那么他的值就不能被改变。编译器通常不为普通const常量分配存储空间,而是保存于符号表中,这使得它成为一个编译期间的常量,没有存储与读内存的操作,使得它的效率更高。

  常见用法如下:

//全局变量,constString1地址不能修改,constString1值能修改
const NSString *constString1 = @"I am a const NSString * string";
//意义同上,无区别
NSString const *constString2 = @"I am a NSString const * string";
// stringConst 地址能修改,stringConst值不能修改
NSString * const stringConst = @"I am a NSString * const string";
  • constString1 跟constString2 无区别
  • 左边代表指针本身的类型信息,const表示这个指针指向的这个地址是不可变的
  • 右边代表指针指向变量的可变性,即指针存储的地址指向的内存单元所存储的变量的可变性

1.3、typedef

  typedef常用于给类型起别名(给已知的类型起别名)。常用于简化复杂类型,变量类型意义化等。typedef是类型替换,语句的一种,结尾必须有;。

//iOS底层源码就是对NSInteger进行了一个别名的设置,其表示的就是long或者int类型。
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif

  

  在iOS开发中最常用到的应该就是使用typedef定义枚举和block了,此外还可以用typedef定义函数。关于typedef定义枚举官方API是这样说的

/* NS_ENUM supports the use of one or two arguments. The first argument is always the integer type used for the values of the enum. The second argument is an optional type name for the macro. When specifying a type name, you must precede the macro with 'typedef' like so:
NS_ENUM支持单个或两个参数,第一个参数一般是NSInteger类型来制定枚举的值类型,第二个参数是可选的枚举类型的别名,如果要定义别名,必须使用typedef进行定义,具体格式如下: typedef NS_ENUM(NSInteger, NSComparisonResult) {
...
}; If you do not specify a type name, do not use 'typedef'. For example:
如果不需要使用特定的名称,则不需要使用typedef NS_ENUM(NSInteger) {
...
};
*/

  typedef的常见用法如下:

typedef double NSTimeInterval;  //给double取别名为NSTimeInterval(变量类型意义化)
typedef NSTimeInterval MyTime; //给NSTimeInterval取别名为MyTime
typedef char * MyString; //给char *取别名为MyString //c语言格式,给Person结构体取别名为MyPerson。使用:MyPerson p = {"jack"};
typedef struct Person {
char *name
}MyPerson; //c语言格式,给Gender枚举取别名为MyGender。使用:MyGender g = Man;
typedef enum Gender {
Man,
Woman
}MyGender; //OC语言格式,给Gender枚举取别名为MyGender。使用:MyGender g = Man;
typedef NS_ENUM(NSInteger, Gender) {
Man,
Woman
}; //给block取别名MyBlock
typedef void(^MyBlock) (int a,int b); //给指向函数的指针取别名MyFunction
typedef int(*MyFunction) (int a,int b);

  typedef定义函数的示例:

int add (int a, int b){
return a + b;
} typedef int(*MyMethod) (int a,int b); int main(){
MyMethod m = add;
m(,); //调用函数
return ;
}

二、区别

2.1 #define与const

  • 宏在预编译时处理(宏在编译开始之前就会被替换);而const会在编译时被处理
  • #define宏没有类型,宏不做任何类型检查,不会报编译错误,只是替换;而const常量有具体的类型,会编译检查,会报编译错误
  • 宏能定义一些函数,方法;const不能
  • 使用大量宏,容易造成编译时间久,每次都需要重新替换
  • 宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存。);而const常量会在内存中分配(可以是堆中也可以是栈中),const 可以节省空间,避免不必要的内存分配
const
#define PI 3.14159 //常量宏 const doulbe Pi=3.14159; //此时并未将Pi放入ROM中
double I=PI; //预编译期间进行宏替换,分配内存 double i=Pi; //此时为Pi分配内存,以后不再分配!
double J=PI; //再进行宏替换,又一次分配内存 double j=Pi; //没有内存分配
  • const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝(因为是全局的只读变量,存在静态区),而 #define定义的常量在内存中有若干个拷贝。
  • 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。

2.2 typedef和#define

  • define是文本替换,属于预编译指令,本身不参与编译,除非希望替换的文本中有;否则不用加。
    typedef是类型替换,语句的一种,结尾必须有;
  • define写在方法/函数中则作用域从写的地方开始有效,直至使用#undef(不写此指令则后面一直有效)。typedef写在方法/函数中则作用域 只在此方法/函数中有效。
  • 若使用 typedef char * MyString; 则 MyString s1,s2等价于 char *s1; char *s2;
    若使用  #define MyString char * 则 MyString s1,s2等价于 char *s1,s2即 char *s1; char s2
    再次说明了typedef是类型替换,直接参与编译,而define只是简单的文本替换。

iOS学习——#define、const、typedef的区别的更多相关文章

  1. C++ —— 非类中使用const定义常量的初始化,以及#define和typedef的区别

    总结一下在非类中使用const关键字定义常量时的初始化问题,亲测VS2015.顺便记录#define宏和typedef的区别. 1 首先对const声明的常量的初始化做简单小结: , w2 = , w ...

  2. 【C语言笔记】#define与typedef的区别

    1.#define define是预处理指令,在编译时不进行任何检查,只进行简单的替换 宏定义的一般形式为: #define 宏名 字符串 这里所说的字符串是一般意义上的字符序列,不要和C语言中的字符 ...

  3. define和typedef的区别

    define和typedef的区别 define是单纯的字符替换,typedef是重新定义了新的类型 #include <stdio.h> #define CHAR1 char* type ...

  4. #define const typedef

    #define用法 1. 定义简单的常数:定义常量,便于修改 #define N 1000 2. 定义简单的函数:注意多使用括号 define可以像函数那样接受一些参数,如下: #define max ...

  5. #define\const\inline的区别与联系

    总结: const用于代替#define一个固定的值,inline用于代替#define一个函数.是#define的升级版,为了消除#define的缺陷. 参考内容:http://www.cnblog ...

  6. #define 和typedef的区别

    typedef和define的详细区别 2011-04-19 15:11 firnow firnow 字号:T | T 对于都可以用来给对象取一个别名的Typedef和define来说,是有区别的.本 ...

  7. 宏定义#define和typedef的区别和典型范例题目辨析

    宏定义#define pStr char*  ,是直接把程序中出现pStr的地方替换成char* ,直接替换: typedef  char * pStr; 是给char*定义一个别名叫做 pStr; ...

  8. define与typedef的区别

    define: 发生在预处理阶段,也就是编译之前,仅仅文本替换,不做任何的类型检查 没有作用域的限制 typedef: 多用于简化复杂的类型声明,比如函数指针声明:typedef bool (*fun ...

  9. iOS学习笔记之typedef

    typedef unsigned long long weiboId; typedef 定义一个使用方便的类型,谓之为“宏定义“. unsigned long long 是一种无符号的长长整型.本应该 ...

随机推荐

  1. Macro For Creating a dwStyle for a window without a menu bar and title bar

    Introduce For CreateWindowEx Creates an overlapped, pop-up, or child window with an extended window ...

  2. EFCore+Mysql仓储层建设(分页、多字段排序、部分字段更新)

    前沿 园子里已有挺多博文介绍了EFCore+Mysql/MSSql如何进行使用,但实际开发不会把EF层放在Web层混合起来,需要多个项目配合结构清晰的进行分层工作,本文根据个人实践经验总结将各个项目进 ...

  3. STL 贺习笔记

    贺文链接www.cnblogs.com/zhouzhendong/p/STL.html C++ STL 的一些基础用法 前言 ​ 创建一个空的 vector ,我一直是这样写的: vector < ...

  4. springboot+freemarker毕业设计项目错误合集

    1.springboot的主程序类必须在最外层. 换句话说,报错: This application has no explicit mapping for /error, so you are se ...

  5. 031 一次全面的java复习

    一:相关概念 1.面向对象的三个特征 封装,继承,多态,这个应该是人人皆知,有时候也会加上抽象. 2.多态的好处 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性.简单的说 ...

  6. 微信小程序支付遇到的坑

    1,微信公众号支付和微信小程序支付有差异 微信公众号:可以直接跳转走h5的微信支付 微信小程序:在测试环境.沙箱环境使用微信公众号的跳转支付没有问题,在线上存在支付异常 最后商讨的解决方法 openi ...

  7. docker报错Service 'pwn_deploy_chroot' failed to build: Get https://registry-1.docker.io/v2/library/ubuntu/manifests/16.04:net/http: request canceled

    这几天碰到师傅让我帮忙做pwn题环境,结果遇到了坑 第一种方法是:https://blog.csdn.net/zhaoyayua/article/details/60141660 解决办法是执行 vi ...

  8. C#事件委托概念

    事件就是一个狭义的委托,也就是事件是一个用于事件驱动模型的专用委托. 通俗的讲,委托你可以在客户代码中直接调用委托来激发委托指向的函数,而事件不可以,事件的触发只能由服务代码自己触发 也就是说在你的代 ...

  9. Unity Shader Graph 小功能实现(一)边缘发光

    在Unity 2018.2 版本正式启用了高清渲染管线,shader可视化编程. 现在我们就尝尝鲜,来实现了个物体边缘发光的shader效果. 准备 点击Windos->Package Mang ...

  10. 第六章 对象-javaScript权威指南第六版(三)

    6.3 删除内容 delete运算符可以删除对象的属性. delete运算符只能删除自有属性,不能删除继承属性. delete表达式删除成功或没有任何副作用时,它返回true. 6.4 检测属性 用i ...