关键字const/static/extern/typedef/typeof/define的释义和用法

1、const(常量---readonly)

作用:
  • 用于修饰 右边 的基本变量或指针变量;
  • 被修饰的变量只读,不能被修改(readonly);
定义的意义:

(1.) 常用使用方式:

  • 常用单独使用形式有三种:(但是一般会和其他关键字联合使用)
const NSString * name = @"jack";
NSString const * sax = @"boy";
NSString * const age = @"24";

这样定义的均为全局常量:不管你定义在那个文件夹(单独定义现在只能存在于.m文件中,见:用法举例->PS),在外部的任意文件中都可以访问到。

  • 和其他关键字结合使用的形式一般有两种:
extern const NSString * name; // 仅做声明使用,一般存在与.h文件中
static const NSString * name = @"jack"; // 使全局常量变为局部变量,具体使用后面会介绍🙃

(2.)const究竟做了什么?
在介绍const时着重强调了“右边”二字,这是有原因的O(∩_∩)O~
在使用时我们发现const 修饰时 位置是不一样的,不同位置分别代表了什么含义呢?

const NSString * name = @"jack";
// *name 不能修改  name 可以修改  ---> *name 是指向指针的指针~
NSString const * sax = @"boy";
// 与上面一样(这就是为什么强调“右边”二字了)
NSString * const age = @"24";
// *name 能修改  name 不可以修改  --->所以我们想定义一个不想被修改的常量应该这样

我们可以用指针变量来验证一下:


1-1-验证
用法举例:

访问的方式一般有两种:
(1.)在.m文件中定义,在其他文件中获取其声明,然后使用;


1-1-定义
1-1-使用

(2.)另一种使用时需要先在.h中声明,然后.m中赋值,当要使用该常量时需要导入定义该常量的头文件,然后直接使用即可。

1-1-声明
1-1-定义
1-1-使用

PS:现在不能直接在.h文件中定义常量了,会发生循环引用问题。具体见http://www.jianshu.com/p/94ca52399ade该篇文章的第十五小标题,所以现在常用方法是单独创建一个专门存放常量的文件,使用第二种方法定义常量,然后在pch文件中导入该文件的头文件。

2、static (静态的)

作用:修饰不同的变量作用不尽相同。

(1.)修饰全局变量:

static NSString * name_boy = @"Bob";
// 下面是与const结合使用的情况
static const NSString * name = @"jack";
static NSString const * sax = @"boy";
static NSString * const age = @"24";

这又分为两种:

---》在.h中修饰全局变量:

现在直接在.h文件中定义全局变量或者const修饰的全局变量运行时会直接报_x86的错误,但是可以使用static 修饰,即可在.h文件中定义,然后在其他文件中可以直接使用!

2-1-定义
2-1-使用
---》在.m中修饰全局变量:

改变全局变量的作用域,使全局变量的作用域仅限于当前文件内部(.m内部),即当前文件内部才能访问该全局变量。同时这样能够避免重复定义全局变量!常见的使用情况:单例中。

若将上图(2-1-定义)中static const NSString * name = @"jack";放到.m文件中则在AppDelegate.m中则访问不到name.

2-1-验证

(2.)修饰局部变量:
---》改变局部变量的生命周期(只到程序结束,这个局部变量才会销毁)不会改变局部变量的作用域;
---》让局部变量只初始化一次,局部变量在程序中只有一份内存

下面有一组对比来说明修饰局部变量后的变化:

正常情况下,未被static修饰的局部变量
使用static修饰的局部变量

可以看到,经过static修饰后,在for循环内部workDays只被初始化了一次。

与const结合使用:

一般是在.m文件中定义经常使用的字符串常量,或者数值常量时使用。static将一个全局变量变成局部变量,然后const将一个局部变量变成局部常量

e.g : MBProgressHUD.m中


3、extern(外部的,外部变量)

作用:
  • 用来声明全局变量;
  • 只是用来获取全局变量(包括全局静态变量)的值,不能用于定义变量;
用法:
  • 在.h中修饰声明全局变量,然后在.m中定义该全局变量,则在其他文件中可以直接使用该变量!
3-1-声明
3-2-定义
3-3-使用
  • 获取全局变量的值(具体用法参考本篇文章中const篇幅中 -> 用法举例 中的(1.);
与const结合使用:

即,在.h中声明一个const修饰的全局变量,让后再在.m中实现其定义。(这样逼格看起来要高一些,其实就是定义了一个全局变量~

在这里还有一些关键字UIKIT_EXTERN、OBJC_EXTERN、FOUNDATION_EXTERN、FOUNDATION_EXPORT、FOUNDATION_IMPORT,这些均为经过处理的extern.

  • UIKIT_EXTERN:将函数/变量修饰为兼容以C编译方式的、具有extern属性的属性。
  • OBJC_EXTERN:与UIKIT_EXTERN差不多,但是比其更加宽泛一些。
  • FOUNDATION_EXTERN:看其定义是与OBJC_EXTERN一毛一样的······
  • FOUNDATION_EXPORT/FOUNDATION_IMPORT:用来兼容win32应用程序,同时也是为了兼容C++语言的~~(不明觉厉😜)

若是使用以上字段是不是看起来逼格又高了一点~~,不过通常使用最多的也就是 UIKIT_EXTERN了。

4、typedef(定义类型)

作用:定义类型的别名。

(1.)定义枚举:

typedef NS_ENUM(NSInteger, UITableViewStyle) {
    UITableViewStylePlain,          
    UITableViewStyleGrouped      
};

typedef NS_OPTIONS(NSUInteger, UISwipeGestureRecognizerDirection) {
    UISwipeGestureRecognizerDirectionRight = 1 << 0,
    UISwipeGestureRecognizerDirectionLeft  = 1 << 1,
    UISwipeGestureRecognizerDirectionUp    = 1 << 2,
    UISwipeGestureRecognizerDirectionDown  = 1 << 3
};
//凡是需要以按位或操作来组合的枚举都应使用NS_OPTIONS定义。若是枚举不需要互相组合,则应使用NS_ENUM来定义

(2.)定义block:

typedef void (^JRNetWorkSuccessBlock)(id responseObject, MBProgressHUD * hud);

(3.)添加别名:

typedef NSString Str;
// 这样再定义string类型时,也可以直接使 Str
// e.g  @property (copy, nonatomic) Str * name;

5、typeof(变量名,类型)

作用:静态获取参数类型。

最常见就是自定义block中防止循环引用:

__weak typeof(self)weakSelf = self;
self.channelHeaderView.addAction = ^{
   [[UIApplication sharedApplication].keyWindow addSubview:weakSelf.channelView];
};

6、define(定义)

作用:主要是用于定义宏

关于宏定义可以看一下我的这篇文章 《iOS预编译指令详解》。对于经常使用的一些常量最好使用const而不是定义成宏。

推荐阅读更多精彩内容