存储类型和一些关键字

参考:C Storage Classes
iOS定义静态变量、静态常量、全局变量
iOS开发——OC篇&常用关键字的使用与区别
iOS 宏(define)与常量(const)的正确使用

一、C语言的存储类型

在C语言中,程序内变量或函数的作用域和寿命是由其存储类确定的。每个变量都具有生存周期,或存储其值得上下文。方法,同变量一样,也存在,或可见于,一个特殊的范围里,这就决定了哪一部分能够知道且能够访问它们。

C里有四种存储类:

  • auto
  • register
  • static
  • extern
1、auto

很有可能你从来没见过这个关键字。这是因为auto是默认存储类,因此通常并不需要显式的使用。

当运行到程序块的时候,auto类型的变量能自动分配内存,并且在该程序块运行完成时释放。 访问auto变量仅限于声明它的block,以及任何嵌套block内。

2、register

大多数OC程序员可能也不熟悉register,因为它没有被广泛的使用在NS世界里。

register行为就像auto,但不同的是它们不是被分配到堆栈中,它们被存储在一个寄存器里。

寄存器能比内存提供更快的访问速度,但由于内存管理的复杂性,把变量放在寄存器中并不能保证程序变得更快。事实上,很可能由于在寄存器上占用了不必要的空间而最终被放缓执行。使用寄存器实际上只是一个给编译器存储变量的建议,实现时可以选择是否遵从这一点。

寄存器在OC不够普及其实挺好的:最好还是不要使用它,因为比起其他任何明显的方式加快应用程序,它更容易引起让人更加头疼的结果。

3、static

作为关键字,static被以很多不同的,不兼容的方式使用,因此要弄清楚每一个实例到底是什么意思可能会造成混淆。

  • 方法或函数内部的一个static变量保留其调用之前的值。

  • 全局声明的一个static变量可以被任何函数或方法调用,只要这些方法出现在跟static变量同一个文件中。这同样适用于static方法。

    静态单例

OC中一个常见的模式是静态单例,在这个case里,一个静态声明的变量被初始化,并在任何一个函数或者类方法中被返回。 dispatch once 用于保证变量初始化在一个线程安全的方式下 只 发生一次:

+ (instancetype)sharedInstance {
  static id _sharedInstance = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
      _sharedInstance = [[self alloc] init];
  });

  return _sharedInstance;
}

单例模式对于创建整个应用程序共享的对象是很有用的,诸如HTTP客户端或一个通知管理,或创建过程很昂贵的对象,诸如格式化

4、extern

当static使得一个特定的文件中的函数和变量全局可见,extern则使它们对所有文件可见。

一般来说,全局变量并不是一个好主意。由于没有如何及何时改变只的任何对extern有两个常见和实际的用途。

全局字符串常量

任何时候,如果你的应用程序要在一个公共文件头部申明一个非自然语言的字符串常量,都应该将其声明为外部字符串常量。尤其是在声明诸如userInfo字典,NSNotification 名称和 NSError 域的时候。

该模式是在公共头文件里申明一个extern的NSSting*const,并在实现文件里定义该NSString * const:

//AppDelegate.h
extern NSString * const kAppErrorDomain;

//AppDelegate.m
NSString * const kAppErrorDomain = @"com.example.yourapp.error";

字符串的值并没有特别需要注意的事情,只要它是唯一的。使用字符串常量建立了严格的约束,用该常数变量来代替字符串文本值本身。

公共方法

一些API可能会想要公开曝光一些辅助方法。由于仅提供辅助而与具体状态无关的考虑,用方法来封装这些行为是一个很好的方式,而且如果特别有用,还可能值得使其全局可用。

//TransactionStateMachine.h
typedef NS_ENUM(NSUInteger, TransactionState) { TransactionOpened, TransactionPending, TransactionClosed,};extern NSString * NSStringFromTransactionState(TransactionState state);

//TransactionStateMachine.m
NSString * NSStringFromTransactionState(TransactionState state) { switch (state) { case TransactionOpened: return @"Opened"; case TransactionPending: return @"Pending"; case TransactionClosed: return @"Closed"; default: return nil; }}

理解任何事情其实都是去了解上下文。可能那些我们看到的很明显且不证自明的东西,对所有那些没有我们的参照系的人来说是未知的。我们无法真正了解和欣赏自己和他人的观点及信息的差异或许使我们最根本的缺点。

这就是为什么,在我们构建的逻辑0和1的宇宙中,我们如此谨慎的区分上下文,并基于这些明确的规则上构建我们的假设。C存储类对于理解程序是如何运行时必不可少的。如果没有他们,我们的开发将如履薄冰。因此,需要谨慎对待这些简单的规则,才能包含新新的编写代码。

二、iOS的内存存储区的划分

  • 1、栈区:栈区主要存放函数内部定义的变量、数组。函数调用时,开辟空间,函数执行完毕,回收空间,空间的开辟与回收有系统管理。
  • 2、堆区:堆区最大的特点:空间的开辟与释放由开发人员手动管理。
  • 3、全局静态区:主要存放函数外部定义的全局变量以及静态变量,空间一旦开辟,就不会回收,直到应用程序执行结束。
  • 4、常量区:存储常量:整形常量、浮点型常量、字符串常量
  • 5、代码区:存放程序编译之后生成的cpu指令。

