static变量详解

引言

OC中经常用到单例。创建一个单例的方法是这样的(这里随便举了一个自己写过的单例作为示例):

+ (instancetype)shareInstance{
    static ICCookieHelper *cookieHelper = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        cookieHelper = [[ICCookieHelper alloc]init];
    });
    return cookieHelper;
}

以前只知道单例是这样写的,dispatch_once函数保证cookieHelper变量在整个app生命周期中只执行一次赋值操作,这是实现单例的关键所在。然后最近突然把目标聚焦在了不是很显眼的地方

    static ICCookieHelper *cookieHelper = nil;

由于shareInstance方法会被多次调用,每次执行该方法,上面语句调用一次(在我未搞清楚static的作用之前我是这么认为的),cookieHelper变量似乎又被重新定义了,且无初始值。但是赋值语句只执行一次啊,这样一来cookieHelper不就是nil了!!一下子就懵逼了。我知道肯定是这个static耍了什么把戏,于是开始查资料…

static变量

变量

变量,包括局部变量和全局变量,又根据有无static修饰,分为静态变量和非静态变量。因此就有了非静态局部变量、静态局部变量、非静态全局变量、静态全局变量。但不管怎样,都是变量没的说!因此先来说说变量的所有的共性:生命周期。

变量生命周期

一个变量,其生命周期无非从创建开始到撤销结束。其中的相关概念包括变量定义、初始化、赋值。

  • 定义:创建一个变量,系统为其分配内存地址。
  • 初始化:变量定义之后首次赋值
  • 赋值:替换变量所在内存的内容
  • 撤销:系统释放存放变量的内存,回收地址

下面代码对变量的使用过程做了测试,打印结果符合预期

    int a;                  //定义一个int变量,系统为其分配内存地址,但变量值是不确定的
    NSLog(@"%d",a);         //一个不确定数
    NSLog(@"%p",&a);        //变量地址
    NSLog(@"********");

    static int *b;          //定义一个指针变量,系统为指针变量分配内存地址,该地址存放指针变量的地址,并不是变量本身所代表的地址,而指针变量本身所代表的地址是一个空地址(空指针)。这里把指针变量看成是普通变量就能理解为什么变量本身值是空的了。
    NSLog(@"%p",b);         //指针变量本身值为0x0
    NSLog(@"%p",&b);        //指针变量地址(并非变量本身所代表的地址,而是存放指针变量的地址)
    NSLog(@"********");

    a = 10;                 //对普通变量a赋值
    NSLog(@"%d",a);         //10
    NSLog(@"%p",&a);        //a的地址没有改变
    NSLog(@"********");

    b = &a;                 //对指针变量b赋值,把a的地址赋给b
    NSLog(@"%p",b);         //&a
    NSLog(@"%p",&b);        //b的地址没有改变
    NSLog(@"********");

    MyObject *myObject;     //定义一个对象,对象是一个指针变量
    NSLog(@"%@",myObject);  //指针变量所指向的值为空 (null)
    NSLog(@"%p",myObject);  //指针变量本身值为0x0
    NSLog(@"%p",&myObject); //指针变量的地址 0x7fff5fbff828

    myObject = [[MyObject alloc]init];  //指针变量初始化
    NSLog(@"%@",myObject);              //<MyObject: 0x100400110>
    NSLog(@"%p",myObject);              //0x100400110 <MyObject: 0x100400110>的地址
    NSLog(@"%p",&myObject);             //0x7fff5fbff828 0x100400110的地址

    myObject = [[MyObject alloc]init];  //重新赋值
    NSLog(@"%@",myObject);              //指针所指的值改变
    NSLog(@"%p",myObject);              //指针变量的值改变
    NSLog(@"%p",&myObject);             //指针变量的地址不变

非静态局部变量(自动变量)

所谓静态变量,即被static修饰的变量。没有被static修饰的变量,称之非静态变量,又称自动变量,事实上它缺省被auto修饰。

局部变量定义在一个函数内部,生存范围为变量定义所在函数或模块,以“{”“}”界定,该类型变量只能在函数(模块)内被调用。

非静态局部变量即变量即是局部的,又是非静态的。变量在定义的时候被创建,当程序运行出了函数(模块),变量就被撤销。当下次再次调用该函数(模块)时,重新创建的变量和之前的那个没有半毛钱关系。

静态局部变量

与非静态局部变量相比,静态局部变量有着很大不同。静态局部变量属于静态存储方式,存放在内存的静态存储区,该内存区域中的变量在整个程序生命周期中地址都是不变的。静态局部变量具有以下特点:

  1. 静态局部变量在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后,尽管该变量还继续存在,但不能使用它。
  2. 基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,其值是不定的。
  3. 静态变量在其生命周期中只能定义一次,即当一个静态局部变量在一个函数中被定义之后,下次再次调用该函数,定义语句将不再被调用!!终于知道为什么OC的单例能那样写了,原来static修饰的变量只能被定义一次,之后就不再调用定义语句了!!又涨姿势了!!不过虽然不能多次定义,多次赋值却是可以的,因此静态变量的值是可以变的!不变的是变量所在的内存地址!

根据静态局部变量的特点,可以看出它是一种生存期为整个源程序的变量。虽然离开定义它的函数后不能使用,但如果再次调用定义它的函数时,它又可继续使用, 而且保存了前次被调用后留下的值。 因此,当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜。

非静态全局变量

非静态全局变量也属于静态存储方式,因此它的生命周期也是整个程序的生命周期。

如果对于一个变量,想让它的作用于不局限与当前函数,而是想在其他函数,甚至在其他文件中都能使用改变,这时候就要把变量定义成全局变量。注意如果定义成静态类型的,那么其作用于只限于当前文件,不能别其他文件所共享。

如何跨文件使用非静态全局变量呢?下面做简单示例:

#import "MyFile.h"

int a = 10;

@implementation MyFile
@end

在MyFile.m文件中创建并初始化了一个全局变量,下面代码在main.m文件中通过extern关键字引用该变量

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    extern int a;
    NSLog(@"%d",a);  //打印结果 10

    return 0;
}

成功在main.m文件中引用了MyFile.m中定义的全局变量a。注意:这里称这个过程为引用是正确的,extern关键的作用就是引用一个外部定义的全局变量,并没有定义一个新的变量。不信的话在不同的地方引用同一个变量,分别打印地址,会发现是同一个地址,也就是说始终只有一个变量,只是在不同的地方使用它罢了(因此在多线程环境中要小心使用)。

另外,无需在引用全局变量的文件中导入定义全局变量所在文件的头文件,全局变量编译时就被定义好了。事实上,如果在一个.h问价中定义了一个局部变量,另一个文件中又导入该文件就会报重复错误,因此局部变量的定义通常都放在.m文件中。

静态全局变量

首先静态全局变量肯定也属于静态存储方式,生命周期为整个程序。另外静态全局变量与非静态全局变量的区别,其实前面以及说过了。两个的唯一区别在于,非静态全局变量的作用域是整个工程,即在别的文件中也可以引用;静态全局变量的作用范围只限于当前文件,在同一源程序的其他文件中不能直接引用。因此要想在别的文件中操作当前文件的静态全局变量,只能在当前文件中定义一个接口函数。

总结

把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生命周期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值