0

So I'm still using Swift3 but getting compiler warnings of a snippet I'm using from NSRange and Swift, I do not understand, specifically this function:

/// Returns a substring with the given `NSRange`, 
/// or `nil` if the range can't be converted.
func substring(with nsrange: NSRange) -> String? {
    guard let range = nsrange.toRange() 
        else { return nil }
    let start = UTF16Index(range.lowerBound)
    let end = UTF16Index(range.upperBound)
    return String(utf16[start..<end])
}

which Xcode 9 complains re: the range fetches that 'init' is deprecated. I think the type alias - UTF16Index, usage is the issue but short of ripping this all out I'd like to try to understand and a resolution.

enter image description here

slashlos
  • 913
  • 9
  • 17
  • Swift 4 provides API to convert `NSRange` to `Range` and vice versa. The custom conversions are obsolete. – vadian Oct 22 '17 at 13:54
  • Possible duplicate of [String, substring, Range, NSRange in Swift 4](https://stackoverflow.com/questions/45449186/string-substring-range-nsrange-in-swift-4) – Rob Oct 23 '17 at 17:26

1 Answers1

0

Yes, the question was a duplicate partially; not sure if that or the reference I gave were the original source; anyway, using that answer as a guide - but still trying to understand it, I came up with this.

extension String {
    /// An `NSRange` that represents the full range of the string.
    var nsrange: NSRange {
        return NSRange(location: 0, length: utf16.count)
    }

    /// Returns a substring with the given `NSRange`,
    /// or `nil` if the range can't be converted.
    func substring(with nsrange: NSRange) -> String? {
        guard let range = Range(nsrange, in: self) else { return nil }
        return self[range]
    }

    /// Returns a range equivalent to the given `NSRange`,
    /// or `nil` if the range can't be converted.
    func range(from nsrange: NSRange) -> Range<Index>? {
        guard let range = Range(nsrange, in: self) else { return nil }
        return range
    }
}
slashlos
  • 913
  • 9
  • 17
  • It's equivalent, but I'd rather rely on `NSRange`'s own method to convert, rather than falling back to `UTF16Index`, e.g.. `var nsrange: NSRange { return NSRange(startIndex ..< endIndex, in: self) }`. – Rob Oct 22 '17 at 15:38
  • @Rob considering that he is passing the whole string range and using utf16.count I don't see any problem with it – Leo Dabus Oct 22 '17 at 20:25
  • Both work, but it seems more intuitive to me to use `NSRange` initializer designed for creating a `NSRange` from a `Range` rather than writing code that reproduces it. Frankly, I always found the injection of UTF16 character views in the discussion about ranges and strings to be somewhat inelegant, so perhaps I'm more quick than others to celebrate its demise. Lol. – Rob Oct 22 '17 at 22:29