1.Unicode 字符串在计算 count 时的正确性改善
在 Unicode 中,有些字符是由几个其它字符组成的,比如 é 这个字符,它可以用 \u{E9} 来表示,也可以用 e 字符和上面一撇字符组合在一起表示 \u{65}\u{301}。
看以下代码:
var family = "x" family += "\u{200D}x" family += "\u{200D}x" family += "\u{200D}x" print(family) print(family.characters.count)
这个 family 是一个由多个字符组合成的字符,打印出来的结果是一个特殊的emoji表情。上面的代码在 Swift 3 中打印的 count 数是 4,在 Swift 4 中打印出的 count 是 1。
2.更快的字符处理速度
Swift 4 的字符串优化了底层实现,对于英语、法语、德语、西班牙语的处理速度提高了 3.5 倍。
对于简体中文、日语的处理速度提高了 2.5 倍。(数据来源于官方PPT)
Swift 3 中的 String 需要通过 characters 去调用的属性方法,在 Swift 4 中可以通过 String 对象本身直接调用,例如:
Swift 4 可以把上面代码中的所有的 characters 都去掉,修改如下:
Swift 4:
Swift 4 中 String 可以当做 Collection 来用,并不是因为 String 实现了 Collection 协议,而是 String 本身增加了很多 Collection 协议中的方法,使得 String 在使用时看上去就是个 Collection。例如:
翻转字符串:
遍历字符:
Map、Filter、Reduce:
在 Swift 中,String 的背后有个 Owner Object 来跟踪和管理这个 String,String 对象在内存中的存储由内存起始地址、字符数、指向 Owner Object 指针组成。Owner Object 指针指向 Owner Object 对象,Owner Object 对象持有 String Buffer。当对 String 做取子字符串操作时,子字符串的 Owner Object 指针会和原字符串指向同一个对象,因此子字符串的 Owner Object 会持有原 String 的 Buffer。当原字符串销毁时,由于原字符串的 Buffer 被子字符串的 Owner Object 持有了,原字符串 Buffer 并不会释放,造成极大的内存浪费。
在 Swift 4 中,做取子串操作的结果是一个 Substring 类型,它无法直接赋值给需要 String 类型的地方。必须用 String() 包一层,系统会通过复制创建出一个新的字符串对象,这样原字符串在销毁时,原字符串的 Buffer 就可以完全释放了。
3.去掉 characters
let values = "one,two,three..." var i = values.characters.startIndex while let comma = values.characters[i...<values.characters.endIndex].index(of: ",") { if values.characters[i..<comma] == "two" { print("found it!") } i = values.characters.index(after: comma) }
Swift 4 可以把上面代码中的所有的 characters 都去掉,修改如下:
let values = "one,three..." var i = values.startIndex while let comma = values[i...<values.endIndex].index(of: ",") { if values[i..<comma] == "two" { print("found it!") } i = values.index(after: comma) }
4.One-sided Slicing
Swift 4 新增了一个语法糖 ... 可以对字符串进行单侧边界取子串。
Swift 3:
let values = "abcdefg" let startSlicingIndex = values.index(values.startIndex,offsetBy: 3) let subvalues = values[startSlicingIndex..<values.endIndex]
Swift 4:
let values = "abcdefg" let startSlicingIndex = values.index(values.startIndex,offsetBy: 3) let subvalues = values[startSlicingIndex...] // One-sided Slicing
5.String 当做 Collection 来用
翻转字符串:
let abc: String = "abc" print(String(abc.reversed())) // cba
遍历字符:
let abc: String = "abc" for c in abc { print(c) } /* a b c */
Map、Filter、Reduce:
// map let abc: String = "abc" _ = abc.map { print($0.description) } // filter let filtered = abc.filter { $0 == "b" } // reduce let result = abc.reduce("1") { (result,c) -> String in print(result) print(c) return result + String(c) } print(result)
6.Substring
在 Swift 4 中,做取子串操作的结果是一个 Substring 类型,它无法直接赋值给需要 String 类型的地方。必须用 String() 包一层,系统会通过复制创建出一个新的字符串对象,这样原字符串在销毁时,原字符串的 Buffer 就可以完全释放了。
let big = downloadHugeString() let small = extractTinyString(from: big) mainView.titleLabel.text = small // Swift 4 编译报错 mainView.titleLabel.text = String(small) // 编译通过
7.多行字符串字面量
func tellJoke(name: String,character: Character) { let punchline = name.filter { $0 != character } let n = name.count - punchline.count let joke = "Q: Why does \(name) have \(n) \(character)'s in their name?\nA: I don't know,why does \(name) have \(n) \(character)'s in their name?\nQ: Because otherwise they'd be called \(punchline)." print(joke) } tellJoke(name: "Edward Woodward",character: "d")
字符串中间有换行只能通过添加 \n 字符来代表换行。
Swift 4 可以把字符串写在一对 """ 中,这样字符串就可以写成多行。
func tellJoke(name: String,character: Character) { let punchline = name.filter { $0 != character } let n = name.count - punchline.count let joke = """ Q: Why does \(name) have \(n) \(character)'s in their name? A: I don't know,why does \(name) have \(n) \(character)'s in their name? Q: Because otherwise they'd be called \(punchline). """ print(joke) } tellJoke(name: "Edward Woodward",character: "d")