生命周期: 一个变量能存活多久,什么时候分配内存,内存什么时候回收
作用域: 一个变量在什么范围内是可见的,可用的
static
分为修饰局部变量和全局变量
在函数或者代码块内声明的变量叫局部变量
修饰局部变量:
- 在程序中只有一份内存
- 修改了局部变量的生命周期
局部变量是存储在栈区的,其生命周期是整个代码块,作用域也是整个代码块,出了这个代码块,该变量的内存就会被回收,局部变量也被销毁。
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSInteger count = 0;
count ++;
NSLog(@"count: %ld", count);
}
多次点击屏幕,打印结果:
[ViewController.m:40行] count: 1
[ViewController.m:40行] count: 1
[ViewController.m:40行] count: 1
局部变量count是声明在touchesBegan:withEvent:方法的代码块内的,其生命周期和作用域均是该代码块。count初始化值为0,每执行一次结束后count就会被销毁,再次执行时 count又会被重新创建和在栈区申请内存
当用static修饰局部变量时,变量被称为静态局部变量,静态局部变量和全局变量、静态全局变量一样存储在全局/静态存储区。存储在全局/静态存储区的变量其生命周期同程序生命周期,也就是直到程序结束它才会销毁。
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
static NSInteger count = 0;
count ++;
NSLog(@"count: %ld", count);
}
多次点击屏幕,打印结果:
[ViewController.m:40行] count: 1
[ViewController.m:40行] count: 2
[ViewController.m:40行] count: 3
首次点击屏幕,即执行函数体内代码时,由于static修饰局部变量count,在全局/静态区申请了一块内存,该内存生命周期同整个源程序,则下次执行该函数体内代码时,不会重新申请新的一块内存,而是找到这块叫count的内存,继续上一次结果进行计算。即使pop出当前VC(当前VC销毁),再次进入VC且点击屏幕执行,count的值仍会从之前值累加,因为static修饰了局部变量count,其生命周期同整个程序,不会随着当前VC的销毁而销毁
修饰全局变量
- 修改了全局变量的作用域,生命周期不会改变
- 避免重复定义全局变量
全局变量存储在全局/静态存储区,它的生命周期同整个源程序,直到程序结束才销毁,我们可以使用extern关键字来引用这个全局变量。
如下我们可以使用extern关键字访问别的文件定义的全局变量(PS: IDE并不会自动补全)
image.png image.png
运行打印结果:
image.png
如果我们使用static修饰全局变量,则该变量作用域仅限于该文件
const
意为"常量、常数"
const用来修饰右边的基本变量或指针变量,被const修饰的变量是只读的。
如下图,变量a被const修饰,a是只读的,不能被修改
image.png
int const *p; //*p只读 p变量
int * const p; //*p变量 p只读
const int * const p; //p和*p都只读
int const * const p; //p和*p都只读
判断p和p是只读还是变量,关键看const在谁的前面,如果在p前面,那么p是只读,p还是变量,在p前面,那么p只读,p变量。
const常用用法:
定义一个全局只读变量,常和static一起使用,修改了其作用域,只在本文件内访问的只读变量
static NSString *const kLogin = @"/login";
extern
在开发中,我们通常会单独抽一个类来管理一些全局的变量或常量
比如:
.h文件:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Define : NSObject
extern NSString * const kLoginNoti;
@end
NS_ASSUME_NONNULL_END
.m文件:
#import "Define.h"
NSString *const kLoginNoti = @"notification.app.login";
@implementation Define
@end
使用时,引入该文件#import "Define.h",则在该文件中即可使用定义的字段
[[NSNotificationCenter defaultCenter] postNotificationName:kLoginNoti object:nil];
const与宏的区别
编译时刻: 宏是预编译(编译之前);const是编译阶段
编译检查: 宏不做检查,不会报编译错误,只是替换;const会编译检查,会报编译错误
宏的好处: 宏能定义函数、方法;const不能
宏的弊端: 如果代码中大量的使用宏会使预编译时间变长
PS: 定义一个字符串的宏,赋值给多个变量,打印其内存地址,经过测试: 宏定义的是常量,常量都放在常量区,只会生成一份内存,故网上说的是不对的
#define SCREEN_Width ([UIScreen mainScreen].bounds.size.width)
#define SCREEN_Height ([UIScreen mainScreen].bounds.size.height)
参考:
iOS中static,const,extern相关的问题
IOS 关键字const 、static、extern详解
iOS const、宏、static、extern的关系
网友评论