编写高质量的OC代码--------熟悉Objective-C

来源:互联网 发布:h5能打开淘宝app吗 编辑:程序博客网 时间:2024/05/17 20:33
    第1条:了解Objective-C语言的起源
        1、Objective-C的消息结构
    Objective-C使用“消息结构”而非“函数调用”。消息结构与函数调用的关键区别在于:使用消息结构的语言,其运行时所应执行的代码由运行环境来决定;而使用函数调用的语言,由编译器决定。如果函数调用是多态的,那么在运行时就要按照“虚方法表”来查出到底应该执行哪个函数实现。而采用消息结构的语言,不论是否多态,总是在运行时才会去查所要执行的方法。实际上,编译器甚至不关心接收消息的对象是何种类型。接收消息的对象问题也要在运行时处理,其过程叫做“动态绑定”。
        2、Objective-C的运行时库
    Objective-C的重要工作都由“运行时库”而非编译器完成的。运行时库提供了Objective-C的面向对象的能力,使用Objective-C的面向对象特性所需的全部数据结构及函数都是由“运行时库”提供的。举例来说,运行期组件中含有全部内存管理方法。
        3、Objective-C的内存模型
      Objective-C中的对象是以指针来指示的。想要声明一个变量,令其指代某个对象,可用以下语法:
        NSString * someStr = @“The string”;
      这种语法基本上是照搬C语言的,它声明了一个名为someString的变量,其类型是NSString*。也就是说,此变量为指向NSString的指针。所有Objective-C语言的对象都必须这样声明,因为对象所占内存总是分配在“堆空间”中,而绝不会分配在“栈”上。不能在栈中分配Objective-C对象。  
        如下代码:
        NSString * someStr = @“The string”;
        NSString * anothreStr = someStr;
        只有一个NSString实例,然而又两个变量指向此实例。两个变量都是NSString* 型,这说明当前“栈帧”里分配了两块儿内存,每块内存的大小都能容下一枚指针(在32位架构的计算机上是4字节,64位计算机上是8字节)。这两块儿内存里的值都一样,就是NSString实例的内存地址。
        分配在堆中的内存必须直接管理,而分配在栈上用于保存变量的内存则会在其栈帧弹出时自动清理。
        Objective-C将对内存管理抽象了出来。不需要用malloc及free来分配或释放内存。Objective-C运行时环境把这一部分工作抽象为一套内存管理架构,名叫“引用计数”。
        如果只是保存int、float、double、char等非对象类型,那么通常使用CGRect这种结构体就可以了。CGRect是C语言结构体。保存在栈上。整个系统框架都在使用这种结构体,因为如果改用Objective-C对象来做的话,性能会受到影响。与创建结构体相比,创建对象还需要额外开销,例如分配及是否堆内存等。

    第2条:在类的头文件中尽量少引用其他头文件
    1.        将引入头文件的时机尽量延后,只在确有需要时才引入,这样就可以减少类的使用者所需引入的头文件梳理。缩短编译时间。
    2.        向前声明可以解决两个类循环引用的问题,当两个类循环引用的时候。使用#import而不是#include虽然不会导致死循环,但却意味着两个类里有一个无法被正确编译。
    3.          有时候必须要在头文件中引用其他头文件。如果你写的类继承自某个超类,则必须引入定义那个超类的头文件。同理,如果要声明你写的类继承自某个超类,那么必须由完整的定义,且不能使用向前声明。向前声明只能告诉编译器有某个协议,而此时编译器却要知道该协议中定义的方法。所以协议通常声明在一个单独的文件中(代理协议除外,代理协议单独声明是没有任何意义的)。

    第3条:多用字面量语法,少用与之等价的方法
    字面量语法实际上只是一种“糖衣语法”,其效果与常规语法等效但是开发者用起来却更加方便。“糖衣语法”可令程序更易读,减少代码出错几率。
        要点:
        1、应该使用字面量语法来创建字符串、数值、数组、字典。与创建此类对象的常规方法相比,这么做更加简明扼要。
        2、应该通过取下标操作来访问数组下标或字典中的键所对应的元素。
        3、用字面量语法创建数组或字典时,若值中有nil,则会抛出异常。因此,务必确保值里不含nil。      
      字面量语法的局限性:
        1、所创建出的对象必须属于Foundation框架。要想创建自定义子类实例,必须采用“非字面量语法”。
        2、字面量语法创建出来的字符串、数组、字典对象都是不可变的。若想要可变版本的对象,则需赋值一份:
    NSMutableArray * mutable = [@[@1,@2,@3,@4]mutableCopy];
    
      第4条:多用类型常量,少用#define预处理指令
    以如下预处理为例为例:
    #define ANIMATION_DURATION0.3
    1、预处理指令不携带类型信息,类型常量携带类型信息。
    2、预处理指令作用域不明确,假设该指令声明在某个头文件中,那么所有引入了这个头文件的代码,其ANIMATION_DURATION都会被替换
  3、即使有人重新定义了常量值,编译器也不会产生警告,这将导致应用程序中的常量值不一致。

  在实现文件中定义“只在编译单元内可见的常量”
staticconstNSTimeInterval kAnimationDuration =0.3;
  变量一定要同时用static和const来声明。const确保变量不可变,static则意味着该变量仅在定义此变量的编译单元中可见。假如声明此变量时不加static,则编译器会为它创建一个“外部符号”。此时若是另一个编译单元中也声明了同名变量,那么编译器会报错。实际上,若干一个变量即声明为static,又声明为const,那么编译器根本不会创建符号,而是会像#define预处理指令一样,把所有遇到的变量都替换为常值。不过还是要记住:用这种方式的常量带有类型信息。
  有时需要对外公开某常量。此类常量需放在“全局符号表”中,以便可以在定义该常量的编译单元之外使用。应该这样来定义

//In the header file
externNSString *const EOCStringConstant;

//In the implementation file
NSString *const EOCStringConstant =@"VALUE";
    这种常量要出现在全局符号表中,所以其名称应加以区隔,通常用与之相关的类名做前缀。总之,勿使用预处理指令定义常量,而应借助编译器来确保常量正确。
    
  第5条:枚举的使用
    C++11标准修订了枚举的某些特性。其中一项改动是:可以指明用何种“底层数据类型”来保存枚举类型的变量。这样做的好处是,可以向前声明枚举变量了。若不指定底层数据类型,则无法向前声明枚举类型。因为编译器不清楚底层数据类型的大小,所以在用的此枚举类型时,也就不知道究竟该给该变量分配多少内存空间。
    如果把传递给某个方法的选项表示为枚举类型,而多个选项又可同时使用,那么就将各选项值定义为2的幂,以便通过按位或操作将其组合起来。
    用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。这样做可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。
    在处理枚举类型的switch语句中不要实现default分支。这样的话,加入新枚举之后,编译器就会提示开发者:switch语言并未处理所有枚举

   
原创粉丝点击