iOS不可错过的关键字
建议查看原文:https://www.songma.com/p/dce05b24d288(不定时升级)
本文概览
前言:我们看源码,或者者面试经常遇到少量关键字,又因为网上的相关文章部分观点错误,我在此汇总了我之前的笔记以及查阅相关书籍,站在巨人的肩膀上,整合出此篇文章。
总之,为了提升,为了面试,理解这些关键字,非常有必要。每个观点,我尽可能的结合代码讲解。
extern
当编译器遇到
extern
模板公告时,它不会在本文件中生成实例化代码,将一个实例化公告为extern
就表示承诺在程序的其余位置有该实例化的一个非extern
定义。对于一个给定的实例化版本,可能有多个extern
公告,但必需只有一个定义。
1、在其余文件(DWConst
)的实现文件公告变量
// DWConst.m// 定义了整个程序都能访问的常量const NSString *myExtern = @"abc";@implementation DWConst@end
2、在 ViewController
类赋值并打印(不用导入DWConst.h
)
// ViewController.m NSLog(@"myExtern=%@", myExtern); NSLog(@"myExtern 地址=%p", &myExtern); myExtern = @"hello"; NSLog(@"myExtern=%@", myExtern); NSLog(@"重新赋值后的myExtern 地址=%p", &myExtern);
打印:
myExtern=abc
myExtern 地址=0x108aaf180
myExtern=hello
重新赋值后的myExtern 地址=0x108aaf180
定义后,无论后面怎么使用,都只是共用一个内存地址(看上面打印),也表明任意一处改变值,都会影响其余处。
static
1、修饰全局变量
- 全局变量的作用域仅限于当前文件(限制作用域)
2、修饰局部变量(下面3个作用,自我觉得,实质是一样的)
- 保证只会开拓一个内存
- 只会初始化一次
- 没有改变局部变量的作用域,仅仅是改变了局部变量的生命周期(直到程序结束,这个局部变量才会销毁)
- (void)viewDidLoad { NSLog(@"----------------- ViewDidLoad -----------------"); [self testStatic];}// 已省略按钮创立代码- (void)btnClicked { NSLog(@"----------------- btnClicked -----------------"); [self testStatic];}- (void)testStatic { NSInteger i = 0; i++; static NSInteger staticValue = 0; staticValue++; NSLog(@"i的地址=%p,staticValue的地址=%p", &i, &staticValue);}
打印:
—————– ViewDidLoad —————–
i的地址=0x7ffee2200948,staticValue的地址=0x10d9ff1c8
—————– btnClicked —————–
i的地址=0x7ffee2200fd8,staticValue的地址=0x10d9ff1c8
由此看出,staticValue 的地址没有变,证实了 ”保证只会开拓一个内存“
把 NSLog(@"i的地址=%p,staticValue的地址=%p", &i, &staticValue);
替换成NSLog(@"i = %ld, s.value = %ld", (long)i, (long)staticValue);
打印:
—————– ViewDidLoad —————–
i = 1, s.value = 1
—————– btnClicked —————–
i = 1, s.value = 2
由此看出,staticValue 的有 +1,而 i 永远都是 1,证实了 static 关键字修饰局部变量”延长了公告周期“,由于 i 没修饰,则每次都重新创立,再 +1
const
至于 const
,我先给出例子:
const int *p = NULL; *p = 20; // 报错
*p 会报错 ,被 const 修饰的 *p 只能被赋值一次, 再次赋值,就会报错 “Read-only variable is not assignable”
int a = 10; p = &a; // 正常通过 NSLog(@"*p=%d", *p); NSLog(@"p=%p", p);
打印:
*p=10
p=0x7ffeec2a9a04
int * const p1 = NULL; NSLog(@"p1=%p", p1); *p1 = 30; // 编译通过,但运行报错
看清楚!p 还是可以修改的,不同于 *p 。由于 const 修饰的是 *p ,而不是 p
*p 和 p 的区别:
*p 是存储的值,而 p 是指针。上例中,p 指针,则存储着 a 的内存地址,而 *p 等于10。
同样,在 id 类型的运用
NSString * const city = @"CN"; city = @"US"; // 报错,
const 修饰的 city 为只读属性
static 和 const 的配合
1、使用
static const CGFloat Height = 180;static const CGFloat author = @"Dwyane";
2、与 #define
的比照
- 共同点:一旦定义,都不允许修改
- 不同点:
static const
修饰变量只有一份内存,检查数据类型;#define
仅仅简单文字替换,不会检查类型,每次使用都需要创立一份内存
inline 内联函数
1、使用
static inline int DWMax(int x, int y) { return (x > y)? x : y;}- (void)viewDidLoad { int i = DWMax(20, 30); NSLog(@"max = %d", i);}
普通函数的好处与缺点
2、引入内联函数的目的
对于少量函数体代码不是很大,但又频繁地被调用的函数来讲,处理其效率问题更为重要。引入内联函数实际上就是为理解决这一问题。
3、滥用内联函数的弊端
滥用内联将导致程序变慢. 内联可能使目标代码量或者增或者减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的添加代码大小. 现代解决器因为更好的利用了指令缓存, 小巧的代码往往执行更快。
注意:内联函数只是我们向编译器提供的申请,编译器不肯定采取inline形式调用函数.另外,假如不申请,编译器会选择性的自动会汇编成内联函数
结论: 一个较为正当的经验原则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 由于有隐含的成员和基类析构函数被调用!
另一个实用的经验原则: 内联那些包含循环或者 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或者 switch 语句从不被执行). –>参考
inline 函数与 #define 比较
建议也看宏与普通函数的区别
inline
函数与#define
区别:
1、 宏调用并不执行类型检查,甚至连正常参数也不检查,但是函数调用却要检查。
2、 C语言的宏使用的是文本替换,可能导致无法意料的后果,由于需要重新计算参数和操作顺序。
3、 许多结构体使用宏或者者使用不同的语法来表达很难了解。内联函数使用与普通函数相同的语言,可以随便的内联和不内联。
4、 内联代码的调试信息通常比扩展的宏代码更有用。
Static参考
内联函数的参考
iOS OC内联函数 inline
上一篇 目录 已是最后
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » iOS不可错过的关键字