59

ObjectProperties.h

@protocol ObjectProperties <NSObject>

@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSDate *date;
@property (assign, nonatomic) int64_t index;

@end

ClassA.h

#import <Foundation/Foundation.h>

@protocol ObjectProperties;

@interface ClassA : NSObject <ObjectProperties>

- (void)specialSauce;

@end;

ManagedClassA.h

#import <CoreData/CoreData.h>

@protocol ObjectProperties;

@interface ManagedClassA : NSManagedObject <ObjectProperties>

- (void)doSomething;

@end;

上記のコード例から、CoreDataオブジェクトとプレーンな古いバニラオブジェクトの両方で使用されるプロトコルを.hファイルで定義しました。適合クラスがヘッダーにプロトコルをインポートするのは「ノイズ」のようです。上に示したように、プロトコルを前方宣言し、実装ファイルにインポートする方がクリーンです。ただし、Xcodeは、次のように実行すると警告をスローします。

Cannot find protocol definition for 'ObjectProperties'

コードはコンパイルされ、ほとんど機能します。私は主に、Core Dataがスカラープロパティのゲッター/セッターを動的に作成しようとしていることにいくつかのファンキーがあるためと言いますが、それはおそらく私がエッジケースにぶつかったためだと思います。

もちろん、最も明白な回避策は、プロトコルヘッダーをクラスヘッダーにインポートすることです。

私の理解が正しければ(そして私の知識はごく最近習得されたので、私が間違っている可能性があります)、プロトコルをクラスヘッダーにインポートしてプロトコルに変更を加えると、クラスを再コンパイルする必要があります。

このタイプの問題を解決する正しい方法は何ですか?

4

4 に答える 4

113

準拠するスーパークラスまたはプロトコルを前方宣言することはできません。そのような場合は、ヘッダーを含める必要があります。これは、(スーパークラスの場合)スーパークラスのインスタンス変数とメソッドがクラスの一部になるためです。または(プロトコルの場合)プロトコルのメソッドは、明示的に宣言する必要なしに、クラスで宣言されたメソッドになります。(つまり、クラスのヘッダーを含む他の人は、クラスがそれらのメソッドを自分で宣言したかのように宣言していることがわかります。)それが可能な唯一の方法は、それらがこのスコープですでに定義されている場合、つまりヘッダーがインポートされている場合です。 。

#import <SomeClass.h>
#import <SomeProtocol.h> // these two must be imported

@interface MyClass : SomeClass <SomeProtocol>
@end

前方宣言は、変数の型(具体的には、オブジェクトポインター変数)に表示されるだけのものに役立ちます。オブジェクトポインタはすべて同じサイズであり、実行時に異なるタイプのオブジェクトポインタに違いはありません(オブジェクトポインタのタイプの概念はコンパイル時のものにすぎません)。したがって、これらのタイプのクラスに何が含まれているかを正確に知る必要はありません。したがって、それらは前方宣言することができます。

@class SomeClass;
@protocol SomeProtocol; // you can forward-declare these

@interface MyClass {
    SomeClass *var1;
    id<SomeProtocol> var2;
}
@end
于 2012-07-18T03:17:00.320 に答える
4

はい、すべてのファイルを再コンパイルする必要があることは正しいですが、これは必要です。クラスヘッダーをインポートするファイルは、実装するプロトコルに関連付けられているメソッドを知っている必要があります。その定義を.mファイルに隠しておくと、1つのファイルにしか表示されません(.mファイルはインポートされないため)。これは、前方宣言クラスと同じではありません。プロトコルを前方宣言する場合は、前方宣言と同じスコープで表示される場所でプロトコルを宣言する必要があります。これが同じファイルで発生しない例は考えられません。

ARCでは、これはエラーです。ARCは、宣言されたメソッドのメモリ管理について知る必要があるためです(+1インスタンス、内部ポインターなどを返しますか?)

于 2012-07-18T01:57:57.943 に答える
2

MyClass.hでクラスを宣言することにより、そのスーパークラスのすべてのヘッダーファイルと、MyClass.hファイルで採用されたプロトコルをインポートする必要があります。Objective-cのプロトコルは、継承のバリアント型と見なされます。

前方宣言は通常、クラスのメンバー宣言で使用されます。

于 2012-07-18T02:11:02.427 に答える
1

プロトコルへの準拠を宣言しているので、プロトコルを含むヘッダーを#importする必要があります。

これは、スーパークラスを前方に宣言するのではなく、#importingと同じです。

@class Foo;

@interface Bar : Foo
// Will get error: attempting to use the forward class 'Foo' as superclass of 'Bar'
@end;
于 2012-07-18T02:15:06.590 に答える