Swift: 如何使用预处理器为*低于*某个iOS版本添加扩展方法?
Swift: How to use preprocessors to add an extension method for *below* a certain iOS version?
我正在尝试 "polyfill" NSManagedObjects init(context:) 方法 iOS9。有没有办法对 belowiOS10 进行预处理器可用性检查?
这是否有意义,或者是否会出现链接冲突问题b/c我们不知道用户将使用哪个iOS版本运行?
请注意,这与 @available(iOS 8, *)
宏不同。我想要相反的东西:如果不可用。或者更准确地说,我想要 @available(iOS <10.0, *)
、"available if iOS is less than 10.0"
这是您要找的吗?
@available(iOS, deprecated: 10.0)
不过,它在 Swift 中被称为 Attributes。没有预处理器。
试试这个语法来显示警告:
@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")
我认为仅仅依靠 Swift 中的 compile-time 操作是不可能的。如果您关心,通过在 Objective-C 中编写一个定义该方法的扩展,您的实现将在平台存在时覆盖它,因此这可能是一个可行且简单的解决方案。
如果您只希望您的实现仅在没有本机实现时才启动,您应该也可以在 Objective-C 中轻松地做到这一点。首先,我有两个警告:
- 您正在修改 CoreData,它本身已经很动态了,我不确定它会如何反应。
- 我无法验证我在这台计算机上所说的任何内容,所以如果它不起作用请发表评论:)
在桥接 header 中,确保编译器知道 init(context:)
可用,无论 iOS 版本如何:
@interface NSManagedObject ()
+(void)initialize;
-(instancetype)initWithContext:(NSManagedObjectContext* _Nonnull)ctx;
@end
+initialize
类别中声明的方法的执行独立于 class 本身是否有 +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:
.
的显式实现
我正在尝试 "polyfill" NSManagedObjects init(context:) 方法 iOS9。有没有办法对 belowiOS10 进行预处理器可用性检查?
这是否有意义,或者是否会出现链接冲突问题b/c我们不知道用户将使用哪个iOS版本运行?
请注意,这与 @available(iOS 8, *)
宏不同。我想要相反的东西:如果不可用。或者更准确地说,我想要 @available(iOS <10.0, *)
、"available if iOS is less than 10.0"
这是您要找的吗?
@available(iOS, deprecated: 10.0)
不过,它在 Swift 中被称为 Attributes。没有预处理器。
试试这个语法来显示警告:
@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")
我认为仅仅依靠 Swift 中的 compile-time 操作是不可能的。如果您关心,通过在 Objective-C 中编写一个定义该方法的扩展,您的实现将在平台存在时覆盖它,因此这可能是一个可行且简单的解决方案。
如果您只希望您的实现仅在没有本机实现时才启动,您应该也可以在 Objective-C 中轻松地做到这一点。首先,我有两个警告:
- 您正在修改 CoreData,它本身已经很动态了,我不确定它会如何反应。
- 我无法验证我在这台计算机上所说的任何内容,所以如果它不起作用请发表评论:)
在桥接 header 中,确保编译器知道 init(context:)
可用,无论 iOS 版本如何:
@interface NSManagedObject ()
+(void)initialize;
-(instancetype)initWithContext:(NSManagedObjectContext* _Nonnull)ctx;
@end
+initialize
类别中声明的方法的执行独立于 class 本身是否有 +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:
.