【问题标题】:Objective-C Protocol Forward DeclarationsObjective-C 协议前向声明
【发布时间】:2012-07-18 00:56:22
【问题描述】:

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 对象以及普通的 ol' vanilla 对象。在其标头中包含符合标准的类#import 协议似乎是“噪音”;如上所示,在实现文件中转发声明协议和导入会更干净。但是,Xcode 在这样做时会抛出警告:

Cannot find protocol definition for 'ObjectProperties'

代码可以编译,并且大部分都可以工作。我之所以这么说主要是因为 Core Data 尝试为标量属性动态创建 getter/setter 有点奇怪,但我认为这可能是因为我遇到了一个极端情况。

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

如果我的理解是正确的(并且我的知识是最近获得的,所以我完全有可能是错的),如果我将协议导入到我的类头并更改协议,那么所有后续文件导入我的类将不得不重新编译。

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

【问题讨论】:

  • 我也有类似的问题,但使用的是 Swift 协议。

标签: objective-c protocols


【解决方案1】:

您不能转发声明超类或它所遵循的协议。在这些情况下,您必须包含标题。这是因为(在超类的情况下)超类的实例变量和方法成为您的类的一部分;或者(在协议的情况下)协议的方法成为您的类中声明的方法,而无需显式声明它们。 (即,现在包含您的类头文件的其他人将看到您的类声明了这些方法,就好像您自己声明了它们一样。)唯一可能的方法是如果它们已经在此范围内定义,即它们的头文件被导入.

#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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          猜你喜欢
          • 2011-07-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-16
          • 2011-08-29
          • 2010-10-31
          • 2013-04-02
          相关资源
          最近更新 更多