コンパイルしようとしましたが、実行するたびに、1つのメソッドが奇妙な「タイプを予期しています」エラーをスローします。ヘッダーにメソッドがあります:
-(ANObject *)generateSomethingForSomethingElse:(NSString *)somethingElse;
エラーは、このメソッドの戻り値の型を指しています。 #import "ANObject.h"
を使用してANObject
をヘッダーにインポートしましたが、ANObject
は正常にコンパイルされています。
なぜこうなった?
これは、ソースファイルがコンパイルされる順序と関係があります。定義される前にメソッドを呼び出すことはできないことを既にご存じでしょう(以下の擬似コードを参照)。
var value = someMethod();
function someMethod()
{
...
}
SomeMethod()がまだ定義されていないため、これによりコンパイル時エラーが発生します。クラスについても同じことが言えます。クラスは、コンパイラによって次々にコンパイルされます。
したがって、コンパイルの前にすべてのクラスが巨大なファイルに入れられると想像すると、すでに問題を確認できるかもしれません。 Ship
およびBoatYard
クラスを見てみましょう:
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
繰り返しますが、Ship
クラスはまだ定義されていないため、まだ参照できません。この特定の問題の解決は非常に簡単です。コンパイル順序を変更してコンパイルします。 XCodeのこの画面に慣れていると思います。
しかし、リスト内でファイルを上下にドラッグできることを知っていますか?これにより、ファイルがコンパイルされる順序が変更されます。したがって、Ship
クラスをBoatYard
クラスの上に移動するだけで十分です。
しかし、それをしたくない場合、またはさらに重要なことに、2つのオブジェクト間に循環関係がある場合はどうでしょうか。 BoatYard
が含まれる現在のShip
への参照を追加して、そのオブジェクト図の複雑さを増しましょう。
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) BoatYard* currentBoatYard;
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
ああ、今、問題があります。これら2つをサイドバイサイドでコンパイルすることはできません。 Ship *クラスが実際に存在することをコンパイラに通知する方法が必要です。そして、これが@class
キーワードはとても便利です。
それを素人の言葉で言うと、「私を信じてください、Ship
は本当に存在し、すぐにわかるでしょう」と言っています。すべてをまとめるには:
@class Ship;
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) BoatYard* currentBoatYard;
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
これで、コンパイラはBoatYard
をコンパイルするときに、Ship
クラス定義がすぐに表示されることを認識します。もちろん、そうでない場合でも、コンパイルは成功します。
全ての @class
キーワードは、クラスがまもなく登場することをコンパイラに通知します。これは、not#import
。ヘッダーファイルをインポートする必要があります。インポートしない場合、クラス内部にはアクセスできません。
@class Ship
-(void) example
{
Ship* newShip = [[Ship alloc] init];
}
これは機能せず、Shipは前方宣言であることを示すエラーメッセージで失敗します。 #import "Ship.h"
、その後、オブジェクトのインスタンスを作成できるようになります。
ヘッダーに循環的な依存関係がある場合、このエラーが発生することがわかりました。このメソッドを宣言する.hファイルがANObject.hにインポートされているかどうかを確認します
基本的に追加します
@class ANObject;
@interfaceの前に!
だから、何らかの理由で、パラメータに列挙型を持つメソッドを設定しようとしたときにこのエラーが発生していました。そのようです:
- (void)foo:(MyEnumVariable)enumVariable;
以前はこのように使用していましたが、問題はありませんでしたが、今では使用しました。循環依存関係を確認しましたが、どれも見つかりませんでした。また、タイプミスを複数回確認しましたが、サイコロはありません。最終的に私の問題を解決したのは、変数にアクセスする前に「enum」を追加することでした。そのようです:
- (void)foo:(enum MyEnumVariable)enumVariable;
{
enum MyEnumVariable anotherEnumVariable;
}
変数のタイプのつづりが間違っていたときに、このメッセージが表示されました。以下をご覧ください
例えば.
-(void)takeSimulatorSafePhotoWithPopoverFrame:(GCRect)popoverFrame {
の代わりに.....
-(void)takeSimulatorSafePhotoWithPopoverFrame:(CGRect)popoverFrame {
通常、このようなエラーが表示されるのは、前の行に追加のかっこや欠落したかっこなどのタイプミスがあるためです。
ばかげているように聞こえるかもしれませんが、これは間違ったシェル処理または大文字/小文字の間違った使用法です。
奇妙なことに、過去にインポートの順序を変更するとこれが修正されました...他のすべてのインポートの後にインポートを一番下に移動してみてください。