Objective-C:@interface之前的@class指令?


78

这两个类声明之间有什么区别?我不明白为什么在这里使用@class。谢谢。

@class TestClass;

@interface TestClass: UIView {
    UIImage *image1;
    UIImage *image2;
}

@interface TestClass: UIView {
    UIImage *image1;
    UIImage *image2;
}

Answers:


194

@class存在以打破循环依赖关系。假设您有A类和B类。

@interface A:NSObject
- (B*)calculateMyBNess;
@end

@interface B:NSObject
- (A*)calculateMyANess;
@end

鸡; 见蛋。由于A的接口依赖于B的定义,因此永远无法编译,反之亦然。

因此,可以使用@class以下方法修复它:

@class B;
@interface A:NSObject
- (B*)calculateMyBNess;
@end

@interface B:NSObject
- (A*)calculateMyANess;
@end

@class有效地告诉编译器该类存在于某处,因此,声明为指向该类实例的指针是完全有效的。但是,您无法在类型仅定义为的实例引用上调用方法,@class因为编译器没有可用的其他元数据(我不记得它是否将调用网站还原为通过id或不)。

在您的示例中,@class有害无害,但完全没有必要。


24
我希望我可以再给一个+1来代表“鸡肉,鸡蛋”
Swapnil Luktuke

4
顺便说一句,它确实恢复了id评估。
2014年

有某些特殊的原因为什么有些人将@class他们的.h文件放入然后将所需的头文件导入他们的.m文件,而其他人可能只是将.h文件导入当前类的头文件?只是好奇,谢谢。@bbum
Josh Valdivieso

4
@JoshValdivieso您仍然会很快遇到循环依赖关系,通常的模式是将头文件中的导入数量减到最少,因为它曾经大大减少了编译时间(在现今的时代已不是这种情况了。预编译的标头)。
bbum 2014年

18
@class TestClass;

这仅声明“将定义TestClass类”。

在这种情况下(您粘贴的那个)这没有任何效果,因此它们是相同的。

但是,如果要定义一个使用类名的协议(例如,作为传递给委托的参数类型),则@class TestClass由于该类仍未定义,因此需要在协议定义之前声明。

通常,如果需要在进行类定义之前提及您的类名,则需要首先发出@class声明


我在协议之前最了解这种实现。感谢分享!
SleepsOnNewspapers 2015年

7

根据Matt的回答,绝对没有必要指向@class代码中的声明。@classforward定义了一个类,以便编译器随后知道您所引用的单元的一般类型。由于Objective-C在运行时几乎是无类型的,因此编译器通常通常需要知道这些-足以将其与原子C值区分开。

我将在黑暗中刺痛,说那是因为实例变量是在@interface您正在查看一些旧代码的情况下声明的。因为它是旧代码,所以@class可能曾经在其他地方(例如,在它们之间声明了委托协议),并且最终无害地搁浅了。


4

当您需要为对象定义协议时,@class通常会与您也要定义其接口的对象进行交互,因此@class非常方便。使用@class,可以将协议定义保留在类的标题中。这种委托模式通常用在Objective-C上,通常比定义“ MyClass.h”和“ MyClassDelegate.h”更好。这可能会导致一些令人困惑的导入问题

@class MyClass;

@protocol MyClassDelegate<NSObject>

- (void)myClassDidSomething:(MyClass *)myClass
- (void)myClass:(MyClass *)myClass didSomethingWithResponse:(NSObject *)reponse
- (BOOL)shouldMyClassDoSomething:(MyClass *)myClass;
- (BOOL)shouldMyClass:(MyClass *)myClass doSomethingWithInput:(NSObject *)input

@end

// MyClass hasn't been defined yet, but MyClassDelegate will still compile even tho
// params mention MyClass, because of the @class declaration.
// You're telling the compiler "it's coming. don't worry".
// You can't send MyClass any messages (you can't send messages in a protocol declaration anyway),
// but it's important to note that @class only lets you reference the yet-to-be-defined class. That's all.
// The compiler doesn't know anything about MyClass other than its definition is coming eventually.

@interface MyClass : NSObject

@property (nonatomic, assign) id<MyClassDelegate> delegate;

- (void)doSomething;
- (void)doSomethingWithInput:(NSObject *)input

@end

然后,在使用类时,既可以创建类的实例,也可以使用单个import语句实现协议

#import "MyClass.h"

@interface MyOtherClass()<MyClassDelegate>

@property (nonatomic, strong) MyClass *myClass;

@end

@implementation MyOtherClass

#pragma mark - MyClassDelegate Protocol Methods

- (void)myClassDidSomething:(MyClass *)myClass {

    NSLog(@"My Class Did Something!")

}

- (void)myClassDidSomethingWithResponse:(NSObject *)response {

    NSLog(@"My Class Did Something With %@", response);

}

- (BOOL)shouldMyClassDoSomething {

    return YES;

- (BOOL)shouldMyClassDoSomethingWithInput:(NSObject *)input {

    if ([input isEqual:@YES]) {

        return YES;

    }

    return NO;

}


- (void)doSomething {

    self.myClass = [[MyClass alloc] init];
    self.myClass.delegate = self;
    [self.myClass doSomething];
    [self.myClass doSomethingWithInput:@0];

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.