クラスのヘッダファイルで他のヘッダファイルをできるだけ少なく参照する

5042 ワード

CとC++と同様に、Objective-Cも「ヘッダファイル」(header file)と「インプリメンテーションファイル」(implementation file)で1つのコードを削除します.Objective-C言語で「クラス」(class)を記述する標準的な方法は、クラス名でヘッダファイルを作成し、それぞれ2つのファイルを作成し、ヘッダファイル接尾辞で.hでファイル用.mを実現します.1つのクラスを作成した後、期待しますか?次のように見えます.

        //EOCPerson.h

        #import 

        @interface EOCPerson : NSObject

        @property (nonatomic, copy) NSString *firstName;

        @property (nonatomic, copy) NSString *lastName;

        @end

        //EOCPersono.m

        #import "EOCPerson.h"

        @Implementation EOCPerson

        // Implementation of methods

        @end


Objective-C言語で記述するクラスはほとんどFoundationを導入する.h.クラス自体にこのファイルを導入しない場合は、スーパークラスが属するフレームワークに対応する「ベースヘッダファイル」(base header file)を導入する必要があります.たとえばiOSアプリケーションの作成では、UIViewControllerクラスが統合されるのが一般的です.これらのサブクラスのヘッダファイルはUImit.hを導入する必要があります.
今から見れば、EOCPerson類はまあまあです.ヘッダファイルはFoundationフレームワーク全体を導入していますが、問題はありません.このようなクラスがFoundationフレームワーク内のクラスから継承されている場合、EOCPersonクラスのコンシューマ(consumer)は、いくつかのクラスの多くのコンテンツを使用する可能性があります.統合子UIViewControllerのクラスも、そのコンシューマがUImitの大部分のコンテンツを使用する可能性があります.
しばらくすると、EOCEmployerという新しいクラスを作成し、各EOCPersonインスタンスにEOCEmployerがあるべきだと思うかもしれません.次に、属性を直接追加します.

//EOCPerson.h

#import  

@interface EOCPerson : NSObject

@property (nonatomic, copy) NSString *firstName;

@property (nonatomic, copy) NSString *lastName;

@property (nonatomic, strong) EOCEmployer *employer;

@end

しかし、コンパイルにEOCPersoonが導入されたという問題がある.hファイルの場合、EOCEmployerクラスは見えず、開発者にEOCPersonの導入を強要することは不便である.hの場合はEOCEmployerを一括導入する必要がある.だから、よくある方法はEOCPersonです.hに次の行を加えます.

#import "EOCEmployer.h"


この方法は可能だが、優雅ではない.EOCPersonクラスを使用したファイルをコンパイルする場合は、EOCEmployerクラスのすべての詳細を知る必要はありません.EOCEmployerというクラスがあることを知るだけでいいです.幸いなことに、この状況をコンパイラに伝える方法があります.

@class EOCEmployer.h


これを「前向き宣言」(forward declaring)と呼びます.EOCPersonヘッダファイルは次のようになりました.

//EOCPerson.h

#import  

@class EOCEmployer.h

@interface EOCPerson : NSObject

@property (nonatomic, copy) NSString *firstName;

@property (nonatomic, copy) NSString *lastName;

@property (nonatomic, strong) EOCEmployer *employer;

@end


EOCPersonクラスのインプリメンテーションファイルは、EOCEmployerクラスのヘッダファイルを導入する必要があります.後者を使用するには、すべてのインタフェースの詳細を知る必要があります.時間ファイルは次のようになります.

// EOCPerson.m

#import "EOCPerson.h"

#import "EOCEmployer.h"

@implementation EOCPerson

// Implementation of methods

@end

ヘッダファイルを導入するタイミングをできるだけ遅らせ、必要に応じて導入するだけで、クラスの使用者が導入するヘッダファイルの数を減らすことができます.この例を想定してEOCEmployer.hはEOCPersonに導入された.h,EOCPersonを導入すれば.h,EOCEmployer.を一括導入する.hのすべての内容.このプロセスが続くと、まったく役に立たないコンテンツが多く導入され、コンパイル時間が増えるのは当然です.
2つの雷が互いに引用し合う問題を解決したと前に宣言した.EOCEmployerレイに従業員の新規および削除方法を追加すると、エアヘッドファイルに部下定義が追加されます.

