最近看了一篇blog:http://www.jianshu.com/p/2fd58ed2cf55 主要讲的就是这三个关键字的使用(以前自己从不用这几个关键字,是不是很low?),博主写的很好,在此致敬。但是我发现我对其中的extern、static理解不了,于是,自己爬网,总结了一下。希望对大家有帮助。
extern
extern(只能用来修饰全局变量)是一个大家很常见的东西,很多的第三方中都会出现这个关键字,以前只知道大概是跨文件引用的,其余的就基本不知道。废话少说,进入正题。对于extern我主要从三个方面来讲解。
1. 与.h文件的关系
2. extern引用变量
3. extern声明
1.与.h文件的关系
.h的用法:想必大家都很了解了,是为了更好的方便其他文件(类)去调用本文件中的变量、属性和方法。而extern也是为了实现变量和函数的跨文件引用。所以很有必要详细讲解一下.h文件和extern的用法。
对于.h文件,我想大家都很熟悉了,不做过多的解释,但是有一点很重要:如果你在.h文件中声明全局变量(在OC中是不合法的:主要指在@interface ExternModel : NSObject和@end之间,当然如果在他们两个之外也是可以声明的)代码如下:
这是一个.h文件
#import <Foundation/Foundation.h>
@interface ExternModel : NSObject
// 这个是不合法的:因为OC的类会将这个全局变量当做成员属性来处理,而成员属性是需要加{}的,所以不合法
NSString *lhString;//声明全局变量的时候默认带有extern,这里必须显式声明
@end
所以正确的写法应该是:(如果还在.h中声明全局变量)
#import <Foundation/Foundation.h>
@interface ExternModel : NSObject
extern NSString *lhString;//这里由于带有extern所以会被认为是全局变量
@end
常用用法(.h结合extern联合使用):
1. 如果在.h文件中声明了extern全局变量,那么在同一个类中的.m文件对全局变量的赋值必须是:数据类型+变量名(与声明一致)=XXXX结构。并且在调用的时候,必须导入.h文件。代码如下:
ExternModel.h
#import <Foundation/Foundation.h>
@interface ExternModel : NSObject
extern NSString *lhString;
@end
ExternModel.m
#import "ExternModel.h"
@implementation ExternModel
NSString *lhString=@"hello";
@end
调用的时候:例如:在viewController.m中调用,则可以引入:ExternModel.h,否则无法识别全局变量。当然也可以通过不导入头文件的方式进行调用(通过extern调用)。
-
extern引用变量
extern具备与.h文件很相似的跨文件访问的功能,但是.h文件不单单局限于范文全局变量,而extern则必须是全局变量(静态+非静态)。
如果在其他文件中访问一个类的全局变量,可以不用导入.h文件,通过extern去直接访问。
例子:同样还是在ViewController.m中访问,此时不需要去导入头文件,代码如下(此时ExternModel代码如上):
#import "ViewController.h"@interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; extern NSString *lhString; NSLog(@"%@",lhString); } @end
输出结果:
2016-03-18 13:37:45.404 ExternTest[1490:180870] hello
可见在不通过.h的情况下去访问全局变量,可以通过extern实现。
- extern声明
extern声明,仅适于修饰全局变量,不能去修饰其他的变量。一般情况下默认,定义的全局变量都带有extern,所以不过多解释。
const
const是用来修饰常量的,这一点注意与宏的区别(苹果推荐我们不要将字符串常量抽成宏):
(以下总结引用自:http://www.jianshu.com/p/2fd58ed2cf55 因为总结的很好)
1.编译时刻:宏是预编译(编译之前处理),const是编译阶段。
2.编译检查:宏不做检查,不会报编译错误,只是替换,const会编译检查,会报编译错误。
3.宏的好处:宏能定义一些函数,方法。 const不能。
4.宏的坏处:使用大量宏,容易造成编译时间久,每次都需要重新替换。
const的介绍:
1. const仅仅用来修饰右边的变量(基本数据变量p,指针变量*p)
2. 被const修饰的变量是只读的。
代码如下:
- (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:常量
}
static修饰全局变量
1.在全局变量前加static,全局变量就被定义成为一个全局静态变量(全局变量和静态全局变量的生命周期是一样的,都是在堆中的静态区,在整个工程执行期间内一直存在)
特点如下:
1)存储区:静态存储区没变(静态存储区在整个程序运行期间都存在);
2)作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
好处:
1)不会被其他文件所访问,修改;
2)其他文件中可以使用相同名字的变量,不会发生冲突。
2.static修饰局部变量
在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。
特点如下:
1)存储区:有栈变为静态存储区rw data,生存期为整个源程序,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,
但不能使用它;
2)作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。
3.static修饰函数
在函数的返回类型前加上关键字static,函数就被定义成为静态函数。
函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用
好处:
1)其他文件中可以定义相同名字的函数,不会发生冲突
2) 静态函数不能被其他文件所用。
在我们这篇博客中主要关注于OC中三个关键字的常用方法。以下将是OC中常用方法的总结:
static和const的联合使用
- static与const作用:声明一个只读的静态变量
- 开发使用场景:在一个文件中经常使用的字符串常量,可以使用static与const组合
具体参考bolg:http://www.jianshu.com/p/2fd58ed2cf55 中的static与const的联合使用
extern和const的联合使用
作用:extern与const组合:只需要定义一份全局变量,多个文件共享。并且全局常量只被定义一次,分配一次内存空间。
代码如下:
ExternModel.h
#import <Foundation/Foundation.h>
@interface ExternModel : NSObject
extern NSString * const lhString;
@end
ExternModel.m
#import "ExternModel.h"
@implementation ExternModel
NSString * const lhString=@"hello";
@end
调用的时候通过导入.h文件进行调用。
网友评论
可以不引入,直接使用下面的方法使用它
extern NSString *lhString;
NSLog(@"%@", lhString);
这样说不太合适吧,给人一种 OC里面 .h 文件无法声明全局变量的暗示。实际上,是可以声明的。