首页 > 代码库 > Effective Objective -C 第一章 熟悉iOS

Effective Objective -C 第一章 熟悉iOS

Objective-C 使用的是“消息结构”,使用消息结构与函数调用的语言关键区别在于:使用消息结构的语言,其运行时所应执行的代码由运行环境来决定;而使用函数调用的语言,则有编译器决定。


  1. 运行期组件(runtime component)----动态库(dynamic library)Objective-C是C语言的"超集"(superset),OC中的指针是用来指示对象的。OC使用的动态绑定的消息结构,也就是说,在运行时才会检查对象类型。接受到消息之后,究竟应执行何种代码,由运行期环境而非编译器来决定。

      NSString *someString = @"The String"; 

      声明一个名为someString 的变量,它的 类型是NSString *,也就是说,此变量为指向NSString的指针。所有OC语言的对象都必须这样声明,因为对象所占内存总是分配在"堆空间"(heap space)中,而绝不会分配在"栈"(stack)上。

      NSString *anotherString = someString;

    两个变量指向同一个实例"The String",两个变量都是NSString*类型的,说明当前"栈帧"里分配了两块内存,每块内存的大小都能容下一枚指针。两块内存里的都是一样,就是NSString实例的内存地址。

技术分享

  分配在堆中的内存必须直接管理,而分配在栈上用于保存变量的内存则会在其栈帧弹出时自动清理。

  OC中定义不含*的变量,它们可能会使用”栈空间“。这些变量保存的不是OC对象。


 

2. 在类的头文件中尽量少引入其他头文件

  •  除非确有必要,否则不要引入头文件。一般来说,应在某个类的头文件中使用前置声明来提及别的类,并在实现文件中引入那些类的头文件。这样做可以尽量降低类之间的耦合(coupling)。
  • @class + 类名
  •  有时无法使用前置声明,比如要声明某个类遵循一项协议。这种情况下,尽量吧"该类遵循某协议"的这条声明移至"class-continuation 分类"中。如果不行的话,酒吧协议单独放在一个头文件中,然后将其引入。 

3.多用字面量(literal)语法、少用与之等价的方法

  • 应该使用字面量语法来创建字符串、数组、字典。与创建此类对象的常规方法相比,这么做更贱简明扼要。
  • 应该通过去下标操作来访问数组下标或字典中的键所对应的元素。
  • 用字面量语法创建数组或字典是,若值中有nil,则会抛出异常。因此,务必确保值里不含nil。
  • 例如:字面量字符串 NSString *someString = @"This is a 葫芦娃";

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

  • 常量命名规则:若常量局限于某"编译单元(也就是实现文件)"之内,则在前面加字母k;若常量在类之外可见,则通常以类名为前缀。
  • 若不打算公开某个常量,则应将其定义在使用该常量的实现文件里
  • static const NSTimeInterval kAnimationDuration = 0.3;
  • 变量一定要同时用static与const 来声明。如果试图修改由const 修饰符所声明的变量,那么编译器就会报错。而static 修饰符则意味着该变量仅在定义次变量的编译单元中可见。在OC中,”编译单元“一词通常指每个类的实现文件。假如声明次变量是不加static,则编译器会为它创建一个”外部符号(external symbol)“.此时若是另一个编译单元中也声明了同名变量,那么编译器就抛出一条错误消息:duplicate symbol _kAnimationDyration in:重复定义的两个.m文件中。如果一个变量既声明为static,又声明为const,那么编译器根本不会创建符号,而是会想#define预处理指令一样,把所有遇到的变量都替换为常值。但是用这种方式定义的常量带有类型信息。
  • 有时候需要对外公开某个常量。比如派发通知时,通知的名称。此常量需要放在"全局符号表(global symbol table)"中,以便可以在定义该常量的编译单元之外使用。

    extern NSString *const stringConstant;// In the header file

    NSString *const stringConstant = @"Value";// In the implemention file

    这个常量在头文件中"声明",且在实现文件中"定义"。注意:const 修饰符在常量类型中的位置。常量定义应从右至左解读,即stringConstant就是"一个常量,而这个常量是指针,指向NSString对象"。

  • 不要用预处理指令定义常量。这样定义出来的常量不含类型信息,编译器只是会在编译钱据此执行查找与替换操作。即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致。
  • 在实现文件中使用static const来定义"只在编译单元内可见的常量"。由于此类常量不在全局符号表中,所以无须为其名称加前缀。
  • 在头文件中使用extern来声明全局常量,并在相关实现文件中定义其值。这种常量要出现在全局符号表中,所以其名称应加以区别,通常用与之相关的类名做前缀。

5.用枚举表示状态、选项、状态码

  • 枚举只是一种常量命名方式。某个对象所经历的各种状态就可以定义为一个简单的枚举集。实现枚举所用的数据类型取决于编译器,不过其二进制位(bit)的个数必须能完全表示下枚举编号才行。

    typedef enum EOCConnectionState EOCConentionState;就是用简写的 EOCConentionState 来代替完整的enum EOCConnectionState。

  • 凡是需要以按位或操作来组合的枚举都应使用NS_OPTIONS定义,若是枚举不需要相互组合,则应使用NS_ENUM来定义。
  • 应该用枚举来表示状态机的状态、传递给方法的选项以及状态码等值,给这些值起一个易懂的名字。
  • 如果把传递给某个方法的选项表示为枚举类型,而多个选项又课同事使用,那么就将个选项值定义为2的幂,以便通过按位或操作将其组合起来。
  • 用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。这样做可以确保枚举使用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。
  • 在处理枚举类型的switch语言中不要实现default分支。这样的话,加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有的枚举。

 

Effective Objective -C 第一章 熟悉iOS