我有一些代码,我想在iOS和OSX项目之间共享。不幸的是,有些类虽然在功能上相对相似(并且具有非常重叠的接口定义),但却是不同层次结构和框架的一部分,并且具有不同的名称。UIKit/AppKit类就是一个很好的例子。
一个解决方案是使用预处理器指令,但这会产生大量重复的代码:
#if TARGET_OS_IPHONE
- (UIImage *)getImage; //have to create an implementation for each
#else
- (NSImage *)getImage; //have to create an implementation for each
#endif;
我曾考虑过使用反射。在Objective-C中,可以使用NSClassFromString(@"name")
动态获取Class对象。这非常好,但是如果经常使用,就会产生丑陋的代码。它也不能在头文件中使用,因为它不是常量,所以这不起作用:
//defined once per project
#if TARGET_OS_IPHONE
Class NUImage = NSClassFromString(@"UIImage");
#else
Class NUImage = NSClassFromString(@"NSImage");
#endif;
//usage
- (NUImage *)getImage; //does not compile
我希望能够定义(理想情况下是在编译时)一个类同义词,以便可以透明地使用它来代替特定的实现类。这可能吗?从本质上讲,我希望避免必须编写包装器类(它要么只是将消息转发给具体实现,因此易于编写,但需要代码完成和检查,或者是大量样板代码,只是为了复制它所包装的类的接口)。
是否可以将Class存储为常量?
您应该尝试这样做:
#if TARGET_OS_IPHONE
typedef UIImage NUIImage; // NUIImage is an alias for UIImage
#else
typedef NSImage NUIImage; // NUIImage is an alias for NSImage
#endif
然后在任何你会使用NSImage或UIImage的地方使用NUIImage。Typedef继承自C语言,所以它只是一个编译成本,对运行时没有影响(因此,例如NSClassFromString(@"NUIImage")
将返回nil
,所有其他条件相同)。它导致编译器认为一个东西是另一个东西的别名。如果您采用严格的C约定,您可能会将其称为NUIImage_t
。
以下是我的原始答案的编辑版本,基于原始的错误阅读,问题取决于使用可能存在也可能不存在的特定类,直到运行时才知道这个事实。对于这种情况,它是准确的,但不是特别相关:
你不需要在方法定义或头文件中通常使用的任何其他定义中找到一个解决方案;你可以在那里使用类名。在Objective-C中,你总是通过指针来引用对象,所有的指针在硬件上看起来都是一样的。因此,为了程序员的利益,在源代码中使用类型化指针是一种虚构(包括通过相关的编译器警告间接地),对生成的二进制文件没有影响。
只要像下面这样的定义可以编译,SomeClass
和SomeOtherClass
在运行时是否可用并不重要:
- (SomeClass *)someMethod:(SomeOtherClass *)argument;
你不会因为声明了方法而得到异常。
真正需要使用NSClassFromString
的唯一地方是在是否定义对象类型的初始分支的地方。例如,您可以编写以下类:
@interface SomeClassThatUsesSomeOtherClass
- (id)init;
@property (nonatomic, readonly) SomeOtherClass *otherClassInstance;
- (void)doSomeTask;
- (SomeOtherClassResult *)doSomeOtherTask;
@end
/* elsewhere */
@implementation SomeClassThatUsesSomeOtherClass
@synthesize otherClassInstance;
- (id)init
{
// blah blah blah, standard init stuff here
// switch is made implicitly here, because if we get nil back
// then we'll end up with nil in 'otherClassInstance' — we're
// considering the class not existing to be equivalent to any
// other issue that might cause an instance not to be created
otherClassInstance = [[NSStringFromClass(@"SomeClass") alloc] init];
if(!otherClassInstance)
{
[self release];
return nil;
}
// blah blah blah, rest of standard init
}
// you'll need a suitable dealloc, too
- (void)doSomeTask
{
[self.otherClassInstance doAThing];
[self.otherClassInstance doAnotherThing];
}
- (SomeOtherClassResult *)doSomeOtherTask
{
return [self.otherClassInstance doAThirdThing];
}
@end
你的代码是完全安全的,自动工作或不工作取决于类是否可用
您可以(这就是我当时的做法)使用preprocessor
如下:
#define MY_CLASS_NAME @"MyClassName"
放在单独的。h文件中(可以包含在。pch文件中),然后在需要
的地方像这样使用它Class myClassInstance = NSClassFromString(MY_CLASS_NAME);
:)