-  (void)addEmployee:(EOCPerson *)person;

-  (void)removeEmployee:(EOCPerson *)person;


この場合、EOCEmployerを編集するには、コンパイラはEOCPersonというクラスを知っている必要があり、EOCPersonをコンパイルするにはEOCEmployerを知っている必要があります.それぞれのヘッダファイルに相手のヘッダファイルを導入すると、ループリファレンス(chichen-and-egg situation)が発生します.1つのヘッダファイルが接続されている場合、コンパイラは別のヘッダファイルが導入されていることを発見しますが、そのヘッダファイルは先頭ヘッダファイルを導入するために振り返ります.includeコマンドではなくimportコマンドだけではデッドループは起こりませんが、2つのクラスのうち1つが正常にコンパイルできないことを意味します.
ただし、ヘッダファイルに他のヘッダファイルを導入する必要がある場合があります.書かれたクラスがスーパークラスから継承されている場合は、そのスーパークラスを定義するヘッダファイルと同様に、書かれたクラスがプロトコル(protocol)に従うことを宣言する場合は、プロトコルに完全な定義が必要であり、前向き宣言は使用できません.前向き宣言は、コンパイラにプロトコルがあることを伝えるだけですが、コンパイラはプロトコルで定義されている方法を知っています.
//たとえば、グラフィッククラスから長方形クラスを統合するには、受領書のプロトコルに従うようにします.

// EOCRectangle.h

#import "EOCShape.h"

#import "EOCDrawable.h"

@interface EOCRectangle : EOCShape

@property (nonatomic, assign) float width;

@property (nonatomic, assign) float height;

@end


第二条#importは避けられない.これに鑑みて、プロトコルは単独でヘッダファイルに入れたほうがいいでしょう.EOCDrawableプロトコルをileのある大きなヘッダファイルに破壊しないようにすると、このプロトコルを導入すれば、必ずそのヘッダファイルのすべての内容が導入され、そうすると、面と向かって言うように、互いに一つの問題が発生し、コンパイル時間が増える.
研二にはいくつかの合意があります.たとえば「依頼プロトコル」(delegate protocol)では、ヘッダファイルを単独で書く必要はありません.その場合、プロトコルは、プロトコル依頼を紹介するクラスと一緒に定義してこそ意味があると思います.この場合、実装ファイルにこのような依頼プロトコルが実装されたことを宣言し、このコードを「class-continuation分類」に置くことが望ましいです.で行ないます.これでは,ファイルに委任プロトコルが含まれているヘッダファイルをどのように実現すればよいのか,パブリックヘッダファイル(public header file)に置く必要はない.
ヘッダファイルが他のヘッダファイルに導入されるたびに、必要かどうかを自分に聞いてみましょう.導入の代わりに前声明を使うことができれば、長い間導入しないでください.プロパティ、インスタンス変数、またはプロトコルに従うためにヘッダファイルを導入する必要がある場合は、できるだけ「class-continuation分類」に移動します.これにより,ロックコンパイル時間だけでなく,相互依存度も低減できる.依存関係が複雑すぎるとメンテナンスに支障をきたすし,コードのある部分だけを共通APIに開放したいなら,複雑すぎる依存関係にも問題が生じる.
要点:
必要がない限り、ヘッダファイルを導入しないでください.一般的には、あるクラスのヘッダファイルで前方宣言を使用して他のクラスをボリューム化し、実装ファイルにどのクラスのヘッダファイルを導入するかが問題になります.これにより,クラス間の結合(coupling)をできるだけ低減できる.
クラスがプロトコルに従うことを宣言するなど、前方宣言を使用できない場合があります.この場合、できるだけ「クラスはプロトコルを遵守する」という声明を「class-continuation分類」に移す.できない場合は、プロトコルを1つのヘッダファイルに個別に配置し、参照します.
この記事は、「Effective Objective-C 2.0高品質iOSとOS Xコードを記述する52の有効な方法」を読んで学習ノートです.
第二条:クラスのヘッダファイルでできるだけ他のヘッダファイルを引用しない