Effective Objective-C 2.0读书笔记(二)

2018-06-28  本文已影响17人  lattr

对象、消息、运行期

“对象”就是“基本构造单元”(building block),开发者可以通过对象来存储并传递数据。在对象之间传递数据并执行任务的过程就叫做“消息传递”(Messageing)。

当程序运行起来后,为其提供相关支持的代码叫做“Objective-C运行期环境”。

6.理解“属性”这一概念

7.在对象内部尽量直接访问实例变量

在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。

在初始化方法及dealloc方法中,总是应该直接通过实例变量来读写数据。

有时会使用惰性初始化技术配置某份数据,这种情况下,需要通过属性来读取数据。

8.理解“对象等同性”这一概念

==操作符比较的是两个指针本身,而不是其所指的对象。

若想检测对象的等同性,请提供“isEqual:”与“hash”方法。

相同的对象必须具有相同的哈希码,但是两个哈希码相同的对象却未必相同。

不要盲目的逐个检测每条属性,而是应该依照具体需求来制定检测方案。

编写hash方法时,应该使用计算速度快而且哈希码碰撞几率低的算法。

9.以“类簇模式”隐藏实现细节

“类簇”(class cluster)是一种很有用的模式(pattern),可以隐藏“抽象基类”(abstract base class)背后的实现细节。

系统框架中普遍使用此模式。比如UIKit中的UIButton,Cocoa里的collection如NSArray与其可变版本NSMutableArray。

从类簇的公共抽象基类中继承子类时要当心,若有开发文档,则应首先阅读。

10.在既有类中使用关联对象存放自定义数据

可以通过“关联对象”机制来把两个对象连起来。

定义关联对象时可指定内存管理语义,用以模仿定义属性时所采用的“拥有关系”与“非拥有关系”。

只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难于查找的bug。

11.理解objc_msgSend的作用

12.理解消息转发机制

若对象无法响应某个选择子,则进入消息转发流程。

通过运行期的动态方法解析功能,我们可以在需要用到某个方法时再将其加入类中。

+ (BOOL)resolveClassMethod:(SEL)sel;
+ (BOOL)resolveInstanceMethod:(SEL)sel;

对象可以把其无法解读的某些选择子转交给其他对象来处理。

- (id)forwardingTargetForSelector:(SEL)aSelector;

经过上述两部之后,如果还是没办法处理选择子,那就启动完整的消息转发机制。

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;

13.用“方法调配技术”调试“黑盒方法”

在运行期,可以向类中新增或替换选择子所对应的方法实现。

使用另一份实现来替换原有的方法实现,这道工序叫做“方法调配”,开发者常用此技术向原有实现中添加新功能。

    SEL sel_classMethod = @selector(classMethod);
    SEL sel_hook_classMethod = @selector(hook_classMethod);
    
    Class metaClass_obj = object_getClass(self);//元类对象
//    Class class_obj = objc_getClass([[[self class] description] UTF8String]);//类对象
    
    Method m_classMethod = class_getClassMethod(metaClass_obj, sel_classMethod);
    Method m_hook_classMethod = class_getClassMethod(metaClass_obj, sel_hook_classMethod);
    
    BOOL isAdd = class_addMethod(metaClass_obj,
                                 sel_classMethod,
                                 method_getImplementation(m_hook_classMethod),
                                 method_getTypeEncoding(m_hook_classMethod));
    if (isAdd) {
        class_replaceMethod(metaClass_obj,
                            sel_hook_classMethod,
                            method_getImplementation(m_classMethod),
                            method_getTypeEncoding(m_classMethod));
    }else{
        method_exchangeImplementations(m_classMethod, m_hook_classMethod);
    }

一般来说,只有调试程序的时候才需要在运行期修改方法实现,这种做法不宜滥用。

14.理解“类对象”的用意

每个实例都有一个指向Class对象的指针,用以表明其类型,而这些Class对象则构成了类的继承体系。

如果对象类型无法在编译期确定,那么就应该使用类型信息查询方法来探知。

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

上一篇下一篇

猜你喜欢

热点阅读