zoukankan      html  css  js  c++  java
  • 【原】Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法(Matt Galloway著)读书笔记(二)

    第14条:理解 “类对象” 的用意

    对象类型并不是在编译期就绑定好了,而是要在运行期查找。在运行期检视对象类型的操作,叫做 “类型信息查询(内省)”

    元类

    在运行期程序库的头文件中,id 类型的定义:

    typedef struct objc_object {
        Class isa;
    } *id;
    

    每个对象结构体是首个成员是 Class 类的变量 isa,该变量定义了对象所属的类。

    在运行期程序库的头文件中,Class 类型的定义:

    typedef struct objc_class *Class;
    struct objc_class {
        Class isa;
        Class super_class;
        const char *name;
        long version;
        long info;
        long instance_size;
        struct objc_ivar_list *ivars;
        struct objc_method_list **methodLists;
        struct objc_cache *cache;
        struct objc_protocol_list *protocols;
    };
    

    定义:isa 指针所指向的类。
    作用:用来表述对象本身所具备的元数据。“类方法” 就定义在这里。

    在类继承体系中查询类型信息

    isMemberOfClass: 判断出对象是否为某个特定类的实例。
    isKindOfClass: 判断出对象是否为某类或者其派生类的实例。

    说明代码:

    NSMutableDictionary *dict = [NSMutableDictionary dictionary]; // 底层对象为:__NSDictionaryM
        NSLog(@"%d", [dict isMemberOfClass:[NSDictionary class]]); // NO
        NSLog(@"%d", [dict isMemberOfClass:[NSMutableDictionary class]]); // NO
        NSLog(@"%d", [dict isMemberOfClass:NSClassFromString(@"__NSDictionaryM")]); // YES
        NSLog(@"%d", [dict isKindOfClass:[NSDictionary class]]); // YES
        NSLog(@"%d", [dict isKindOfClass:[NSArray class]]); // NO
    

    像这样的类型信息查询方法使用 isa 指针获取对象所属的类,然后通过 super_class 指针在继承体系中游走。
    系统对象创建后,其元类并未创建时使用的类,系统将其转为一些底层类,如上面的 __NSDictionaryM
    自定义对象(继承NSObject),还是创建时的对象。

    类对象是单例,在用于程序范围内,每个类的 Class 仅有一个实例。
    自定义对象,通过 == 操作符也可判断出对象是否为某类的实例。

    id object = [EOCSomeClass new];
    if ([object class] == [EOCSomeClass class]) {
        ...
    }
    

    代理: 对象可能会把其受到的所有选择子转发给另一个对象,这个对象就是代理。这种对象均以 NSProxy 为根类。
    代理对象上调用 class 方法返回的是代理对象本身,而非接受代理的对象所属的类。

    总结: 尽量使用类型查询方法来确定对象类型,而不是直接比较对象,因为某些对象可能实现了消息转发功能。

    第三章:接口与 API 设计

    第15条:用前缀避免命名空间冲突

    问题:Objective-C 没有其他语言那种内置的命名空间机制,容易产生命名冲突。

    苹果宣称其保留使用所有 “两字母前缀” 的权利,所以我们在开发中最好使用三个字母的。

    若自己所开关的程序库中用到了第三方库,则应为其中的名称加上前缀。

    第16条:提供 “全能初始化方法”

    这种可为对象提供必要信息以便其能完成工作的初始化方法叫做 “全能初始化方法”。

    在类中提供一个全能初始化方法。其他初始化方法均应调用此方法。
    若全能初始化方法与超类不同,则需要覆写超类中的对应方法。

    第17条:实现 description 方法

    NSLog(@"object = %@", object)
    

    在构建需要打印到日志的字符串时,object 对象会收到 description 消息,该方法所返回的描述信息将取代 ”格式字符串“ 里的 ”%@“

    自定义对象在打印时,只能打印出对象的类名及地址,这些内容一般没有什么用。
    覆写 description 方法,可以打印自己所需要的内容。

    - (NSString *)description {
        return [NSString stringWithFormat:@"<%@: %p, %@>",
        [self class],
        self,
        @{@"参数1" : 参数1,
          @"参数2" : 参数2}
        ];
    }
    

    debugDescription 用于 debug 模式下 po 的打印。

    第18条:尽量使用不可变(对外只读)对象

    不可变:只读(read-only)
    可变:即可读又可写(read-write)

    尽量把对外公布出来的属性设置为只读,而且只在必要的时候才将属性对外公布。

    第19条:使用清晰而协调的命名方式

    起名时应遵从标准的 Objective-C 命名规范,这样创建出来的接口更容易为开发者所理解。

    第20条:为私有方法名加前缀

    好处:

    • 便于区分 公共方法私有方法
    • 便于修改 方法名方法签名

    建议:
    不要单用一个 _ 做私有方法的前缀,苹果公司就是这么用的,可能会覆写系统私有方法。建议使用 p_ 作为私有方法的前缀

    第21条:理解 Objective-C 错误模型

    第22条:理解 NSCopying 协议

    • copy:返回的拷贝对象与当前一致
    • immutableCopy:返回不可变的拷贝对象
    • mutableCopy:返回可变的拷贝对象

    第23条:通过委托与数据源协议进行对象间通信

    缓存方法响应能力缓存的最佳途径是使用 ”位段“ 数据类型。

    位段:

    struct data {
        unsigned int fieldA : 8; // 位段,占8个二进制位
        unsigned int fieldB : 4; // 位段,占4个二进制位
        unsigned int fieldC : 2; // 位段,占2个二进制位
        unsigned int fieldD : 1; // 位段,占1个二进制位
    };
    

    代理缓存:

    // 用于缓存委托对象是否能响应特地的选择子
    struct {
        unsigned int delegateMethdo1 : 1;
        unsigned int delegateMethdo2 : 1;
        unsigned int delegateMethdo3 : 1;
    } _delegateFlags;
    
    ...
    
    // 实现缓存功能所有的代码可以写在 delegate 属性所对应的设置方法里面
    - (void)setDelegate:(id<delegate类名>)delegate {
        _delegate = delegate;
        _delegateFlags.delegateMethdo1 = [delegate respondsToSelector:@selector(delegateMethdo1:)];
        _delegateFlags.delegateMethdo2 = [delegate respondsToSelector:@selector(delegateMethdo2:)];
        _delegateFlags.delegateMethdo3 = [delegate respondsToSelector:@selector(delegateMethdo3:)];
    }
    

    在以后调用代理方法的时候,直接使用结构体里面的标志进行判断即可。

    第24条:将类的实现代码分散到便于管理的数个分类之中

    第25条:总是为第三方类的分类名称加前缀

    在运行期系统加载分类时,会将分类中所实现的方法都加入到类的方法列表中,就好比这个类的固有方法。如果类中本来就有此方法,而分类中有实现了一次,那么分类中的方法会覆盖原来那一份实现代码。实际上可能会发生很多次覆盖,多次覆盖的结果以最后一个分类为准。

    为防止覆盖,将分类的名称和其中的方法名称加上前缀

    第26条:勿在分类中声明属性

  • 相关阅读:
    jackson 枚举 enum json 解析类型 返回数字 或者自定义文字 How To Serialize Enums as JSON Objects with Jackson
    Antd Pro V5 中ProTable 自定义查询参数和返回值
    ES6/Antd 代码阅读记录
    es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?
    Antd Hooks
    使用.Net Core开发WPF App系列教程(其它 、保存控件内容为图片)
    使用.Net Core开发WPF App系列教程( 三、与.Net Framework的区别)
    使用.Net Core开发WPF App系列教程( 四、WPF中的XAML)
    使用.Net Core开发WPF App系列教程( 二、在Visual Studio 2019中创建.Net Core WPF工程)
    使用.Net Core开发WPF App系列教程( 一、.Net Core和WPF介绍)
  • 原文地址:https://www.cnblogs.com/gfxxbk/p/12186732.html
Copyright © 2011-2022 走看看