Swift:如何使用预处理器为某个iOS版本以下的扩展添加扩展方法?

时间:2018-10-01 15:53:08

标签: swift preprocessor

我正在尝试为iOS9以下的版本“ polyfill” NSManagedObjects init(context :)方法。是否可以对以下 iOS10进行预处理器可用性检查?

这是否有意义,或者是否存在链接冲突问题b / c,我们不知道用户将运行哪个iOS版本?

请注意,这与@available(iOS 8, *)宏不同。我要相反:如果不可用。或者更准确地说,我想要类似@available(iOS <10.0, *)之类的东西,“如果iOS小于10.0则可用”

3 个答案:

答案 0 :(得分:1)

我认为仅仅依靠Swift中的编译时操作是不可能的。如果您愿意的话,通过在Objective-C中编写定义该方法的扩展,您的实现将覆盖平台的存在,因此这可能是一个可行且简单的解决方案。

如果仅在没有本机实现的情况下才希望实施,那么在Objective-C中也应该可以轻松实现这一点。首先,我有两个警告:

  1. 您正在修改CoreData,它本身已经非常动态了,我不确定它会如何反应。
  2. 我无法验证我在这台计算机上所说的任何内容,因此请注释一下,如果它不起作用:)

在桥接头中,确保编译器知道init(context:)可用,而与iOS版本无关:

@interface NSManagedObject ()
+(void)initialize;
-(instancetype)initWithContext:(NSManagedObjectContext* _Nonnull)ctx;
@end
在类别中声明的

+initialize方法是独立执行的,而与该类本身是否具有+initialize方法还是其他类别都具有一个方法无关。

然后,实现将如下所示:

@implementation NSManagedObject ()

static id initWithContext(NSManagedObject* self, SEL sel, NSManagedObjectContext* context) {
    // your implementation goes here
}

+(void)initialize {
    SEL init = @selector(initWithContext:);
    if (![self instancesRespondToSelector:init]) {
        class_addMethod(self, init, (IMP)initWithContext, "@:@");
    }
}

@end

我认为这很简单:检查NSManagedObject是否支持initWithContext:,如果不支持,则添加您自己的实现。您无需提供initWithContext:的显式实现。

答案 1 :(得分:0)

这是您要寻找的吗?

@available(iOS, deprecated: 10.0)

尽管如此,它在Swift中被称为Attributes。没有预处理器。

答案 2 :(得分:0)

尝试使用以下语法显示警告:

@available(iOS, introduced: 8.0, deprecated: 10.0)

或者此操作是为了防止在当前的iOS目标中使用它:

@available(iOS, introduced: 8.0, obsoleted: 10.0)

您甚至可以提供自定义消息:

@available(iOS, introduced: 8.0, obsoleted: 10.0, message: "This is obsoleted")