背景
请考虑以下步骤:
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
问题
我想知道在应用程序的任何地方是否没有此类别的#import,甚至可能 NSString仍然可以使用NSObject + Extension吗?这种行为让我对我声明的每个Objective-C类别都感觉非常糟糕,因为我希望我声明的类别只在声明的范围内 。例如,我希望NSObject仅在某些类中被Extension
扩展,而不是在整个应用程序中扩展,因为否则其全局空间会变为“污染”。
有没有办法避免这种行为?我确实希望我的类别仅在我明确导入它们时才能工作,而不是在我将它们链接到我用来运行的目标时。
答案 0 :(得分:14)
我想知道在应用程序的任何地方是否没有此类别的#import,NSString如何仍然可以使用NSObject + Extension?这种行为让我对我声明的每个Objective-C类别感觉非常糟糕,因为我希望我声明的类别仅在它们声明的范围内可用。例如,我希望NSObject只能在某个类中扩展,但不能在整个应用程序中扩展,因为否则其全局空间会变为“污染”。
Objective-C对象上没有名称空间。如果您声明某个类有方法(无论是通过类别还是主要@interface
),那么该类的每个实例都将具有该方法。
Objective-C处理“私有”方法的方式是选择不告诉其他人有关方法(这是通过#import
- 声明这些方法的文件来完成的。这与-Wundeclared-selector
一起使用(如果你使用编译器不知道的选择器就会发出警告)就像你将要获得的那样一样好。
但是无论如何,如果你将.m文件编译成你的最终二进制文件,那么方法将存在,即使没有其他人“知道”它。
有没有办法避免这种行为?我确实希望我的类别仅在我明确导入它们时才起作用,而不仅仅是当我将它们链接到我用来运行的目标时。
是的,使用-Wundeclared-selector
,Xcode会警告你。
答案 1 :(得分:4)
包含标题只是让编译器知道它。它编译它,因为xCode编译目标中包含的每个文件。在运行时,该方法将存在,因此即使您没有将其包含在编译时检查中,该对象仍将响应该类别方法。