Objective-C中未申报的方法与类别

时间:2015-02-19 01:26:35

标签: ios objective-c objective-c-category

想象一下,我已经定义了一个MyClass类,如下所示:

类接口文件:

#import <Foundation/Foundation.h>

@interface MyClass : NSObject

@property (nonatomic) NSString *myProperty;

- (void)myPublicMethod;

@end

使用类别的类实现文件:

#import "MyClass.h"

@interface MyClass (MyCategory)

- (void)myPrivateMethod;

@end

@implementation MyClass

- (void)myPublicMethod {
    NSLog(@"myPublicMethod was called!");
    [self myPrivateMethod];
}

- (void)myPrivateMethod {
  NSLog(@"myPrivateMethod was called!");
}

@end

不使用类别的替代类实现文件:

#import "MyClass.h"

@ implementation MyClass

- (void)myPublicMethod {
    NSLog(@"myPublicMethod was called!");
    [self myPrivateMethod];

}

- (void)myPrivateMethod {
    NSLog(@"myPrivateMethod was called!");
}

@end

希望有人能解释两种实现文件方法之间的区别。

是否使用类别意味着&#34;私人&#34;方法由MyClass的任何子类继承,而不使用类别意味着&#34;私有&#34;方法是继承任何子类?

2 个答案:

答案 0 :(得分:1)

类中存在的所有方法始终都是继承的,任何人都可以调用,无论您如何声明它们。主要区别在于是否有人了解它们。在使用之前还需要声明事物,这导致旧的和旧式代码中的内部前向声明。


类别用于向现有类添加方法。常见的用途是扩展现有类之一的功能。例如,您可以实现:

@interface NSURL (HTTPQueryParameters)

- (NSDictionary *)httpQueryParameters;

@end

从那时起,您已经为NSURL本身提供了解析HTTP协议查询参数所需的知识。将功能直接添加到没有源代码的类中通常是正确的因子。

Objective-C过去遵循C规则,即方法只知道在编译单元中先于它们之前的那些方法。因此,为了能够调用稍后出现在源文件中的方法,您需要一个前向声明。如果您不想为世界发布该方法,那么您可以通过类别或类扩展(为此目的只是一个未命名的类别)实现该方法。

现在,Objective-C方法可以调用在编译单元中任何位置定义的任何方法,包括随后在同一源文件中。因此,现在通常不会为了编译器的利益而将未发布的方法收集到类别或扩展中。

留下以下类别:

  • 向现有类添加功能;和
  • 如果您的课程变得非常大,则对其进行细分;

类扩展现在主要用于:

  • 声明@property s而不发布它们。

在Objective-C中,任何方法调用都可以发送到任何对象 - 对象是动态类型的。因此,从运行方法名称到实现,每个类在运行时都有一个映射表。查找过程是查看该方法是否在调度到的类中实现。如果没有,则调度到超类。如果运行时用完了超类,则会引发异常。

答案 1 :(得分:0)

类别@interface中方法的声明仅用于将方法公开给类的用户,包括 - 正如您在评论中提到的 - 子类。

(使用类扩展(有时称为“匿名类别”)更常见的是声明一个你在主实现块中定义的方法。实际上,我不是100%确定交互是什么在你的类别声明和主要块定义之间 - 如果没有编译,我不会感到惊讶,但确实如此。)

因此,您的两个示例之间的唯一区别是声明允许您在您希望自己的子类访问此方法的情况下创建私有标头,但是具有您想要限制的框架用户。