static、const、extern的正确使用方式

窥探iOS底层实现--OC对象的本质(一) - 掘金objective-c

窥探iOS底层实现--OC对象的本质(二) - 掘金swift

窥探iOS底层实现--OC对象的分类:instance、class、meta-calss对象的isa和superclass - 掘金安全

窥探iOS底层实现-- KVO/KVC的本质 - 掘金函数

1.extern

全局变量extern,也称之为外部变量,是在方法外部定义的变量。它不属于那个方法,而是属于整个源程序。做用因而整个程序。若是全局变量和局部变量重名,则在局部变量做用域内,全局变量被屏蔽,不起做用post

///> DDExtern.h
    
    #import <Foundation/Foundation.h>
    NSString *flag = @"DDExtension";
    @interface DDExtern : NSObject
    @end
复制代码

定义了一个字符串 flagui

///> main.m 

#import <Foundation/Foundation.h> 
int main(int argc, const char \* argv\[\]) { 
    extern NSString *flag; 
    NSLog(@"%@",flag); 
    return 0; 
}
复制代码
打印结果:DDExtension
复制代码

从例子中能够看出,main.m无需导入JJExtern的头文件,直接在NSString *flag前面加上extern关键字就能够取到JJExtern的flag值。 须要注意的是,extern修饰的变量名必须是和Extern下的变量名一致,即都为flag,不然会都提示找不到。 还须要注意extern修饰的变量是没有真的内存的。spa

  • 总结:

    • 想要访问全局变量,能够在变量前加一个extern
    • extern修饰的变量没有真正的内存

问题:

既然只须要extern就能获得并修改其余文件的变量,这样不是很不安全?由于随时都会被人改掉,怎么办??3d

答案:

使用接下来所讲的 static关键字修饰变量,那么该变量就只能在本文件中修改,其余文件没法使用extern获取变量指针

2.static

static 既能够修饰全局变量,又能够修饰局部变量。code

  • 修饰全局变量

    使用以前的例子,在JJExtern的 NSString *flag = @"JJExtension"; 前面加 static,以下

    ///> JJExtern.h
    
      #import <Foundation/Foundation.h>
      static NSString *flag = @"DDExtension";
      @interface JJExtern : NSObject
      @end
    复制代码

    再次运行main函数 编译会报错

    note_staticAbout_01.png
    因此只要在全局变量前加static,那么这个全局变量的做用域就会缩小到当前文件,外界就不能访问了

    • 总结:

      • static修饰全局变量,保证全局变量安全,外界不能够访问与修改,做用域仅限于当前文件。
  • 修饰局部变量:

代码:

///> main.m
void test() {
    static int a = 0; 
    a++; 
    NSLog(@"a = %d", a); 
} 
int main(int argc, const char \* argv\[\]) { 
    @autoreleasepool { 
      for (int i = 0; i<3; i++) { 
          test(); 
      }
    } 
    return 0;
}

/** 输出结果: * 2018-12-05 19:20:55.494405+0800 tesy[11959:2261816] a = 1 * 2018-12-05 19:20:55.499893+0800 tesy[11959:2261816] a = 2 * 2018-12-05 19:20:55.505727+0800 tesy[11959:2261816] a = 3 */

复制代码

修饰局部变量时,做用域仅限于test函数的大括号内,其余地方都不可使用。test这个函数中若是不添加 static,那么a打印出来永远都是1,由于在运行完此段函数 局部变量a就会被释放。从新执行函数时a++为0+1.

加上static以后的含义就改变了,结果为1,2,3。由于被static修饰的变量只会初始化一次,永远都只有一分内存,因此当第一次调用test函数时a就已经被初始化了,a有一个内存空间而且值为0,第二次调用test函数因为a被static修饰,因此不会再初始化新的值,它会拿到以前的那分内存进行a++操做,就会变成1,以此类推。

  • 总结:

    • 让局部变量只初始化一次
    • 局部变量在内存中只有一分内存
    • 直到程序结束才会被销毁

3. const

const的做用和宏相似,苹果不推荐使用宏定义,推荐使用const,因此在swift中苹果抛弃了宏的使用。

  • const 和 宏的区别

    \ const
    编译时刻 预编译(在编译前处理) 编译阶段
    编译检查 不作检查,不会报编译错误,单纯替换功能,用宏定义的函数会报参数类型错误 会作编译检查,会报编译错误
    宏的好处 宏能定义一些函数、方法 例如RGB函数 不能
    宏的坏处 使用大量的宏,容易形成编译时间久每次都须要从新替换 1.0.2 -> 1.0.4
    • 使用过多的宏会消耗大量编译时间。 const的做用就是使右边的变量,只可读,不可修改

