美文网首页
iOS const、static、extern实操

iOS const、static、extern实操

作者: 高射火炮 | 来源:发表于2019-07-11 16:32 被阅读0次

    去阿里面试被问到了好多基本功和底层知识,由于没有总结过,导致有很多用过的东西并不知道怎么表达,遭到了无情的鄙视;决定要每周总结一个知识点,立下flag,激励自己一下!
    先从最基本的写起:先写几个修饰关键字 const、static、extern.

    一、const:: 被const修饰的变量是只读的(变量->只读变量).

    先从最基础的开始
    定义变量

     int a = 1;
     a = 20;// 允许修改值
    

    然后开始进入const
    const两种用法
    1、const:修饰基本变量p

    const int b = 20; // b:只读变量
    int const b = 20; // b:只读变量
    b = 1; // 会报错// 不允许修改值
    

    2、const:修饰指针类型*p
    定义一个指向int类型的指针,指向a的地址

    int a = 20;
    int *p = &a;
    NSLog(@"p == %p---&a == %p",p,&a);
    int c = 10;
    p = &c;
    NSLog(@"p == %p---*p == %d",p,*p);
    int d = 11;
    *p = d;
    NSLog(@"p == %p---*p == %d",p,*p);
    //打印结果
    2019-07-11 09:45:32.867368+0800 Runtime理解[44662:1691119] p == 0x7ffeefb433ac---*p == 20
    2019-07-11 09:45:32.867518+0800 Runtime理解[44662:1691119] p == 0x7ffeefb4339c---*p == 10
    // 允许修改p指向的地址
    2019-07-11 09:45:32.867637+0800 Runtime理解[44662:1691119] p == 0x7ffeefb4339c---*p == 11
    // 允许修改p访问内存空间的值
    
    

    const修饰指针变量访问的内存空间,修饰的是右边*p1,

    int a = 20;
    const int *p = &a; 
    NSLog(@"p == %p---*p == %d",p,*p);
    int c =10;
    p = &c;
    NSLog(@"p == %p---*p == %d",p,*p);
    //打印结果
    2019-07-11 10:15:54.968002+0800 Runtime理解[45151:1709783] p == 0x7ffee3f193ac---*p == 20
    2019-07-11 10:15:54.968132+0800 Runtime理解[45151:1709783] p == 0x7ffee3f1939c---*p == 10
    // 允许修改p指向的地址
    
     int d = 11;
    *p = d;//报错,Read-only variable is not assignable(只读变量不可赋值)
    // 不允许修改p访问内存空间的值
    
    
    int a = 20;
    const *p = &a; 
    NSLog(@"p == %p---*p == %d",p,*p);
    int c =10;
    p = &c;
    NSLog(@"p == %p---*p == %d",p,*p);
    //打印结果
    2019-07-11 10:15:54.968002+0800 Runtime理解[45151:1709783] p == 0x7ffee3f193ac---*p == 20
    2019-07-11 10:15:54.968132+0800 Runtime理解[45151:1709783] p == 0x7ffee3f1939c---*p == 10
    // 允许修改p指向的地址
    
     int d = 11;
    *p = d;//报错,Read-only variable is not assignable(只读变量不可赋值)
    // 不允许修改p访问内存空间的值
    
    int a = 20;
    int const *p = &a; 
    NSLog(@"p == %p---*p == %d",p,*p);
    int c =10;
    p = &c;
    NSLog(@"p == %p---*p == %d",p,*p);
    //打印结果
    2019-07-11 10:15:54.968002+0800 Runtime理解[45151:1709783] p == 0x7ffee3f193ac---*p == 20
    2019-07-11 10:15:54.968132+0800 Runtime理解[45151:1709783] p == 0x7ffee3f1939c---*p == 10
    // 允许修改p指向的地址
    
     int d = 11;
    *p = d;//报错,Read-only variable is not assignable(只读变量不可赋值)
    // 不允许修改p访问内存空间的值
    
    总结:const int *p 作用等同于 int const *p 
    *p 是常量 p是变量
    
    int a = 20;
    int * const p = &a; 
    NSLog(@"p == %p---*p == %d",p,*p);
    int c =10;
    p = &c; //报错,Read-only variable is not assignable(只读变量不可赋值)
    // 不允许修改p指向的地址
    int d = 11;
    *p = d;
    NSLog(@"p == %p---*p == %d",p,*p);
    // 打印结果
    2019-07-11 10:50:44.694506+0800 Runtime理解[45665:1731013] p == 0x7ffee8f413ac---*p == 20
    2019-07-11 10:50:44.694684+0800 Runtime理解[45665:1731013] p == 0x7ffee8f413ac---*p == 11
    // 允许修改p访问内存空间的值
    
    总结: int *const p    *p是变量 p是常量;
    
    通过以上代码总结:const修饰的紧右边的为常量,在此就不一一验证,有兴趣的可以自己写代码验证一下;
    const int *p              // *p:常量   p:变量
    int const *p              // *p:常量   p:变量
    int *const p              // *p:变量   p:常量
    const int * const p       // *p:常量   p:常量
    int const * const p       // *p:常量   p:常量
    

    下面来试验一下const最常用的方法:修饰NSString,废话少说,上代码:

    NSString * const str1=@"sdh";
    str1 = @"123" //报错
    //因为NSString是不可变字符串:指针指向内存的内容是不允许改变的,因为const修饰的是指针 str1:指针不允许指向其他内存;
    //所以不可以修改指针指向的原内存中的内容,指针不可以指向其他的内存
    
    
     NSString const *str2 = @"sdh";
     str2 = @"123"; //不报错
    //因为NSString是不可变字符串:指针指向内存的内容是不允许改变的,因为const修饰的是指针 *str2:指针指向内存的内容不允许改变,所以 *str2 是常量 但str2是变量指针可以指向一天内存;
    //所以不可以修改指针指向的原内存中的内容,指针可以指向其他的内存
    
    
    NSMutableString *const var1 =[NSMutableString string];
    NSMutableString *var2 = [NSMutableString stringWithFormat:@"%@",@"123"];
    var1 = var2; //报错 因为const修饰的是指针 var1:指针不允许指向其他内存;
    [var1  appendString:@"123"]; //不报错 因为NSMutableString是可变字符串:指针指向内存的内容是允许改变的
    //所以可以修改指针指向的原内存中的内容,指针不可以指向其他的内存
    
    NSMutableString const *var3 =[NSMutableString string];
    var3 = var2; //不报错  因为const修饰的是指针 *var3 所以var3是变量,指针可以指向其他内存地址
    [var3 appendString:@"123456"]; //不报错 因为var3是可变字符串指针指向的原内存中的内容可以改变
    //所以可以修改指针指向的原内存中的内容,常量指针可以指向其他的内存
    NSLog(@"str1 = %@ -- str2 = %@ -- var1 = %@ -- var2 = %@",str1,str2,var1,var2);
    //打印结果
    2019-07-11 11:28:43.957979+0800 Runtime理解[46292:1755776] str1 = sdh -- str2 = 123 -- var1 = 123 -- var2 = sdh123456
    
    

    const修饰字符串总结:

    NSString *const str1
    不可以修改指针指向的原内存中的内容,指针不可以指向其他的内存
    NSString const *str2
    不可以修改指针指向的原内存中的内容,指针可以指向其他的内存
    NSMutableString const *var1
    可以修改指针指向的原内存中的内容,指针可以指向其他的内存
    NSMutableString *const var2
    可以修改指针指向的原内存中的内容,指针不可以指向其他的内存
    

    const用法总结道这里。

    二、static和extern简单使用
    "static作用":
    1、修饰局部变量:
    1)延长局部变量的生命周期,程序结束才会销毁。
    2)局部变量只会生成一份内存,只会初始化一次。
    3)Static关键字不可以改变局部变量的作用域。

    @implementation Person
    -(instancetype)init{
        self = [super init];
        if (self) {
            [self conlogAge];
            [self conlogAge];
        }
        return self;
    }
    
    -(void)conlogAge{
        static NSInteger age = 18;
        age ++;
        NSLog(@"%ld",age);
    }
    
    
    #import "Person.h"
    @interface ConstStaticViewController ()
    @end
    @implementation ConstStaticViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        Person *per = [Person new];
        Person *per2 = [Person new];
    }
    //打印输出
    //2019-07-11 15:19:25.617612+0800 Runtime理解[49598:1888382] 19
    //2019-07-11 15:19:25.617712+0800 Runtime理解[49598:1888382] 20
    //2019-07-11 15:19:25.617800+0800 Runtime理解[49598:1888382] 21
    //2019-07-11 15:19:25.617892+0800 Runtime理解[49598:1888382] 22
    

    注意:ConstStaticViewController是二级页面,我们返回到一级页面,该页面销毁,在重新创建改页面,viewDidLoad会重新执行一次,我们在看打印数据:

    2019-07-11 15:42:11.181260+0800 Runtime理解[50022:1905671] 19
    2019-07-11 15:42:11.181433+0800 Runtime理解[50022:1905671] 20
    2019-07-11 15:42:11.181541+0800 Runtime理解[50022:1905671] 21
    2019-07-11 15:42:11.181711+0800 Runtime理解[50022:1905671] 22
    2019-07-11 15:42:14.761006+0800 Runtime理解[50022:1905671] 23
    2019-07-11 15:42:14.761159+0800 Runtime理解[50022:1905671] 24
    2019-07-11 15:42:14.761285+0800 Runtime理解[50022:1905671] 25
    2019-07-11 15:42:14.761378+0800 Runtime理解[50022:1905671] 26
    

    说明:
    1、age这个变量并未因持有他的对象的销毁儿销毁,局部变量的生命周期被延长
    2、而且, [self conlogAge]函数被调用多次,age这个变量并未重新初始化,而是跳过初始化,继续进行 ++操作,所以:局部变量只会生成一份内存,只会初始化一次。

    
    -(void)conlogAge{
        static NSInteger age = 18;
        age ++;
        NSLog(@"%ld",age);
    }
    -(void)showAge{
        age++;//直接报错
        extern NSInteger age; //编译时报错
        NSLog(@"%ld",age);
    }
    

    3、被static修饰过的变量,在其他作用域是不能访问的。

    2、static修饰全局变量

    1)只能在本文件中访问,修改全局变量的作用域,生命周期不会改
    2)避免重复定义全局变量

    NSString *allChange = @"allChange";//全局变量,本文件直接用,其他文件借助extern调用
    static NSString *changes =@"change";//全局变量,本文件直接用,其他文件借助不能调用,用extern调用,会报错
    
    

    三、const、static配合使用
    开发时常用的写法,用const、和static配合使用来代替宏的部分功能(#define)
    一、const与宏的区别(面试题):

    • "const简介":之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量。
    • "执行时刻":宏是预编译(编译之前处理),const是编译阶段。
    • "编译检查":宏不做检查,不会报编译错误,只是替换,const会编译检查,会报编译错误。
    • "宏的好处":宏能定义一些函数,方法。 const不能。
    • "宏的坏处":使用大量宏,容易造成编译时间久,每次都需要重新替换。
    #define CHANGE @"change";
    static NSString *const changes =@"change";
    

    虽然测试过,及时用相当数量的宏编译时间并不会差很多,但是,我们还是要按照苹果的推荐来的好,用第二个表示方法。

    四、extern使用
    "extern作用":只是用来获取全局变量(包括全局静态变量)的值,不能用于定义变量。
    "extern工作原理":先在当前文件查找有没有全局变量,没有找到,才会去其他文件查找。
    废话补多说:代码解释

    #import "SLStaticDemo.h"
    NSInteger age = 10;
    @implementation SLStaticDemo
    @end
    
    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.view.backgroundColor = [UIColor whiteColor];
        
        extern NSInteger age;
        NSLog(@"age = %ld", (long)age);
        
        age += 10;
        NSLog(@"age = %ld", (long)age);
    }
    @end
    

    打印结果:

    image
    从输出结果 age = 10 我们可以看到即便我们在ViewController.m中并没有import SLStaticDemo.h也能得到SLStaticDemo中定义的age变量,这就是extern关键字的功劳(extern可以访问全局变量);
    注:这里理解起来很简单,懒得自己写了,参照的大神的代码,网址:https://www.jianshu.com/p/9c09989b6862

    好,用了将近一天的时间,把这三个基本的关键字理清了,可能有写啰嗦,希望大家选择性参考。

    相关文章

      网友评论

          本文标题:iOS const、static、extern实操

          本文链接:https://www.haomeiwen.com/subject/sxfkkctx.html