第一章: IOS優(yōu)化(2) @class與引入文件問題

第二條 :
一: 利用@class在類的頭文件中可以減少編譯時間
  1. 當我們用Xcode創(chuàng)建類時, 其代碼看上去如下
//  Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
//   Person.m
#import "Person.h"
@implementation Person
@end

用OC編寫類幾乎都要引入Foundation.h. 如果不在該類中引入這個文件, 那么就要引入與其父類所屬框架相對應的"基本頭文件", 例如: 在創(chuàng)建IOS應用程序時, 通常會集成UIViewController類, 而這些子類的頭文件需要引入UIKit.h, 集成UIViewController哪些類, 可能會用到UIKit中的許多內容

  1. 這段時間如果創(chuàng)建了一個名為Dog的新類, 讓每個Person實例都擁有一個Dog. 于是代碼如下:
// Person.h
import <Foundation/Foundation.h>
#import "Dog.h"
@interface Person : NSObject
/** Dog */
@property (nonatomic,strong) Dog *dog;
/** name */
@property (nonatomic,strong) NSString *name;
@end
  • 注意: 這么做不夠優(yōu)雅, 在編譯使用了一個Person類的文件時, 不需要知道Dog類的全部細節(jié), 只需要知道有一個類名叫Dog就好, 這時, 我們就可以把這種情況告訴編譯器, 用@class,代碼如下:
//  Person.h
#import <Foundation/Foundation.h>
@class Dog;
@interface Person : NSObject
/** Dog */
@property (nonatomic,strong) Dog *dog;
/** name */
@property (nonatomic,strong) NSString *name;
@end
  • 這叫做"向前聲明"(forward declaring)該類
    如果Person的實現(xiàn)文件要使用Dog類, 則必須知道所有接口, 這時實現(xiàn)文件代碼就如下:
//  Person.m
#import "Person.h"
#import "Dog.h"
@implementation Person
@end
  • 只有在真的需要時才引入, 這樣就可以減少類的使用者所需引入的頭文件的數(shù)量, 上例中, 把Dog.h引入到Person.h,那么只要引入Dog.h, 就會一并引入Dog.h的所有內容, 這會增加編譯時間, 如果使用@class, 則不需要引入很多根本用不到的內容, 這會大大減少編譯時間
二: 利用@class可以避免循環(huán)引用

1.假設要為Dog類加入新增及刪除Master的方法, 那么其頭文件中會加入下述方法:

- (void)addMaster:(Person *)person;
- (void)removeMaster:(Person *)person;

這時, 編譯器若要編譯Dog.h, 那么編譯器必須知道Person, 這個類, 而要編譯Person.h, 則必須又要知道Dog這個類, 倆個類的聲明文件如下(以下情況沒有用@class):

//  Person.h
import <Foundation/Foundation.h>
#import "Dog.h"
@interface Person : NSObject
/** dog */
@property (nonatomic,strong) Dog *dog;
@end

// Dog.h  
#import <Foundation/Foundation.h>
#import "Person.h"
@interface Dog : NSObject

- (void)addMaster:(Person *)person;
- (void)removeMaster:(Person *)person;

@end
  • 上面代碼會造成, "循環(huán)引用"(chicken-and-egg situation), 當解析其中一個頭文件時, 編譯器會發(fā)現(xiàn)它引入了另一個頭文件, 而那個頭文件又回過頭來引用第一個頭文件,使用#import而非#include指令雖然不會導致死循環(huán), 這意味著倆個類有一個無法被正確編譯, 這時候就需要用到@class, 將其中一個改為使用@class 例如:
//  Dog.h
#import <Foundation/Foundation.h>
@class Person;
@interface Dog : NSObject

  - (void)addMaster:(Person *)person;
  - (void)removeMaster:(Person *)person;

  @end
三: 有時候必須要在頭文件中, 引入其他頭文件
  1. 如果你寫的類, 集成某個類, 則必須引入定義那個父類的頭文件
  2. 或者是你聲明的類遵從某個協(xié)議(protocol), 那么該協(xié)議必須有完整定義, 而且不能用向前聲明, 向前聲明只能告訴編譯器有某個協(xié)議, 而此時編譯器卻需要知道該協(xié)議中定義的方法, 例如:
    一個Student繼承自Person, 并且遵守<SchoolDelegate>協(xié)議
#import <Foundation/Foundation.h>
#import "Person.h"
#import "SchoolDelegate.h"
 @interface Student : Person <SchoolDelegate>
 @end
  *  仔細看上述代碼就會發(fā)現(xiàn), student類引入了倆個頭文件, 其中一個是    SchoolDelegate.h文件, 這個文件里面放存放了協(xié)議, 代碼如下:  
    ```
     #import <Foundation/Foundation.h>
     @protocol SchoolDelegate <NSObject>

      - (void)buyTicket: (id *)stu;

      @end
     ```
  * 這樣將協(xié)議單獨放到一個文件中雖然也是一種方法, 但是會增加編譯時間

  * (delegate protocol)這時候可以將協(xié)議與接收協(xié)議的類放在一起定義, 最好能在實現(xiàn)文件中聲明此類實現(xiàn)了該代理方法, 并把實現(xiàn)代碼放在"分類", 這樣的話, 只要在實現(xiàn)文件中引入包含協(xié)議的頭文件即可, 不需要將這個文件放在公共頭文件里, 代碼如下:
          //Student.m  文件
          #import "Student.h"

          @protocol SchoolDelegate <NSObject>
          - (void)buyTicket:(id)stu;
          @end

          @implementation Student
          @end
重點:
  1. 每次在頭文件中引入其他頭文件之前, 都要先問問自己這樣做是否有必要, 如果可以用向前聲明取代引入, 那么最好用向前聲明, 若因為實現(xiàn)屬性, 實例變量, 或者要遵守協(xié)議而必須引入頭文件, 則盡量將其移到"class-continuation分類"中
  2. 這樣做的好處, 不近可以縮減編譯時間, 而且還能降低彼此依賴程序,
  3. 除非有必要, 否則不要引入頭文件, 一般再來, 應在某個類的頭文件中使用向前聲明來提及別的類, 并在實現(xiàn)文件中引入那些類的頭文件, 這樣做可以降低耦合
  4. 有時無法使用向前聲明, 比如遵守協(xié)議, 這種情況下, 盡量把"該類遵循某協(xié)議"的這條聲明移到"class-continuation分類"中, 如果不行的話, 就把協(xié)議單獨放在一個頭文件

聲明: 以上大部分內容均來自 Effective Objective-C

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.項目經驗 2.基礎問題 3.指南認識 4.解決思路 ios開發(fā)三大塊: 1.Oc基礎 2.CocoaTouch...
    陽光的大男孩兒閱讀 5,016評論 0 13
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139
  • Objective-C 1. import的用法 拷貝文件內容可以自動防止文件的內容被重復拷貝(#define宏定...
    馬文濤閱讀 5,354評論 3 17
  • 我先問大家一個問題:"是長槍的射程遠,還是短槍的射程遠?還有兩者誰的精準度更好"。 從我們看過的電影來說...
    一匹馬來了閱讀 1,066評論 0 0
  • 又是一個起風的夜晚 卸去一天疲憊的偽裝 把你的倩影在心里放大一張又一張 所有的霓虹都比不上你眼睛的明亮 分手的時候...
    坐看云起的Annie閱讀 496評論 7 12