























第二弹来了。
这一节讲的是尽量在一个头文件中减少其它头文件的引入。
Objective-C和C语言、C++很像,都将类的实现与声明分开,用.h后缀名文件表示声明文件,用.m文件实现类。当要用到这个类的时候,只需要引入头文件即可,至于编译器、运行时是如何知道头文件里面的类对应的实现在哪里,在这了不做说明。一下用例子说明,先看看下面的类:
1 |
|
第二个类
1 |
|
然后就是车类Car:
1 |
|
注意到少了什么东西没有?
是的,写过C语言、C++的童鞋一下就能发现,Car类没有引入Engine和Wheel的头文件,肯定会编译出错的,因为编译器不知道Engine、Wheel类是啥。
那好,我们加上下面两行:
1 | #import "Wheel.h" |
嗯。这样就不会出错了。但是这样真的好吗?Objective-C给我们提供了@class关键字,就是来解决这个问题的。
何为前置声明?看看下面的Car类的头文件例子。
1 |
|
@class就是类的前置声明(forward declaration),就是告诉编译器“嗨,不用找了,Wheel类和Engine类是肯定存在的,用到的时候再找”。有了前置声明,我们就不用显式的引入Wheel类和Engine类了。
当然,在Car类的实现文件.m文件中,我们还是要显式的引入Wheel和Engine类的,因为在这里我们要具体用到这两个类了,当然要知道类的细节。
为什么不直接import呢?因为如果直接用import引入Wheel和Engine的声明,那么任何import引入了Car类的文件,也同时会引入Wheel、Engine类的声明,而且最终我们可能并不一定会直接跟Wheel、Engine类打交道,这样不就引入了“没有用”的类了吗?而且这样做很可能造成文件引入成“环”。
虽然import可以避免重复声明造成编译出错,传统的C语言、C++在声明的时候也可以通过如下方式避免重复声明:
1 | #ifndef _WHEEL_H_ |
但是既然Objective-C有@class这种前置声明的办法,为何不用呢。
当然,@class这样的前置声明并不能解决一切头文件引入的问题,如下这样的类,就必须要用import:
1 | #import <Foundation/Foundation.h> |
是的,当类需要被继承、定义的protocol需要实现的时候,就需要import相关的头文件了(protocol的实现如果跟类的使用者没有关联,可以定义在类的实现文件中的“扩展category”中),当然,还有@protocol这样的protocol的前置声明,怎么用就留给读者自己查阅相关资料了。
大费周章的讲了这么多,其实目的就是一个:尽量少在头文件里面引入其他头文件。
最终的目的就是只暴露最少的细节。
写代码有段时间了,一直都在琢磨这句话,希望读者也能好好体会~
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。