前言
大家好,我是milo,在学习ios开发中,我们有时候会用到static(静态变量)、const(常数)、extern(外部变量),在这篇文章中,我将讲解它们的基本使用。我讲解的顺序是extern->static->const,为什么有个顺序呢,那么请往下看。
extern
全局变量extern,也称之为外部变量,是在方法外部定义的变量。它不属于哪个方法,而是属于整个源程序。作用域是整个源程序。如果全局变量和局部变量重名,则在局部变量作用域内,全局变量被屏蔽,不起作用。
上面这段话理解起来有点抽象,下面演示一个简单的例子:
JJExtern.h文件
#import <Foundation/Foundation.h>
NSString *flag = @"JJExtension";
@interface JJExtern : NSObject
@end
定义了一个字符串flag
main.m文件
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
extern NSString *flag;
NSLog(@"%@",flag);
return 0;
}
打印结果如下:
2018-05-12 16:46:01.643949+0800 oc练习[1810:181852] JJExtension
从以上例子可以看出,main.m无需导入JJExtern的头文件,直接在 NSString *flag前面加上extern就可以取得JJExtern内的flag值。需要注意的是,extern修饰的变量名必须是和JJEXtern下变量名的一致的,即都为flag,否则就会提示找不到。还有一点要注意的是,extern修饰的变量是没有真正的内存的。
总结:
<1>要想访问全局变量可以在前面加extern
<2>extern修饰的变量没有真正内存
那么问题来了,即然只需要extern就能得到并修改其他文件的变量,此不是很安全?因为随时会被人改掉?该怎么办?
答案就是使用static修饰变量,那么该变量就只能在本文件中修改,其他文件无法使用extern获取变量。
static
static既可修饰全局变量,又可以修饰局部变量。
1、修饰全局变量
以前面的例子来说,在 JJExtern 的 NSString *flag = @"JJExtension"; 前面加static,如下:
#import <Foundation/Foundation.h>
static NSString *flag = @"JJExtension";
@interface JJExtern : NSObject
@end
再次运行main.m,编译器报错如下图
总结:static修饰全局变量,保证全局变量安全,外界不可访问与修改,作用域仅限于当前文件。
2、修饰局部变量
下面先看示例代码:
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;
}
修饰局部变量时,作用域仅限于test函数的大括号,其他地方都不顶用 。test这个函数中如果不加static,那么a打印出来的结果永远是1,因为每当调用一次函数,就会定义一个新的变量,每次a的值都是零,a++后就是1 。
但是加上static后,含义就不一样了,打印的结果就是1,2,3......因为被static修饰的变量只会初始化一次,永远都只有一份内存,所以当第一次调用test函数时,a有一个内存空间,并且值是0,第二次再调用test函数时由于int a被 static 修饰,所以不会再初始化新值,它会拿到之前的那份内存a++,就会变为1,以此类推,之后就会变为2,3,4......
总结:
<1>让局部变量只初始化一次
<2>局部变量在程序中只有一份内存
<3>保住所修饰变量的命,保证它不会挂,直到程序结束,这个局部变量才会销毁
const
一句话概括,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;
int * const px = &x; // 让指针px指向变量x(此时const右边是p)
px = &y; // 改变px的指向,出错:Read-only variable is not assignable
(*px) += 2; // 改变px指向的变量x的值
int x = 1;
int y = 2;
const int * const px = &x; // 让指针px指向变量x(此时const右边是*p和p)
px = &y; // 改变px的指向,出错:Read-only variable is not assignable
(*px) += 2; // 改变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”
}
想深入了解可以参考http://www.cocoachina.com/bbs/read.php?tid=1708764
和https://www.cnblogs.com/lulipro/p/7460206.html,分别是oc指针讨论和c指针详解。
引用了以下链接的资料,在此表示感谢:
http://www.cocoachina.com/bbs/read.php?tid=1708764
https://blog.csdn.net/jymn_chen/article/details/18900201
https://www.cnblogs.com/lulipro/p/7460206.html
https://blog.csdn.net/gezi0630/article/details/51993934
网友评论