三、OC中的一些关键字

1、static
1.1 static变量只是在编译时候进行初始化,对于static变量,无论是定义在方法体里面还是在方法体外面其作用域都一样。

我们经常使用的UItableViewController里面,在定义UItableView的时候,模板会经常使用以下代码

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 
{
 
static NSString *CellIdentifier = @"Cell";
 
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
 
return cell;
 
}

在上面定义了static变量,在编译期间会对这个变量进行初始化赋值,也就是说这个变量值要么为nil,要么在编译期就可以确定其值,一般情况下,只能用NSSrting或者基本类型,并且这个变量只能在cellForRowAtIndexPath访问。这个和C语言里面的static的变量属性一样。

1.2 static变量也可以定义在.m的方法体外。这样所有的方法内部都可以访问这个变量。但是在类之外是没有办法访问的,也就是不能用 XXXClass.staticVar 的方式来访问 staticVar变量。相当于static变量都是私有的。

如果.m文件和方法体里面定义了同名的static变量,那么方法体里面的实例变量和全局的static变量不会冲突,在方法体内部访问的static变量和全局的static变量是不同的。

@implementation IFoundAppDelegate
 
static NSString * staticStr  = @"test";
 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 
{
 
static NSString * staticStr  = @"test2";
 
NSLog(@"the staticStr is %@ -- %d",staticStr,[staticStr hash]);
 
}
 
- (void)applicationWillResignActive:(UIApplication *)application
 
{
 
NSLog(@"the staticStr is %@ -- %d",staticStr,[staticStr hash]);
 
}

以上两个static变量是两个不同的变量,在didFinishLaunchingWithOptions方法内部,访问的是方法体内部定义的staticStr变量,在applicationWillResignActive方法体里面,访问的是全局定义的staticStr变量。可以通过日志打印其hash来进行确认两个变量是否一样。

2、const和define
2.1、当我们想全局共用一些数据时,可以用宏、变量、常量

宏:

#define HSCoder @"汉斯哈哈哈"

变量:

NSString *HSCoder = @"汉斯哈哈哈";

常量:

//四种写法:
static const NSString *HSCoder = @"汉斯哈哈哈";
const NSString *HSCoder = @"汉斯哈哈哈";
NSString const *HSCoder = @"汉斯哈哈哈";
NSString * const HSCoder = @"汉斯哈哈哈";

思考:宏与常/变量的选择?

  • 宏:只是预处理器里进行文本替换,没有类型,不做任何类型检查,编译器可以对相同的字符串进行优化。只保存一份到 .rodata 段。甚至有相同后缀的字符串也可以优化,你可以用GCC 编译测试,"Hello world" 与 "world" 两个字符串,只存储前面一个。取的时候只需要给前面和中间的地址,如果是整形、浮点型会有多份拷贝,但这些数写在指令中。占的只是代码段而已,大量用宏会导致二进制文件变大。
  • 变量:共享一块内存空间,就算项目中N处用到,也不会分配N块内存空间,可以被修改,在编译阶段会执行类型检查。
  • 常量:共享一块内存空间,就算项目中N处用到,也不会分配N块内存空间,可以根据const修饰的位置设定能否修改,在编译阶段会执行类型检查。
2.2 常量区分

全局常量: 不管你定义在任何文件夹,外部都能访问。

const NSString *HSCoder = @"汉斯哈哈哈";

局部常量:用static修饰后,不能提供外界访问

static const NSString *HSCoder = @"汉斯哈哈哈";

ps :static经常用到.m文件中,如果是.h文件定义的全局变量,在别的文件中,引入这个头文件,也是可以访问这个变量的。

2.3const修饰位置不同,代表什么?
1.const NSString *HSCoder = @"汉斯哈哈哈";
"*HSCoder"不能被修改, "HSCoder"能被修改

2.NSString const *HSCoder = @"汉斯哈哈哈";
"*HSCoder"不能被修改, "HSCoder"能被修改

3.NSString * const HSCoder = @"汉斯哈哈哈";
"HSCoder"不能被修改,"*HSCoder"能被修改


结论:const右边的总不能被修改

验证:

1.png
2.png
3.png
4.png
image.png

所以一般我们定义一个常量又不想被修改应该这样:

NSString * const HSCoder = @"汉斯哈哈哈";

一般项目中,定义全局常量,会写在独立文件中

5.png
6.png

访问:

导入头文件


7.png

访问常量


8.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,296评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 注:这是第三遍读《C语言深度解剖》,想想好像自从大学开始就没读完过几本书,其中谭浩强的那本《C语言程序设计(第四版...
    HavenXie阅读 1,667评论 1 6
  • 阅读及笔记时间:2016年12月4日,20:00-23:00;3小时; 阅读书本:《菊与刀》;作者:【美】鲁思·本...
    时空山庄阅读 387评论 0 6
  • 作为中国最大的搜索引擎,同时也是 BAT 中最臭名昭著的产品,百度搜索,我们每天都在使用,虽然已经有无数文章和你讲...
    尘飞FlyingDust阅读 1,570评论 5 9