OC之日常内存优化一

日常开发优化小常识

1. 在类的头文件中尽量少引入其他头文件
  • 除非确有必要,否则不要引用头文件。一般来说,应在某个类的头文件中使用向前声明(@class xxx)来提及别的类,并在实现文件中引入哪些类的头文件,这样做,可以避免两个类相互引用问题,可以尽量降低类之间的耦合(coupling)
  • 有时无法使用向前生命,比如要声明某个类遵循一项协议。这种情况下,尽量把“该类遵循某协议”的这条声明移至“class-continuation分类”中。如果不行的话,就把协议单独放在一个头文件中,然后将其引入
2.多用字面量语法,少用与之等价的方法
  • 字面数值:有时候需要把整数、浮点数、布尔值封入oc对象中,这种情况下可以用NSNumber,该类型可以处理多种类型的数值。
    不用字面量:NSNumber *someNumber=[NSNumber numberWithInt:1];
    使用字面量:NSNumber *intNumber=@1;
    NSNumber *[email protected];
    NUNuber *[email protected];

    NSNumber *boolNumber=@YES;

    NSNumber *charNumber=@'a';

    以上字面量来表示数值十分有用,这样做可以令NSNumber对象变得整洁,因为声明中只包含数值,而没有多余的语法成分。数组、字典类似

  • 应该使用字面量语法来创建字符串、数值、数组、字典。与创建此类对象的常规方法相比,这么做更加简明扼要

  • 应该通过取下标操作来访问数组下标或字典中的键所对应的元素

  • 用字面量语法创建数组或字典时,若值中有nil,则会抛异常,因此,务必确保值里不含nil

3.多用类型常量,少用#define预处理指令
  • 预处理执行原理:例如,视图播放动画,设置播放动画的时间为常量 #define ANIMATION_DUEATION 0.3 存在两个问题,a、不包含类型信息 b、预处理过程会把碰到的所有的ANIMATION_DUEATION一律替换成0.3,这样的话,假设此指令声明在某个头文件中,那么所有引入这个头文件的代码,其ANIMATION_DUEATION都会被替换
更优处理(利用编译器的某种特性)
  • static const NSTimeInterval kAnimationDuration = 0.3 此方式定义的常量包含类型信息(NSTimeInterval)
    变量一定要同时用static与const来声明。如果试图修改由const修饰符所声明的变量,那么编译器就会报错。在这个例子中,我们正式希望这样:因为动画播放时长为定值,所以不允许被修改。而static修饰符则意味着该变量仅在定义此变量的编译单元中可见。编译器没收到一个编译单元,就会输出一个“目标文件”(object file)。在oc的语境下,“编译单元”通常指每个类的实现文件(以.m为后缀名)。假如声明此变量时不假static,则编译器会为它创建一个“外部符号”(external symbol),此时,若是另外一个编译单元也声明了同名变量,那么编译器就会抛出一条错误信息: duplicat symbol _kAnimationDuration in :XXX SSS

延伸:有时候需要对外公开某个常量怎么办?

比如说:你可能要在类代码中调用NSNotificationCenter以通知他人。用一个对象来派发通知,令其他欲接收通知的对象向该对象注册,这样就能实现该功能。派发通知时,需要使用字符串来表示此项通知的名称,而这个名字就可以为一个外界可见的常值变量(constant variable),这样的话,注册者无需知道实际字符串值,只需要以常值变量来注册自己想要接收的通知即可。
此类常量需要放在“全局符号表”(global symbol table)中,以便可以在定义该常量的编译单元之外使用。因此,其定义方式与static const有所不同。
.h里面:extern NSString *const EOCStringConstant;
.m里面:NSString *const EOCStringConstant=@"value";

这种常量在头文件中“声明”,且在实现文件中“定义”,常量定义应该从右至左解读。所以在本例中:EOCStringConstant就是“一个常量,而这个常量是指针,指向NSString对象”。这与我们的需求相符,发通知的时候,我们不希望有人改变此指针常量,使其指向另一个NSString对象。

编译器看到头文件中的extern关键字,就会告诉编译器,在全局符号表中将会有一个名叫EOCStringConstant的符号。也就是,编译器无须查看其定义,就可以允许代码使用此变量。因为它知道。当链接成二进制文件之后,肯定能找到这个常量。
原理解释:此类常量必须要定义,而且智能定义一次。通常将其定义在声明该常量的头文件相关的实现文件里。由实现文件生成目标文件时,编译器会在“数据段”(data section)为字符串分配存储空间。链接器会把此目标文件与其他目标文件相链接,以生成最终的二进制文件。凡事用到EOCStringConstant这个全局符号的地方,链接器都能将其解析。

要点总结
  • 不要用预处理指令定义常量。这样定义出来的常量不包含类型信息,编译器只是会在编译前执行查找与替换操作。即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致
  • 在实现文件中使用 static const来定义 “只在编译单元内可见的常量”(translation-unitspecific constant)。由于此类常量不在全局符号表中,所以无须为其名称加前缀
  • 在头文件中使用extern来声明全局变量,并在相关实现文件中定义其值。这种常量要出现在全局符号表中,所以其名称应加以区隔,通常用与之相关的类名做前缀【比如:系统UIKit就按照这种方式来声明用作通知名称的全局变量,类似:UIApplicationDidEnterBackgroundNotification、UIApplicationWillEnterForegroundNotification这样的常量名】

你可能感兴趣的:(OC之日常内存优化一)