子类化时的前向声明与#import

Forward Declaration vs #import when subclassing

我有 MyClassA,它有一个 属性 类型 MyClassB

//
//  MyClassA.h
//  

@interface MyClassA : NSObject

@property (strong, nonatomic, readonly) MyClassB *myClassB;

@end

MyClassB 有一个 属性 myString.

//
//  MyClassB.h
//  

@interface MyClassB : NSObject

@property (copy, nonatomic, readonly) NSString *myString;

@end

我有 MyClassC 需要在其实现中访问 myString

我应该 -

a) 在 MyClassA.h 中转发声明 MyClassB 并在 MyClassC.m

中转发声明 #import "MyClassB.h"

b) #import MyClassB.hMyClassA.h

一般来说,您应该尽可能在头文件中使用 @class 进行前向声明。唯一一次你可能不想这样做的是当你从一个超级 class 继承或声明协议一致性时,因为编译器需要知道那个 class 或协议中发生了什么.

对于这种情况,我会在头文件中对所有 属性 声明使用 @class,在 MyClassC.m 文件中使用 #import MyClassB.h。这将允许 MyClassC 了解 MyClassB 上的所有属性。

从稍微不同的角度来看这个……你需要决定是否想让世界真正了解 myClassBMyClassA 的 属性。例如,如果您可能只想宣传可以通过 MyClassA 获得的 myString。这将其他 class 与了解 myString 的底层实现隔离开来。除非你需要暴露 MyClassB 你应该从 "rest of the world".

中隐藏它

在这种情况下,您可以按如下方式更改 MyClassA.h:

//
//  MyClassA.h
//  

@interface MyClassA : NSObject

@property (strong, nonatomic, readonly) NSString *myString;

@end

在 MyClassA.m 中,您将执行以下操作。

//
//  MyClassA.m
//  

#import "MyClassA.h"
#import "MyClassB.h"

@interface MyClassA()

@property (strong, nonatomic) MyClassB *myClassB;;

@end

@implementation MyClassA

// Other meaningful code omitted

- (NSString *)myString {
    return self.myClassB.myString;
}

@end

请注意,我在这里所做的是使用匿名类别在内部为 myClassB 定义 属性。

这里的关键是不向其他人暴露 MyClassB 是否有意义。这种方法的主要优点是您的代码更具延展性。假设 myString 以不同的方式导出。来自不同的 class 或完全不同的方法。免疫需要消耗myString的代码

如果您需要公开 MyClassB,那么您可以使用上面 Tyler 推荐的 @class 或 MyClassA.h 中的 #import MyClassB.h。最佳实践规定前向声明 @class。但有时不必记住在实现文件中导入大量文件的便利性会胜出。这是您的代码库,因此您可以选择最适合您的代码库。我一般是两者结合使用。