`UTF16Index()` or `UTF16Index.init(encodedOffset:)` for Xcode 8/9 support

Viewed 1896

I'm on a development team that's supporting both Xcode 8 and Xcode 9.

I was developing a feature that used String.UTF16Index(range.location) in Xcode 8. When I upgraded to Xcode 9, that resulted in the error 'init' is deprecated.

So in Xcode 9 I changed it to UTF16Index.init(encodedOffset: range.lowerBound). However, now that doesn't work in Xcode 8 with the error Argument labels '(encodedOffset:)' do not match any available overloads.

Even if I could check the Xcode version and write different code, one of the lines would fail at compile time. How can I manage this? Or am I stuck waiting until we fully move to Xcode 9?

2 Answers

From Version Compatibility in the Swift documentation:

NOTE

When the Swift 4 compiler is working with Swift 3 code, it identifies its language version as 3.2. As a result, you can use conditional compilation blocks like #if swift(>=3.2) to write code that’s compatible with multiple versions of the Swift compiler.

In your case that would be

#if swift(>=3.2)
let idx = String.UTF16Index(encodedOffset: range.lowerBound)
#else
let idx = String.UTF16Index(range.location)
#endif

In Xcode 9 (Swift 4 or Swift 3.2 mode) only the first line is compiled, and in Xcode 8 (Swift 3.1) only the second line is compiled.

Update: The use of encodedOffset is considered harmful and will be deprecated in Swift 5. Starting with Swift 4, the correct way to convert an NSRange to a Range<String.Index> is

let str = "abc"
let nsRange = NSRange(location: 2, length: 1)
let sRange = Range(nsRange, in: str)

As others have said, you can do a Swift version check to call the right API. But if you're calling this from multiple places then it might be easier to define a shim

#if swift(>=3.2)
// already correct
#else
extension String.UTF16Index {
    init(encodedOffset: Int) {
        self.init(encodedOffset)
    }
}
#endif

Now you can just write String.UTF16Index(encodedOffset: range.lowerBound) and in Xcode 8 it will call your shim.

Related