《Effective Objective-C 2.0编写高质量i

作者: Mr_WangZz | 来源:发表于2018-11-05 17:49 被阅读0次

    1. 了解OC语言的起源

    知识点

    1. OC: 消息型类型,使用消息结构,其运行时所应执行的代码由 运行环境 决定;
    2. 而使用函数调用的语言,则由 编译器 决定。
    3. 对象所占内存总是分配在 堆空间,而绝不会在栈上。
    4. 上保存的是指向对象的指针。
    5. 定义里不含 “ * ” 的变量(非对象类型),可能会被分配到 栈 上,如CGRect。它是C 结构体。

    要点总结

    • Objective-C 为 C 语言添加了 面向对象 的特性,是其超集。Objective-C使用 动态绑定的消息结构 。所以,在运行时 才会检查对象类型。接收一条消息之后,究竟应执行何种代码,由运行时环境决定,而非编译器。

    • 理解C语言的核心概念(重点是内存模型指针)有助于写好OC程序。

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

    想要在一个文件中引入另一个(如Model:Person.h)类,且只需要知道类名,可以:

    //#import "Person.h"
    @class Person;
    

    这种写法,叫“向前声明”该类。总结:

    除非有必要,否则不要引入头文件。一般来说,应在某个类的 (xxxx.h)头文件 中使用 向前声明 来提及别的类,并在 (xxxx.m)实现文件 中引入那些类的头文件。这样做 可以尽量降低类之间的耦合(coupling)

    有时无法使用向前声明,如声明某个类遵循一项协议。这种情况下,尽量把 “该类遵循某协议” 的这条声明移至 “class-continuation分类” 中。如果不行的话,就把协议单独放在一个头文件中,然后将其引入。见27条

    3. 多用字面量语法,少用与之等价的方法

    知识点

    1. 使用字面量语法(Literal syntax)可以缩短源代码长度,使之更为易读。如
    • 字面数值
    /** 1 */
    NSString *someString1 = [[NSString alloc] initWithString:@"I'm wanazen"];
    //可简写为:
    NSString *someString2 = @"I'm wanazen";
    
    /** 2 */
    NSNumber *someNumber = [NSNumber numberWithInt:1];
    //可简写为:
    NSNumber *intNumber = @1;
    NSNumber *doubleNumber = @3.14159;
    NSNumber *boolNumber = @YES;
    NSNumber *charNumber = @'a';
    
    int x = 5;
    float y = 8.99f
    NSNumber *expressionNumber = @(x * y) ;
    
    • 字面量数组
    /** 创建 */
    NSArray *animals = [NSArray arrayWithObjects:@"cat", @"dog", @"mouse", nil];
    //可简写成
    NSArray *animalsNew = @[@"cat", @"dog", @"mouse"];
    
    /** 取值 */
    NSString *cat = [animals objectAtIndex:0];
    //可简写为
    NSString *catNew = animalsNew[i];
    
    • 字面量字典
    /** 创建 */
    NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"Wanazen",@"firstName", @"Lona", @"lastName", [NSNumber numberWithInt:2019], @"year"];
    //可简写为
    NSDictionary *dic2 = @[@"firstName":@"Wanazen", @"lastName":@"Lona", @"year":@2019];
    
    /** 取值 */
    NSString *firstName = [dic objectForKey:@"firstName"];
    //可简写为
    NSString *firstName2 = dic[@"firstName"];
    
    //赋值操作可以写成字面量。
    
    1. 字面量语法实际上只是一种“语法糖”(syntax sugar),其效果等于是 先创建了一个对象,然后执行了那些简写之前的操作。
    2. 数组、字典等一旦有值为nil时,可能会抛出异常。
    3. 限制:除了字符串之外,所创建出来的对象必须属于Foundation框架才行。
    4. 使用字面量创建出来的字符串、数组、字典对象都是不可变的(immutable)。若想创建可变版本的对象,则需要复制一份。
    //虽然会多调用一个方法,还要在创建一个对象,不过优大于劣
    NSMutableArray *mutableArray = [[@1, @2, @3, @4] mutableCopy];
    

    要点总结:

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

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

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

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

    优化前的目标代码:

    #define ANIMATION_DURATION 0.3
    
    1. 只在文件内(.m)使用 的写法:
    /*
    升级的写法. 
    根据实际数据类型声明常量。
    const:不允许修改。修改后编译器报错
    static:局限在编译单元.m文件中
    */
    static const NSTimInterval kAnimationDuration = 0.3;
    
    1. 在被引入的文件同样生效(对外开放) 的写法:
    //在.h文件 - 声明
    
    // LoginManager.h
    #import <Foundation/Foundation.h>
    
    extern NSString *const LoginManagerDidLoginNotification;
    
    @interface LoginManager()
    ***
    @end
    
    //在.m文件 - 定义
    // LoginManager.m
    
    #import "LoginManager.h"
    
    NSString *const LoginManagerDidLoginNotification = @"LoginManagerDidLoginNotification";
    
    @implementation LoginManager
    ***
    @end
    

    常用的命名法:

    • 若常量局限在.m文件中,以 “k” 开头;
    • 在类之外可见,常以 类名 开头。
    要点总结:
    • 不要使用预处理指令(#define)定义 常量 。这样定义出来的常量不含类型信息,编译器只是会在编译前据此执行查找和替换操作。即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致。

    • 在实现文件(.m)中使用 static const 来定义 “只在编译单元内可见的常量”。由于此类常量不在全局符号表中,所以无需为其名称加前缀。

    • 在头文件中使用 extern 来声明全局常量,并在相关实现文件中定义其值。这种常量药出现在全局符号表中,所以其名称应加以区隔,通常用与之相关的类名做前缀。

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

    由于 OC 基于 C 语言,所以 C 语言有的功能它都有。枚举(ENUM),是一种常量的命名方式。

    /**
     C语言下的语法
    */
    enum EOCConnectionStateConnectionState {
        EOCConnectionStateDisConnected = 1,
        EOCConnectionStateConnecting,
        EOCConnectionStateConnected,    
    };
    
    /**
     OC中
    */
    typedef NS_ENUM(NSUInteger, EOCConnectionState) {
        EOCConnectionStateDisConnected,
        EOCConnectionStateConnecting,
        EOCConnectionStateConnected,    
    };
    
    //适用于 按位或操作来组合 的枚举
    typedef NS_OPTIONS(NSUInteger, EOCPermittedDirection) {
        EOCPermittedDirectionUp = 1 << 0,
        EOCPermittedDirectionDown = 1 << 1,
        EOCPermittedDirectionLeft = 1 << 2,
        EOCPermittedDirectionRight = 1 << 3,
    };
    
    要点总结:
    • 应该用 枚举 表示状态机的状态传递给方法的选项以及状态码等值,给这些值起简单易懂的名字。

    • 如果把传递给 某个方法的选项 表示为枚举类型,而多个选项又可同时使用,那么就将各选项定义为2的幂对应的值,便于按 操作组合使用。

    • NS_ENUMNS_OPTIONS 宏 来定义枚举类型,并指明其底层数据类型。可以确保枚举是用开发者所选的底层数据类型实现的,而不会采用编译器所选的类型。

    • 在处理枚举类型的switch语句中不要出现 default分支 。这样在加入新枚举值之后,编译器会提示开发者:在switch语句中并未处理所有枚举。

    系列文章

    相关文章

      网友评论

        本文标题:《Effective Objective-C 2.0编写高质量i

        本文链接:https://www.haomeiwen.com/subject/ittexqtx.html