iOS不可错过的关键字

建议查看原文:https://www.jianshu.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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏企鹅号快讯

看完这篇文章就能当Python工程师

有句话说得好,不想做程序员的司机不是好厨师!用十分钟看完小编整理的这篇文章,分分钟钟教你做司机...不是,是厨师...哦也不是,是程序猿! 在这里我还是要介绍一...

21850
来自专栏微信公众号:Java团长

Java堆和栈的区别

在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作...

26230
来自专栏coolblog.xyz技术专栏

Dubbo 源码分析 - 自适应拓展原理

我在上一篇文章中分析了 Dubbo 的 SPI 机制,Dubbo SPI 是 Dubbo 框架的核心。Dubbo 中的很多拓展都是通过 SPI 机制进行加载的,...

12020
来自专栏程序员互动联盟

【基础编程】聊聊C语言-变量的寿命

上一篇在编程世界的容器中,我们讲述了程序中的数据都存储在变量中,而变量根据数据类型的不同所占用的内存大小也不一样。但是计算机的内存大小是有限的不可能无限的分配下...

39470
来自专栏轮子工厂

5. 很“迷”的字符与字符串

最近一直在为自己的浏览量而担忧啦,都快被厂长大人约谈了……我真的有尽力在写稿子哦,所以也请各位老铁,如果觉得我的文章还不错就转发到朋友圈或者微信群之类的,让更多...

12720
来自专栏前端布道

JavaScript设计模式与开发实践 - 高阶函数的应用

定义 高阶函数是指至少满足下列条件之一的函数: 函数可以作为参数被传递; 函数可以作为返回值输出。 JavaScript语言中的函数显然满足高阶函数的条件,在实...

32830
来自专栏noteless

[三]java8 函数式编程Stream 概念深入理解 Stream 运行原理 Stream设计思路

        流不是存储元素的数据结构;相反,它通过一个计算操作的管道,从一个数据源,如数据结构、数组、生成器函数或i/o通道中传递元素

43250
来自专栏智能算法

Python学习(三)---- 集合、文件操作、字符编码和函数

https://blog.csdn.net/fgf00/article/details/52167245

10720
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础-day01-基础题

1. 简述java语言,具有哪些特性? (1).java语言是简单的 java语言是和c++语言类似的,其次java中丢弃了c++中一些难理解的特性,比如运算符...

28740
来自专栏Python小屋

详解Python字符串编码格式

最早的字符串编码是美国标准信息交换码ASCII,仅对10个数字、26个大写英文字母、26个小写英文字母及一些其他符号进行了编码。ASCII采用1个字节来对字符进...

27260

扫码关注云+社区

领取腾讯云代金券