Objective-C协议前向声明

时间:2012-07-18 00:56:22

标签: objective-c protocols

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;

从上面的代码示例中,我在.h文件中定义了一个协议,用于Core Data对象以及普通的'vanilla对象。似乎“噪音”使符合类#import协议在其标题中;转发声明协议&amp;会更清晰。如上所示,在实现文件中导入。但是,Xcode在执行此操作时会发出警告:

Cannot find protocol definition for 'ObjectProperties'

代码编译,并且主要起作用。我之所以这么说主要是因为Core Data尝试动态创建标量属性的getter / setter有一些愚蠢,但我认为这可能是因为我遇到了边缘情况。

当然,最明显的解决方法是将协议标头导入类标题。

如果我的理解是正确的(并且我的知识最近被获得,因此我完全有可能我错了),如果我将协议导入我的类标题并对协议进行更改,那么所有后续文件导入我的类将不得不重新编译。

解决此类问题的正确方法是什么?

4 个答案:

答案 0 :(得分:106)

您无法转发声明超类或其符合的协议。在这些情况下,您必须包含标题。这是因为(在超类的情况下)超类的实例变量和方法成为你的类的一部分;或者(在协议的情况下)协议的方法成为您的类中声明的方法,而无需明确声明它们。 (即现在包含你的类标题的其他人会看到你的类声明了这些方法,就像你自己声明它们一样。)唯一可行的方法是它们是否已在此范围内定义,即它们的标题是导入的

#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

答案 1 :(得分:4)

是的,你是正确的,所有文件都需要重新编译,但这是必要的。导入类头的文件需要知道与其实现的协议相关的方法。如果你将该定义放在.m文件中,那么它只对一个文件可见(因为.m文件永远不会被导入)。它与前向声明类不同。如果转发声明协议,则必须将其声明在与转发声明相同的范围内可见的位置。我想不出在同一个文件中不会出现这种情况的任何例子。

在ARC这是一个错误,因为ARC需要知道声明的方法的内存管理(它们返回+1实例,内部指针等吗?)

答案 2 :(得分:2)

通过在MyClass.h中声明您的类,您必须导入其超类的所有头文件以及它在MyClass.h文件中采用的协议。 Objective-c中的协议被认为是一种变体类型的继承。

前向声明通常用于类'成员声明。

答案 3 :(得分:1)

由于您声明符合协议,您应该#import包含协议的标头。

这与#importing超类相同,而不是向前声明它:

@class Foo;

@interface Bar : Foo
// Will get error: attempting to use the forward class 'Foo' as superclass of 'Bar'
@end;
相关问题