How to Stop Fearing deprecated and Embrace Slicing in Swift
If you've ever written code in Swift and tried to cut out part of a string, you've likely encountered this frightening message: 'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator. Sounds like a death sentence? In reality, it's an invitation to a new, safer, and more powerful world of working with strings. Let's figure out what happened, why Apple decided to change the familiar API, and how to properly "slice" strings in Swift 4 and newer.
Why did substring become a thing of the past?
The good old substring(to:) worked, but it was... not very smart. It returned a new Substring object, which was essentially just a "window" into the original string. This led to confusion: you thought you were working with an independent string, but in reality, you were holding a reference to the old memory. In Swift 4, they decided to clean things up: now all substring operations return the Substring type, and to get a full-fledged string, you need to explicitly convert the result. Sounds more complicated? In practice, it's much clearer and safer.
Meet: String slicing subscript
The new approach uses subscripts and ranges. Instead of the substring(to:), substring(from:), and substring(with:) methods, you now write code that looks like working with arrays. Here's a basic analogy:
let fullString = "Привет, мир!"// Old way (deprecated)// let oldResult = fullString.substring(to: fullString.index(fullString.startIndex, offsetBy: 6))
// New waylet newResult = fullString[..<fullString.index(fullString.startIndex, offsetBy: 6)]print(newResult) // "Привет"See the ..< operator? That's the very partial range from operator — a partial range "from the beginning up to, but not including, the specified index". Powerful? You bet.
The Three Pillars of the New Approach: from, to, through
Let's break down the three main scenarios that the substring methods used to cover.
1. substring(to:) → prefix(upTo:) or a partial range
Want to take everything up to a certain index? Use ..< (half-open range) or the prefix(upTo:) method:
let str = "Hello, Swift"let index = str.firstIndex(of: ",") ?? str.endIndex
// Option using subscriptlet result1 = str[..<index]print(result1) // "Hello"
// Option using methodlet result2 = str.prefix(upTo: index)print(result2) // "Hello"2. substring(from:) → suffix(from:) or a partial range
Need to take everything from an index to the end? Use ... (closed range) with the start omitted:
let startIndex = str.index(str.startIndex, offsetBy: 7)let result3 = str[startIndex...]print(result3) // "Swift"
// Or via methodlet result4 = str.suffix(from: startIndex)print(result4) // "Swift"3. substring(with:) → a regular range
Want to extract a specific piece? Just specify the range:
let range = str.index(str.startIndex, offsetBy: 7)..<str.endIndexlet result5 = str[range]print(result5) // "Swift"
// Or via closed rangelet closedRange = str.index(str.startIndex, offsetBy: 7)...str.index(before: str.endIndex)let result6 = str[closedRange]print(result6) // "Swift"Note: all these operations return Substring, not String. If you need a full-fledged string, simply wrap the result in String():
let newString = String(result1)print(type(of: newString)) // StringWhat about prefix and suffix? They aren't deprecated!
Yes, the prefix(_:), suffix