1.static
1.1 static修饰局部变量
- 修饰方法中的局部变量: 如果方法中的局部变量被static修饰,那么这个变量就会变成静态局部变量,储存在常量区,当方法执行完毕之后,不会回收,下次再执行这个方法的时候,直接使用,就不会再声明了
举个例子:
//Teacher.h文件 只声明了一个方法
#import <Foundation/Foundation.h>
@interface Teacher : NSObject
-(void)sayHi;
@end
//Teacher.m文件 实现方法
#import "Teacher.h"
@implementation Teacher
- (void)sayHi
{
int num = 12;
NSLog(@"num = %d",num);
num++;
}
@end
#import <Foundation/Foundation.h>
#import "Teacher.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//实例化对象 调用sayHi的方法两次 查看输出的结果
Teacher *teacher = [[Teacher alloc]init];
[teacher sayHi];
[teacher sayHi];
}
return 0;
}
输出的结果:
2017-05-27 19:37:56.951110+0800 property[17992:628125] num = 12
2017-05-27 19:37:56.951692+0800 property[17992:628125] num = 12
两次的结果都是12, 这次我们在sayHi方法的局部变量中加入static关键字,再次打印输出,看看结果会是什么
//Teacher.m文件 实现方法
#import "Teacher.h"
@implementation Teacher
- (void)sayHi
{
static int num = 12; //加入了static关键字
NSLog(@"num = %d",num);
num++;
}
@end
继续调用两次sayHi的方法,打印输出的结果为:
2017-05-27 19:44:57.023325+0800 property[18082:632493] num = 12
2017-05-27 19:44:57.023478+0800 property[18082:632493] num = 13
注意 :
当我们不加static关键字时,在方法在执行完了之后,方法内的局部变量就会被回收, 再此调用的时候,就会再次生成一个新的局部变量,所以两次的值一样
加了static之后,局部变量就变成了静态变量,只初始化一次,下一次依据上一次的结果
不能修饰属性 :
@interface Teacher : NSObject
{
static NSString *name; //这样是会报错的
// 报错信息: Type name does not allow storage class to be specified
}
不能修饰方法
1.2 static修饰全局变量
1.在全局变量前加static,全局变量就被定义成为一个全局静态变量(全局变量和静态全局变量的生命周期是一样的,都是在堆中的静态区,在整个工程执行期间内一直存在)
特点如下:
1)存储区:静态存储区没变(静态存储区在整个程序运行期间都存在);
2)作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
好处:
1)不会被其他文件所访问,修改;
2)其他文件中可以使用相同名字的变量,不会发生冲突
2. extern
2.1 extern声明
extern声明: 仅适于修饰全局变量,不能去修饰其他的变量。
工作原理: 先在当前文件查找有没有全局变量,没有找到,才会去其他文件查找
2.2 extern和.h文件的关系
.h文件的作用就是为了更好的方便其他文件(类)去调用本文件中的变量、属性和方法。而extern也是为了实现变量和函数的跨文件引用
如果你在.h文件的@interface XXX : NSObject和@end之间声明全局变量是不合法的:
#import <Foundation/Foundation.h>
@interface Hello : NSObject
// 这个是不合法的:因为OC的类会将这个全局变量当做成员属性来处理,而成员属性是需要加{}的,所以不合法
NSString *lhString;//声明全局变量的时候默认带有extern,这里必须显式声明
@end
所以正确的写法应该是:(如果还在.h中声明全局变量)
// Hello.h文件
#import <Foundation/Foundation.h>
@interface Hello : NSObject
extern NSString *myString;//这里由于带有extern所以会被认为是全局变量
@end
//Hello.m文件
#import "Hello.h"
@implementation Hello
NSString *myString=@"hello";
@end
2.3 extern引用变量
extern具备与.h文件很相似的跨文件访问的功能,但是.h文件不单单局限于范文全局变量,而extern则必须是全局变量(静态+非静态)
如果在其他文件中访问一个类的全局变量,可以不用导入.h文件,通过extern去直接访问。
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
extern NSString *myString;
NSLog(@"%@",myString);
}
@end
输出结果: ` 2017-05-27 21:23:47.424 Test[1490:180870] hello
3. const
3.1使用方法:
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:常量
}
3.2 const与宏(define)的区别
1.编译时刻:宏是预编译(编译之前处理),const是编译阶段。
2.编译检查:宏不做检查,不会报编译错误,只是替换,const会编译检查,会报编译错误。
3.宏的好处:宏能定义一些函数,方法。 const不能。
4.宏的坏处:使用大量宏,容易造成编译时间久,每次都需要重新替换。
4.static与const联合使用
static与const作用: 声明一个只读的静态变量
开发使用场景: 在一个文件中经常使用的字符串常量,可以使用static与const组合, 可以理解为代替宏的使用
5.extern与const联合使用
开发中使用场景: 在多个文件中经常使用的同一个字符串常量,可以使用extern与const组合。
原因:
- static与const组合:在每个文件都需要定义一份静态全局变量。
- extern与const组合 : 只需要定义一份全局变量,多个文件共享。
全局常量正规写法:开发中便于管理所有的全局变量,通常搞一个GlobeConst文件,里面专门定义全局变量,统一管理,要不然项目文件多不好找。
本文部分内容借鉴了以下网址
袁峥Seemygo 韩俊强 liyubao160