2012年5月11日金曜日

Objective-Cで 'Cannot find interface declaration for 'XXXXClass', superclass of 'ZZZZClass'...'が出る

どうも、俺@昼休みです。
タイトルの通り、Xcodeでコンパイルすると
「Cannot find interface declaration for 'XXXXClass', superclass of 'ZZZZClass'...」のエラーが出て困っていた俺へのめも。
何が起こってるかというと、簡単に言うと循環参照。

Objective-Cのクラスの前方宣言がないと困ること - アールケー開発に同じような内容の詳しい解説があります。

ClassA
#import "ClassB.h"
@interface ClassA: NSObject
{
  ClassB *b;
}
@end

ClassB
#import "ClassA.h"
@interface ClassB: NSObject
{
  ClassA *a;
}
@end
ClassAとClassBがそれぞれのヘッダファイルでお互いをimportしていて、
かつどちらかでどちらかのインスタンス変数を持っている、
またはどちらかのクラスを継承している、
ような場合にタイトルのような問題が発生します。
※コンソールからgccとかで直接コンパイルした場合は、

In file included from ClassA.h:2,
                 from ClassA.m:1:
ClassB.h:6: error: expected specifier-qualifier-list before ‘ClassA'
のようなエラーが出ます。困ったもんだ。

問題の詳細はコンパイルの処理にあり、
■ClassA.hのコンパイル
ClassA.h内で#import "ClassB.h"が見つかった時点でClassB.hをインポート(解析)する。
ClassB.h内にある#import "ClassA.h"が見つかりClassA.hをインポート(解析)するはずだが、#import宣言はネストしながらインポートしないため、実際はClassA.hのインポートは行われない。
ClassB.h内のClassAインスタンス変数の定義(ClassA *a;)で、ClassAの宣言が見つからないのでエラーとなる。
、、、そうです。

こういうような場合、#import宣言をやめて@classを使い前方宣言で対処できるのであればそれで解決できます。

ClassA
@class ClassB;
@interface ClassA: NSObject
{
  ClassB *b;
}
@end

ClassB
@class ClassA;
@interface ClassB: NSObject
{
  ClassA *a;
}
@end


ただし、対象のクラスを継承していたり、処理内で対象のクラスをallocしたりしてる場合は#importを使わなければいけません。


以上でェェエェす。


0 件のコメント: