iOS 高级开发技巧 1.熟悉Objective-C (二) 在类的头文件中尽量少引入其他头文件

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


今天这一个点是很多小伙伴都会忽略的,尤其是刚刚学习,甚至工作一两年的童鞋都会忽略

可是在我看来是比较重要的,因为我就吃过这方面的亏

当我明白应该怎么做的时候,我不惜花了一个小时来调整它

至少我觉得很必要


objective-c和C和C++一样,都使用“头文件”与“实现文件”来区隔代码。

objective-c编写类的方法为:

1、以类名做文件名,分别创建两个文件

2、头文件后缀名用.h、实现文件后缀名用.m

下面这个就是一个很简单的例子:

<span style="font-family:Microsoft YaHei;">//Person.h
#import <Foundation/Foudation.h>

@interface Person : NSObject
@property (nonatomic, retain) NSString *firstName;
@property (nonatomic, retain) NSString *secondName;
@end</span>
<span style="font-family:Microsoft YaHei;">//Person.m
#import "Person.h"
@implementation Person
// 实现方法
@end</span>


现在看来Person.h还是比较清晰明了的,它只引入了Foundation.h,objective-c中任何类几乎都要引入它。

如果不引入它,那么也必须引入和它的超类所属框架对应的“基本头文件”。

例如创建一个继承自UIViewController的类,它需要引入头文件UIKit。

现在,我们经常会出现的情况就有了,如果我们定义了一个新的类,叫Student

我们想让在每一个Person实例中都有一个Student,于是直接为Person加一条属性

<span style="font-family:Microsoft YaHei;">@property (nonatomic, retain) Student *student;</span>


这么做的话我们必须要做的一件事情就是引入Student的头文件

常见的方法是在Person的头文件中加上这行代码

<span style="font-family:Microsoft YaHei;">#import "Student"</span>


这种方法可行,但是不够好。

因为再Person的头文件在创建Student对象的时候,我们暂时不需要知道它内部所有的东西,我们只需要知道,有Student这个类就好了。

但是上面这行代码会在编译的时候将Student里所有的东西编译一遍。

这里有个办法,想必很多人都知道,但是不常用

<span style="font-family:Microsoft YaHei;">@class Student</span>


这叫做“向前声明”该类,这样,编译Person头文件的时候,不会花费那么多时间和资源。

先看看这个时候的Person.h中的代码:

<span style="font-family:Microsoft YaHei;">//Person.h
#import <Foundation/Foudation.h>

@class student;

@interface Person : NSObject
@property (nonatomic, retain) NSString *firstName;
@property (nonatomic, retain) NSString *secondName;
@property (nonatomic, retain) Student *student;
@end</span>


当然,我们在Person.m中,我们必须要知道Student中接口的所有细节,于是Person.m的代码就成了这样:

<span style="font-family:Microsoft YaHei;">//Person.m
#import "Person.h"
#import "Student"
@implementation Person
// 实现方法
@end
</span>

尽量拖延引入头文件的时间,只有在需要使用其详细接口信息的时候再使用,这样可以减少类使用者所引入头文件的数量

假设上面所说例子中在Person.h中引入了Student.h,那么只要引入了Person.h,就会引入Student.h中所有的内容。

想想,这样下去,编译一个类的时候,可能会编译很多根本不需要的内容,那当然会增加大量的编译时间。

-----------------------------------------------  分割线 ------------------------------------------------------

当然前面说的编译时间等问题在某种情况下还是可以忽略的,但是下面的问题就大了,会出BUG!!!!

这个时候如果我们想要在学生中加点人或者删除点人,我们需要有相应的方法:

<span style="font-family:Microsoft YaHei;">- (void)addPerson : (Person *)person;
- (void)deletePerson : (Person *)person;</span>

这个时候我想是个人都知道在Student中需要引入Person

如果你在Person.h中引入了Student.h,而不是@class Student; 

那么在Student.h中如果你也引入了Student,h也不是@class Person;

那么在A类中引用B类,在B类中引用A类,就会出现循环调用。

这样程序就傻了,到底是怎么回事?!是先有鸡还是先有蛋啊!!对了,“循环引用”的英文释义就是:chicken-and-egg situation (鸡-鸡蛋 情况)


于是,我在给我的舍友 Per 讲的时候他就很不礼貌的打断我说:OK,明白了,以后就是在.h里面不适用import就OK了嘛,都用@calss!

这样明显是不行的,我当时就狠狠的敲打了他,嘿嘿....

当你写的某个类继承自某个超类,或者声明你要写的类尊从某个协议(protocol)的时候,你是必须引入的。

那么既然有这样的情况,我们最好的做法就是讲协议单独放在一个头文件中。

具体怎么做我仍然在研究中,等我研究明白了,我一定回来改。

但是有一种协议是比较蛋疼的,像“委托协议”,因为这种协议只有跟协议所委托的类在一起才会有意义。

这也是有解决方法的,就是在实现文件中声明此类实现了该委托协议,并且把实现代码放在“class-continuation 分类”里。

这个东西我也没有搞明白,这几天看了再来填坑。


要点

- 除非必须,否则最好不要引入头文件。尽量降低类之间的耦合。

- 有时没有办法必须引入的时候,尽量把“该类遵循某条协议” 的这条声明移至“class-continuation 分类”里。如果不行,就把协议单独放在一个头文件中,然 后   将其引入





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值