ios - Objective-C 中未声明的方法与类别

标签 ios objective-c objective-c-category

假设我定义了一个类 MyClass,如下所示:

类接口(interface)文件:

#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

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

是否使用类别意味着“私有(private)”方法被 MyClass 的任何子类继承,而不使用类别意味着“私有(private)”方法被任何子类继承?

最佳答案

类中存在的所有方法总是被继承并且可以被任何人调用,无论您如何声明它们。主要区别在于是否有人知道它们。历史上还需要在使用前声明事物,这导致在旧代码和旧式代码中进行内部前向声明。


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

@interface NSURL (HTTPQueryParameters)

- (NSDictionary *)httpQueryParameters;

@end

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

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

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

剩下的类别是:

  • 为现有类添加功能;和
  • 如果类变得非常大,则将它们分段;

类扩展现在主要用于:

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

在 Objective-C 中,任何方法调用都可以发送到任何对象——对象是动态类型的。所以每个类从方法名到实现在运行时在内存中都有一个映射表。查找过程是查看该方法是否在派发到的类中实现。如果没有,则分派(dispatch)给父类(super class)。如果运行时用完父类(super class),将引发异常。

关于ios - Objective-C 中未声明的方法与类别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28597197/

相关文章:

objective-c - 在 Objective-C 中操作字符串的最快方法

objective-c - 使用 UIImageJPEGRepresentaion() 将 UIImage 转换为 NSData 并将其保存到文件会增加文件大小(以字节为单位)

ios - UINavigationController 支持的InterfaceOrientations : category vs swizzle

objective-c - 将 NSDate 类别与 Swift 3 日期类型一起使用

ios - 使用 APNS 的 Apple 推送通知是免费的吗?

ios - 将应用传递给 Xcode

ios - 在 NSArray 崩溃中用另一个替换 NSDecimalNumbers

iOS如何在屏幕外启动图像并将其动画化到屏幕上

ios - Objective-C : Is there a way to call a completion block for a method in another method?

objective-c - 在 Objective-C 中,从类别访问类扩展中定义的属性 : is it possible?