What's the Swift equivalent of Objective-C'

2020-05-25 18:38发布

问题:

I want to use Xcode 9 to add iOS 11 code to my project while keeping the option to compile the project with Xcode 8 which only supports iOS 10.

In Objective-C I can do this by using a preprocessor directive to check if __IPHONE_11_0 is defined. Which will hide the code if I'm compiling with a Base SDK earlier than iOS 11. Like this:

#ifdef __IPHONE_11_0
    if (@available(iOS 11.0, *)) {
        self.navigationController.navigationBar.prefersLargeTitles = YES;
    }
#endif

Is there a way to do that in Swift?

if #available(iOS 11.0, *) doesn't work because that's a runtime check.

回答1:

The iOS 11 SDK comes with Swift 3.2 (or Swift 4), so you can use a Swift version check to accomplish the same thing:

#if swift(>=3.2)
    if #available(iOS 11.0, *) {
        …
    }
#endif


回答2:

This is the solution suggested by Apple:

if #available(iOS 11.0, *) {
    // iOS 11 specific stuff here
} else {
    // non iOS 11 stuff here
}

Please refer to this resource (watch video on mark 6:50 for more details)



回答3:

If you want to put the condition outside of the function, you could do it like below.

@available(iOS 11.0, *)
func functionName() {
 // function contents
}


回答4:

I understand. I've got an old Mac I like to use that is too old for Xcode 9, so I want to also be able to sometimes compile my projects under Xcode 8.

But if all you want is to support both iOS 10 and iOS 11, the easy way is to just set the minimum SDK of the Xcode target to 10.0, and always compile with the iOS 11 SDK. Swift will work for you in that case, and give you syntax errors unless you correctly use if #available(iOS 11.0, *) {

You'll still be able to test under both iOS 10 and iOS 11 and you won't need to bother with Xcode 8.

From the point of view of Xcode 8, you are trying to compile source code from the future. There's no good solution for Xcode 8.

Going forward, here is the solution:

In Xcode 9.3 (Swift 4.1), you can say:

#if canImport(MagiciOS12Kit)
  if #available(iOS 12.0, *) {
     MagiciOS12Class.standard.method()
  }
#endif

and your code will still compile under Xcode 9.3, but skipping that future stuff that needs a hypothetical Xcode 10.0 or later.

#if canImport(moduleName) was only added in Swift 4.1, which Xcode 8 can't handle. But even this only works for entire modules that Apple adds in the future. If Apple merely extends an existing class with new methods, as in your navigationController.navigationBar.prefersLargeTitles you still won't be able to test for prefersLargeTitles directly, but you can find another framework that Apple introduced at the same time as prefersLargeTitles and check for the existence of that framework with #if canImport(…).



回答5:

You can achieve, by doing this for function like below

@available(iOS 11.0, *)
func myFunction() {
 // function defination 
}

Or if you want check inside function write this

if #available(iOS 11.0, *) {
    // iOS 11 specific stuff here
} else if #available(iOS 10.0, *) {
   // iOS 10 specific stuff here
} else {
    // non iOS 11 & 10 stuff here
}