iOS const、static、extern实操

2019-07-11  本文已影响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与宏的区别(面试题):

#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

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

上一篇下一篇

猜你喜欢

热点阅读