三段代码理解const

int x = 1; 

int y = 2; 

const int *px = &x; // 让指针px指向变量x(此时const右边是*p) 

px = &y;// 改变指针px的指向,使其指向变量y 

*px = 3; // 改变px指向的变量x的值,出错:Read-only variable is not assignable

复制代码
int x = 1; 

int y = 2;

const int *px = &x; // 让指针px指向变量x(此时const右边是*p)

px = &y; // 改变指针px的指向,使其指向变量y 

*px = 3; // 改变px指向的变量x的值,出错:Read-only variable is not assignable

复制代码
int x = 1; 

int y = 2; 

const int *px = &x;// 让指针px指向变量x(此时const右边是*p) 

px = &y; // 改变指针px的指向,使其指向变量y 

*px = 3; // 改变px指向的变量x的值,出错:Read-only variable is not assignable

复制代码

上面的三段代码处理的是基本数据类型,咱们知道OC语言是C语言的超集,因此上面部分基本数据类型的处理OC与C同样。 可是咱们知道OC是C语言的超集,OC中还有NSString等的数据类型,它们的本质是个结构体,因此在处理指针方面与基本数据类型不一样

代码以下:

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {   

    NSString const *name = @"milo";// const修饰*name 
    NSLog(@"%@",name);// 打印结果“milo” 
    
    name = @"vicky";// 在oc中NSString等类的值不是经过*name访问的,而是经过name访问的,这就是和c语言的指针的区别,但仍是遵循const右边是谁,谁就只可读的原则。
    NSLog(@"%@",name);// 打印结果“vicky” 
}

复制代码

objective-c语言代码

- (void)viewDidLoad {
  [super viewDidLoad]; 
  // 定义变量 
  int a = 1; 
  // 容许修改值 
  a = 20;
  // const两种用法 
  // const:修饰基本变量p
  // 这两种写法是同样的,const只修饰右边的基本变量b 
  const int b = 20; // b:只读变量 
  int const b = 20; // b:只读变量 
  b = 1; // 不容许修改值 
  
  
  // const:修饰指针变量\*p,带\*的变量,就是指针变量. 
  // 定义一个指向int类型的指针变量,指向a的地址 
  int *p = &a; 
  int c = 10; 
  p = &c; 
  // 容许修改p指向的地址,
  // 容许修改p访问内存空间的值 
  *p = 20;
  
  
  // const修饰指针变量访问的内存空间,修饰的是右边*p1, 
  // 两种方式同样 
  const int *p1; // *p1:常量 p1:变量 
  int const *p1; // *p1:常量 p1:变量 
  
  // const修饰指针变量p1 
  int * const p1; // *p1:变量 p1:常量
  
  
  // 第一个const修饰*p1 第二个const修饰 p1 
  // 两种方式同样 
  const int * const p1; // *p1:常量 p1:常量
  int const * const p1; // *p1:常量 p1:常量 
}
复制代码
  • 总结:

    • const仅仅用来修饰右边的变量(基本数据变量px 指针变量*px)
    • 被const修饰的变量是只读的

4. static、const结合使用

  • static与const做用:声明一个只读的静态变量
  • 开发使用场景:在一个文件中常用的字符串常量,可使用static与const组合
///> 开发中经常使用static修饰全局变量,只改变做用域
    
///> 为何要改变全局变量做用域,防止重复声明全局变量。
    
///> 开发中声明的全局变量,有些不但愿外界改动,只容许读取。
    
///> 好比一个基本数据类型不但愿别人改动
    
///> 声明一个静态的全局只读常量
static const int a = 20;

///> staic和const联合的做用:声明一个静态的全局只读常量
    
///> iOS中staic和const经常使用使用场景,是用来代替宏,把一个常用的字符串常量,定义成静态全局只读变量.

///> 开发中常常拿到key修改值,所以用const修饰key,表示key只读,不容许修改。
static  NSString * const key = @"name";
    
///> 若是 const修饰 *key1,表示*key1只读,key1仍是能改变。 
static  NSString const *key1 = @"name";
复制代码

5. extern与const联合使用

  • 开发中使用场景:在多个文件中常用的同一个字符串常量,可使用extern与const组合。
  • 缘由:
    • static与const组合:在每一个文件都须要定义一份静态全局变量。
    • extern与const组合:只须要定义一份全局变量,多个文件共享。
  • 全局常量正规写法:开发中便于管理全部的全局变量,一般搞一个GlobeConst文件,里面专门定义全局变量,统一管理,要否则项目文件多很差找。
///> In the header file

extern NSString *const EOCStringConstant;



///> In the implementation file
NSString *const EOCStringConstant = @"VALUE";

复制代码
相关文章
相关标签/搜索