9

背景。

请考虑以下步骤:

1) 在 Xcode 中创建一个新的“单一视图应用程序”。

2)创建类别NSObject+Extension.h和.m文件:

// .h
@interface NSObject (Extension)
- (void)someMethod;
@end

// .m
@implementation NSObject (Extension)
- (void)someMethod {
    NSLog(@"someMethod was called");
}
@end

3) 确保NSObject+Extension.m文件包含在主目标中。

4) 将以下行添加到 AppDelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[NSString new] performSelector:@selector(someMethod)];

    return YES;
}

5)确保该#import "NSObject+Extension.h行在应用程序的任何地方都不存在

6) 运行应用程序。

输出是

2013-08-27 04:12:53.642 Experimental[32263:c07] someMethod was called

问题

  1. 我想知道应用程序中是否没有任何此类别的#import ,NSString怎么可能仍然有 NSObject+Extension 可用?这种行为让我对我声明的每个 Objective-C 类别感到非常糟糕,因为我希望我声明的类别仅在它们声明的范围内可用。例如,我希望 NSObjectExtension仅在某个类中扩展,而不是在整个应用程序中扩展,因为否则它的全局空间会被“污染”。

  2. 有没有办法避免这种行为?我确实希望我的类别仅在我明确导入它们时才起作用,而不是当我将它们链接到我用来运行的目标时。

4

2 回答 2

14

我想知道应用程序中是否没有任何此类别的#import,NSString 怎么可能仍然有 NSObject+Extension 可用?这种行为让我对我声明的每个 Objective-C 类别感到非常糟糕,因为我希望我声明的类别仅在它们声明的范围内可用。例如,我希望 NSObject 仅在某些类中而不是在整个应用程序中由 Extension 扩展,因为否则它的全局空间会被“污染”。

Objective-C 对象上没有命名空间。如果您声明一个类有一个方法(无论是通过类别还是在主类上@interface),那么该类的每个实例都将具有该方法。

Objective-C 处理“私有”方法的方式是选择不告诉其他人有问题的方法(这是通过 not #import-ing 声明这些方法的文件来实现的)。再加上-Wundeclared-selector(如果您使用编译器不知道的选择器,则发出警告)与您将要获得的保护一样好。

但无论如何,如果您将 .m 文件编译为最终二进制文件,该方法存在,即使没有其他人“知道”它。

有没有办法避免这种行为?我确实希望我的类别仅在我明确导入它们时才起作用,而不仅仅是当我将它们链接到我用来运行的目标时。

是的,使用-Wundeclared-selector,Xcode 会警告你。

于 2013-08-27T01:35:34.263 回答
4

包含头文件只是为了让编译器知道它。无论如何,它都会编译它,因为 xCode 编译目标中包含的每个文件。在运行时,该方法将存在,因此即使您没有将其包含在编译时检查中,该对象仍将响应该类别方法。

于 2013-08-27T01:33:52.367 回答