原文: Updating Strings for Swfit 3
作者: kharrison
譯者: kemchenj
我去年寫了一篇 Swift String Cheat Sheet 來幫助我記憶如何使用 Swift 標(biāo)準(zhǔn)庫里的那些難用的 API, 在痛苦的版本遷移之后, Swift 3有了明顯的改善, 這一部分得歸功于新的 API 命名規(guī)范, 還有 Collections 集合, indicates 索引和 ranges 范圍的一種新的運(yùn)作方式.
這里有我關(guān)于 Swift 3的遷移工作的總結(jié) Swift playground.
更好的 API 命名
標(biāo)準(zhǔn)庫采用了新的 API 命名規(guī)范 API guidelines 之后, String
的屬性和方法都有了很多改變. 因?yàn)榇蟛糠?API 命名的變化 Xcode 都會(huì)自動(dòng)幫你修正, 所以我不會(huì)在這里把全都都列出來. 這里列出一些典型的改變讓你能更好的了解這次變化:
初始化一個(gè) String
標(biāo)準(zhǔn)庫把 String
的初始化方法 init(count: repeatedValue:)
改成了 init(repeating: count:)
, repeatedValue
的類型也從 Character
字符換成了 String
字符串去獲得更多靈活性:
// Swift 2
let h = String(count:3, repeatedValue:"0") // "000"
// Swift 3
let h = String(repeating:"01", count:3) // 010101
大小寫轉(zhuǎn)換
uppercaseString
和 lowercaseString
兩個(gè)屬性現(xiàn)在變成了函數(shù), 重新命名為 uppercased()
和 lowercased()
:
let mixedCase = "AbcDef"
// Swift 2
// let upper = mixedCase.uppercaseString // "ABCDEF"
// let lower = mixedCase.lowercaseString // "abcdef"
// Swift 3
let upper = mixedCase.uppercased() // "ABCDEF"
let lower = mixedCase.lowercased() // "abcdef"
接下來我還會(huì)講到一些別的命名的變化
使用索引去訪問集合
Swift 3 里對于 String
影響最大的一個(gè)變化就是 new model for collections and indices. 總結(jié)起來就是你不能直接訪問 String
里的元素, 而必須使用索引去從集合里把元素取出來:
let country = "Espa?a"
country.characters // characters
country.unicodeScalars // Unicode scalar 21-bit codes
country.utf16 // UTF-16 encoding
country.utf8 // UTF-8 encoding
Swift 3里每個(gè)集合的 view 里的 startIndex
和 endIndex
屬性還是沒變:
let hello = "hello"
let helloStartIndex = hello.characters.startIndex // 0
如果想要獲取字符的集合, 你也可以使用 characters
屬性:
(譯者注: characters
能夠自動(dòng)幫助我們處理編碼問題, 讓我們獲得人類理解的"字符集合". Swift 的字符串 API 剛接觸可能會(huì)覺得很難用, 但了解了背后的原理之后, 會(huì)發(fā)現(xiàn)它其實(shí)做了很多, 幫我們避開了很多坑, 了解方法之后也很容易使用)
let startIndex = hello.startIndex // 0
let endIndex = hello.endIndex // 5
hello[startIndex] // "h"
之前通過增減索引去訪問字符串的方式改變了, successor()
, predecessor()
和 advancedBy(n)
的函數(shù)都去掉了.
// Swift 2
hello[hello.startIndex] // "h"
hello[hello.startIndex.successor()] // "e"
hello[hello.endIndex.predecessor()] // "o"
hello[hello.startIndex.advancedBy(2)] // "l"
現(xiàn)在在 Swift 3 里你會(huì)使用 index(after:)
, index(before:)
和 index(_: offsetBy:)
去處理相同的情況:
// Swift 3
hello[hello.startIndex] // "h"
hello[hello.index(after: startIndex)] // "e"
hello[hello.index(before: endIndex)] // "o"
hello[hello.index(startIndex, offsetBy: 1)] // "e"
hello[hello.index(endIndex, offsetBy: -4)] // "e"
你也可以給 offset 加上限制, 避免錯(cuò)誤的下標(biāo)訪問. 函數(shù) index(_: offsetBy: limitedBy:)
會(huì)返回一個(gè)可選值, 下標(biāo)越界的時(shí)候就會(huì)返回 nil
:
if let someIndex = hello.index(startIndex,
offsetBy: 4, limitedBy: endIndex) {
hello[someIndex] // "o"
}
找到第一個(gè)符合條件的元素<T>的方式(在這種情況下, T 是一個(gè)字符串):
let matchedIndex = hello.characters.index(of: "l") // 2
let nomatchIndex = hello.characters.index(of: "A") // nil
最后, 獲取兩個(gè)索引之間距離的方法現(xiàn)在也被重新命名了:
// Swift 2
let distance = word1.startIndex.distanceTo(indexC)
// Swift 3
let distance = word1.distance(from: word1.startIndex, to: indexC)
使用 Ranges (范圍)
Swift 3 里對 Ranges 進(jìn)行了修改. 假設(shè)我有字符集合的一個(gè)起始索引值和一個(gè)終點(diǎn)索引值:
let fqdn = "useyourloaf.com"
let tldEndIndex = fqdn.endIndex
let tldStartIndex = fqdn.index(tldEndIndex, offsetBy: -3)
用起始和終點(diǎn)索引去初始化 Range 的方式:
let range = Range(uncheckedBounds: (lower: tldStartIndex, upper: tldEndIndex))
fqdn[range] // "com"
創(chuàng)建一個(gè)范圍最簡單的方法就是使用 ..<
和 ...
操作符:
let endOfDomain = fqdn.index(fqdn.endIndex, offsetBy: -4)
let rangeOfDomain = fqdn.startIndex ..< endOfDomain
fqdn[rangeOfDomain] // useyourloaf
查找和返回子字符串的范圍:
if let rangeOfTLD = fqdn.range(of: "com") {
let tld = fqdn[rangeOfTLD] // "com"
}
Playground
你可以在這里找到一份完整的升級(jí)后的 API 變化的 playground 文件 Code Examples repository. 我也更新了之前我寫的那篇文章 original post.