Effective Objective-C 2.0 笔记(一)

编写高质量的 iOS 和 OS X 代码的52个有效办法-读书笔记

最近在读Effective Objective-C 2.0,想做一下记录,我是挑选自己感兴趣的,和书中的顺序不一样,看到那写到哪

第4条:多用类型常量,少用 #define 预处理命令

在定义常量的时候,我们通常需要确定一下几件事:

  1. 常量代表的含义
  2. 常量的作用域
  3. 什么样的常量的命名方式简单易懂?

如果我们定义个动画时间的时候,我们通常会这么定义

#define ANIMATION_DURATION 0.3

这么定义的缺点是

  • 常量代表的含义不清晰,未明确指出0.3与时间有关.
  • 常量的作用域过大,预处理过程会把碰到所有的ANIMATION_DURATION一律替换成0.3,这样的话,假设此指令声明在某个头文件中,那么引入这个头文件的代码中的ANIMATION_DURATION都会被替换掉,所以说即使你使用#define定义常量,也要放在 .m文件里
  • 什么样的常量的命名方式简单易懂?,这种命名方式,没有规范,下面会介绍一下规范的定义常量

正确的定义方式应该按照下面两种方式:

第一,常量的作用域仅在当前类,即局部常量

//in the implementation file - EOCAnimatedView.m
static const NSTimeInterval kAnimationDuration = 0.3;

第二,常量的作用域在所有引用了当前类的代码中,即全局常量

//in the header file - EOCAnimatedView.h
extern const NSTimeInterval EOCAnimatedViewAnimationDuration;

//in the implementation file - EOCAnimatedView.m
const NSTimeInterval EOCAnimatedViewAnimationDuration = 0.3;

为什么要这样定义呢?

  1. 常量代表的含义明确,0.3与时间有关,所以我们用NSTimeInterval表示,这样容易让人理解
  2. 常量的作用域明确,常量的作用域仅在当前类时,我们用第一种方法定义,常量的作用域在所有引用了当前类的代码中,即全局变量我们用第二种方式定义
  3. 什么样的常量的命名方式简单易懂?若某常量局限于编译单元(translation unit) 也就是"实现文件"即.m文件,则在前面加字母k,因为局部变量仅在当前类使用,所以不用加以区分,若常量在类外可见,则通常以类名为前缀,因为全局常量加入到全局常量表中,必须用类名加以区分

为什么我们不能在.h文件里面定义局部常量?

局部常量的定义不应该出现在.h文件里,因为 OC 没有 namespace 这个概念,所有引入这份头文件的其他文件都会出现这个名字,如果在局部常量的定义出现在.h文件里,就等于声明了一个kAnimationDuration全局常量

为什么常量的作用域仅在当前类时,我们用第一种方法定义?

因为static 修饰符意味着该常量仅定义在定义该常量的编译单元中(.m)可见, 编译器每收到一个编译单元,就会输出一份目标文件(object file),如声明此常量不加static,编译器会为它创建一个外部符号(external symbol), 此时,另一个编译也声明了同名变量,那么编译器就会报错.

为什么常量的作用域在所有引用了当前类的代码中,即全局变量我们用第二种方式定义?

全局常量需要放在全局符号表(global symbol table) 中,这种常量的定义是在头文件声明,在实现文件里定义,这样,编译器在使用此常量的时候无需查看其定义,即允许代码使用此常量,因为他知道,当链接成二进制文件之后,肯定能找到这个常量.

Note:

  • 常量的定义应该从右到左解读
  • 使用第二种定义优于使用#define,因为#define定义出来的常量不含类型信息,编译器只会在编译前据此执行查找与替换操作,即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致

你可能感兴趣的:(Effective Objective-C 2.0 笔记(一))