Hari Honor
Hari Honor

Reputation: 8924

Swift: How to use preprocessors to add an extension method for *below* a certain iOS version?

I'm trying to "polyfill" NSManagedObjects init(context:) method for below iOS9. Is there a way to do an preprocessor availability check for below iOS10?

Does this even make sense or would there be a linking collision issue b/c we don't know what iOS version a user will be running?

Note this is not the same is the @available(iOS 8, *) macros. I want the opposite: if NOT available. Or more accurately I want something like @available(iOS <10.0, *), "available if iOS is less than 10.0"

Upvotes: 1

Views: 330

Answers (3)

zneak
zneak

Reputation: 138251

I don't think that this is possible just relying on compile-time operations in Swift. If you care, by writing an extension in Objective-C that defines the method, your implementation will override the platform's when it exists, so that may be a viable and simple solution.

If you only want your implementation to kick in only if there is no native one, you should be able to do that somewhat easily in Objective-C, too. First, I have two warnings:

  1. You are modifying CoreData, which itself is already quite dynamic, and I'm not sure how it will react.
  2. I can't verify any of what I'm saying on this computer, so comment if it doesn't work :)

In your bridging header, ensure that the compiler knows that init(context:) is available regardless of the iOS version:

@interface NSManagedObject ()
+(void)initialize;
-(instancetype)initWithContext:(NSManagedObjectContext* _Nonnull)ctx;
@end

+initialize methods declared in categories are executed independently of whether the class has a +initialize method itself or if any other category has one.

The implementation will then look like this:

@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

Which is rather straightforward in my opinion: check if NSManagedObject supports initWithContext:, and if not, add your own implementation of it. You don't need to provide an explicit implementation of initWithContext:.

Upvotes: 1

ielyamani
ielyamani

Reputation: 18591

Try this syntax to show a warning:

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

Or this one to prevent using it in the current iOS target:

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

You may even provide a custom message:

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

Upvotes: 1

OOPer
OOPer

Reputation: 47896

Is this what you are looking for?

@available(iOS, deprecated: 10.0)

Though, it's called Attributes in Swift. No preprocessor.

Upvotes: 0

Related Questions