Undeclared Methods vs Categories in Objective-C
假设我定义了一个类MyClass,如下所示:
类接口文件:
1 2 3 4 5 6 7 8 9 | #import <Foundation/Foundation.h> @interface MyClass : NSObject @property (nonatomic) NSString *myProperty; - (void)myPublicMethod; @end |
使用类别的类实现文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #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 |
不使用类别的替代类实现文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #import"MyClass.h" @ implementation MyClass - (void)myPublicMethod { NSLog(@"myPublicMethod was called!"); [self myPrivateMethod]; } - (void)myPrivateMethod { NSLog(@"myPrivateMethod was called!"); } @end |
希望有人能解释这两种实现文件方法之间的区别。
使用categories是否意味着"private"方法由myclass的任何子类继承,不使用categories是否意味着"private"方法不由任何子类继承?
类上存在的所有方法都始终是继承的,并且任何人都可以调用这些方法,而不管您如何声明它们。主要的区别在于是否有人知道他们。还有一个历史性的需求,即在使用前声明内容,这会导致在旧样式的代码中进行内部前向声明。
类别用于向现有类添加方法。一个常见的用途是扩展现有类之一的功能。例如,您可以实现:
1 2 3 4 5 | @interface NSURL (HTTPQueryParameters) - (NSDictionary *)httpQueryParameters; @end |
因此,从那时起,您已经为
Objective-C用于遵循C规则,即方法只知道编译单元中它们之前的那些方法。因此,为了能够调用在源文件后面出现的方法,您需要一个转发声明。如果您不想发布这个方法让全世界看到,您可以通过一个类别或一个类扩展(为此目的,它只是一个未命名的类别)来实现这一点。
现在,objective-c方法可以调用编译单元中任何地方定义的任何方法,包括随后在同一个源文件中定义的任何方法。因此,为了编译器的利益,现在不将未发布的方法收集到一个类别或扩展中是正常的。
留下的类别有:
- 向现有类添加功能;以及
- 如果你的课程变得非常大,就把它们分开;
类扩展现在主要用于:
- 在不公布的情况下宣布
@property s。
在objective-c中,任何方法调用都可以发送到任何对象,对象是动态类型的。所以在运行时内存中有一个映射表,用于从方法名到实现的每个类。查找过程是查看方法是否在调度到的类中实现。如果没有,那么发送到超类。如果运行时超类用完,将引发异常。
类
(通常使用类扩展(有时称为"匿名类别")声明您在主实现块中定义的方法。实际上,我不能100%地确定类别声明和主块定义之间的交互是什么——如果没有编译,我不会感到惊讶,但确实如此。)
因此,两个示例之间的唯一区别是,声明允许您在希望自己的子类访问此方法,但需要限制框架用户的情况下创建私有头。