β

读Effective Object-C 2.0(一)

Hecv Blog 28 阅读
这部分内容是整本书书中说到的52 个方法中的1-14条

NO.1

在头文件中尽量减少其他头文件的引入,减少编译时间。例如:一旦A 类引用了类B,而C类有引用A 类的情况下,那么隐藏了对B类的现实,而对C类而言,是不需要使用B 类的。所以,我们使用 class 关键字 ,语法: @class AClass.h 这是一种向前引用,就是告诉编译器,“你先用着这个类,具体的是我,我来处理”。二在 .m 文件中,我们在 使用 # import AClass.h ,来实现具体的细节。通过这样的处理方式,就减少了类的使用者所需引入头文件的数量,减少编译需要的时间。

NO.2

多用字面量语法,(难道是鼓励使用 语法糖),这样有问题在编译阶段就可以发现,而且容易看懂, eg: @[1,3,4,nil,6]。

NO.3

多用类型常量,少用 #define 预处理指令。 这样可以看到类型的信息,使用 static const type var;如果只是实现文件(xxx.m)文件需要使用,那就别放到 xxx.h 文件中去。而如果这个定义的常量 ,比如定义通知的名字 static const NSString KxxxxxxNotification。因为需要让监听者使用这个,所以需要放到头文件中,让其他类使用,那么就要换种方式,使用 extern你 关键字 。 在头文件中这样定义 extern NSString *const ConstStr 。这个 extern 关键字就是告诉编译器,在全局符号表中将会有一个名叫 ConstStr 的符号。也即是说无需查看其定义,就允许代码使用 ConstStr 常量。

NO.4

使用枚举来表示状态,这样可以通过字面量来看出意义。而在使用 switch 的流程控制与剧中,如果使用枚举中的 值来表示状态,请不要加 default分支 , 这样在加入新的枚举值时候,编译器会提示开发者: switch 语句并未处理所有枚举。

NO.5

在类内部使读取实例变量时候,应该直接通过实例变量来读,也就是 使用 _value 。而如果在写入数据时候,则应该通过 属性来写入。 也就是 self.value = val ;通过实例变量,可以直接拿到对应的值,而不需要通过 get 方法,这样就少了一层调用。在写入的时候,使用self.value 方式,则调用了一次 set 方法,从而保证了内存的正确处理(也就是保证了引用计数)。

NO.6

考虑使用惰性初始化的方法来配置数据,节省内存。但这样的方式,得使用 属性来读取数据,保证数据对象的内存管理策略已经生效。

NO.7

慎用对象关量处理,也就是 Associated Object 。因为如果使用不当、或者滥用,可能会造成位置的bug,并且还难于调试,发现其中的问题。

NO.8

消息转发。碰到一个对象,无法识别接受到的消息,他会把这个消息发送给他的父类,直至响应。如果一层层上去到根类,依然无法响应,那么根类将接收到 doesNotRecogniseSelector 的消息,这个消息打印异常信息, unrecognized selector sent to instance …. 并且程序会崩溃。如果我们不想让他崩溃,那么可以通过 hook 一个方法,也就是执行 doesNotRecogniseSelector 之前的时候,将它替换掉。

NO.9

接着上面,上面说到方法如果在本类没有响应,他会继续转发知道找到可以识别的接受者或者跑出一场,但是我们可以在本类无法识别消息的时候,动态添加对应的处理方法。那就是在本类重写 +(BOOL)resolveInstanceMethod:(SEL)sel 这是一个类方法,不是事例方法,想想也应该知道为毛是类方法。

    
    
    +(BOOL)resolveInstanceMethod:(SEL)sel{
    NSLog(@"selector is %@",NSStringFromSelector(sel));
    if (sel == @selector(setName:)) {
        class_addMethod([self class], sel,   (IMP)dynamicMethodIMP , "v:@");
        return YES;
    }
    return [super respondsToSelector:sel];

    }    
    

这里利用了 属性的 dynamic 处理,也就是 name 属性要动态生成,而我实际上没有实现 setName 方法,所以这个时候,即将发生消息的转发,在实际的转发之前,如果我们是实现了 resolveInstanceMethod 这个类方法,并且在这做了处理,返回了 yes ,那么下一步的转发会终止。我们如果通过 动态的向本类中添加方法,那么,也是可以执行到的。 使用 runtime 的 class_addMethod 函数,第一个参数是那个类对象,第二个参数是替换的方法,第三个是函数指针,第四个是类型编码,具体意义查看文档。这样动态添加方法之后,程序就会执行添加的方法,而不会崩溃。

总结

这里提到的前几条,在我理解来说,确实可能会提高程序的效率。但后面的几条,就偏向于对obj runtime 的理解。objc 是一门动态的语言,也是面向对象的语言。动态语言,是说他的消息绑定是在运行能否响应。面向对象就不用说了。要想进一步的了解 runtime 可以参考以下博客

Objective-C Runtime 运行时之一、二、三、四、五、六(南峰子的技术博客) Objective-C runtime之消息转发机制 一、二、三 (王中周的个人博客)

读Effective Object-C 2.0(一) was originally published by 何巍 at Hecv Blog on January 16, 2015.

作者:Hecv Blog
原文地址:读Effective Object-C 2.0(一), 感谢原作者分享。

发表评论