前言
本文主要是筆者小結 WWDC2017 中 《What's New in Swift》的 Session ,其中也摻雜了些《What’s New in Foundation》,僅作記錄。
下面步入主題。
私有通路控制("Private" Access Control)
SE-0169
在 Swift 4 中,private 修飾的屬性可以在 Extension 中通路了,再也不要用 fileprivate 修飾屬性了?。
下面我們來區分 Swift 3 與 Swift 4 中的差別。
Swift 3:
Swift 4:
類與協定(Class and Subtype Existentials)
SE-0156
在 Swift 3 中,有些童鞋使用代理時,無法同時繼承類和協定
Swift 4 中,針對此處進行了改進,直接上 WWDC17 示例代碼:
func shareEm(control: UIControl & Shakeable) {
control.share()
}
protocol Shakeable {
func share()
}
extension Shakeable {
func share() {
print("starting share!")
}
}
extension UIButton: Shakeable { }
extension UISlider: Shakeable { }
Smart KeyPaths
SE-0161
在 Swift 4 中新增了一種 Key-Path 表達式,該表達式可用于 KVC & KVO 中的 APIs,格式如下:
\[Type Name].[Property Name]
示例代碼如下:
struct SomeStructure {
var someProperty: Int
}
func smartKeyPath() {
let s = SomeStructure(someProperty: 12)
let keyPath = \SomeStructure.someProperty
let value = s[keyPath: keyPath]
print(value)
// value is 12
}
如果在上下文中,能隐含的推斷出其類型,那麼 Key-Path 表達式中的 Type Name 可以省略,即
\.[Property Name]
如:
@objcMembers class SomeClass: NSObject {
dynamic var someProperty: Int
init(someProperty: Int) {
self.someProperty = someProperty
}
}
var observe: NSKeyValueObservation?
let c = SomeClass(someProperty: 10)
func smarkKVO() {
observe = c.observe(\.someProperty) { object, change in
// ...
print(object.someProperty, change)
}
c.someProperty = 10
}
Archival & Serialization
SE-0166
Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C (Swift 4 beta).
我們以下面這段 JSON 為例,來看 Swift 4 中針對 JSON 進行解析的新方法
{
"name": "Banana",
"points": 200,
"description": "A banana grown in Ecuador.",
"varieties": [
"yellow",
"green",
"brown"
]
}
首先,我們要遵循 Codable 協定:
struct GroceryProduct: Codable {
let name: String
let points: Int
let description: String
let varieties: [String]
}
使用 JSONDecoder 進行解析:
let json = """
{
"name": "Banana",
"points": 200,
"description": "A banana grown in Ecuador.",
"varieties": [
"yellow",
"green",
"brown"
]
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let banana = try! decoder.decode(GroceryProduct.self, from: json)
print("\(banana.name) (\(banana.points) points): \(banana.description)")
// Prints "Banana (200 points): A banana grown in Ecuador.
Encoders
SE-0167
本節主要展示 JSONEncoder 編碼,直接上代碼:
struct University: Codable {
enum Level: String, Codable {
case one, two, three
}
var name: String
var founds: Int
var type: Level
}
func codableTest (_ obj: University) {
let encoder = JSONEncoder()
let decoder = JSONDecoder()
guard let data = try? encoder.encode(obj) else { return }
guard let jsonData = try? decoder.decode(University.self, from: data) else { return }
print("jsonData:", jsonData)
}
關于字元串(String)
字形群集(Grapheme Cluster)
在 Swift 4 中,修複了字形群集長度計算的一些問題,如 emoji 表情。關于字形群集或者 Unicode 編碼概念生疏的童鞋可以看筆者之前寫的兩篇文章 《字元編碼(一)》、《Swift3.0 中 Strings/Characters 閑聊》。下面我們來看看 WWDC17 上的的示例:
var family = "?"
family += "\u{200D}?"
family += "\u{200D}?"
family += "\u{200D}?"
print("\(family):\(family.count)")
// result --> ????:1
在之前 family.count 會等于 4(\u{200D} 是一個零寬度的 joiner)。
筆者在 Xcode 9 beta1 上運作,選擇 Swift 編譯語言版本時,測試結果無效,隻有在 Xcode 8 測試時 family.count = 4。
字元串改版(String Revision)
SE-0163
在 Swift 2 中,String 的集合這一特性被遺棄,在 Swift 3 中,String 也沒有遵守集合的相關協定(如:RangeReplaceableCollection, BidirectionalCollection),是以自 Swift 2 起,String 不是一個集合,而是把這一特性賦予給了 String 的一個屬性 --> characters (A view of the string’s contents as a collection of characters.),該屬性是 String.CharacterView 類型,并且遵守 RangeReplaceableCollection 協定。
extension String.CharacterView : RangeReplaceableCollection {···}
是以我們在周遊或者操作 String 時,經常會這麼寫:
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 3.1).” iBooks. https://itunes.apple.com/us/book/the-swift-programming-language-swift-3-1/id881256329?mt=11
for character in "Dog!?".characters {
print(character)
}
// D
// o
// g
// !
// ?
.characters.····。
但,直至 Swift 4,String 又開始遵循集合相關協定,從此可以這麼寫了:
for character in "Dog!?" {
print(character)
}
// D
// o
// g
// !
// ?
當然在 Swift 4 中又出現了一個新的結構體 Substring,Substring 無法直接指派給 String 的。
關于 Substring 與 String 之間的轉換可以這麼寫:
let label = UILabel()
let superStr = "tingxins"
let subStr = superStr.prefix(4)
label.text = String(subStr)
print(subStr)
字元串跨行寫法(Multi-Line String Literals)
SE-0168
如果字元串需要跨多行,可以這麼寫:
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 4).”.
let quotation = """
The White Rabbit put on his spectacles.
"Where shall I begin, please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""
沒錯,三對引号。
如果字元串本身包含三個連續的 ‘"""‘ 引号時,可以采用反斜杠進行轉義處理(),如:
let threeDoubleQuotes = """
Escaping the first quote \"""
Escaping all three quotes \"\"\"
"""
單面區間文法(One-Sided Ranges)
SE-0172
在 Swift 3 中,區間運算符隻有兩種:閉區間運算符(Closed Range Operator)、半閉區間運算符(Half-Open Range Operator)。在 Swift 4 中,又新增了一種更加簡單友善的區間運算符-->單面區間(One-Sided Ranges)。
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 4).
你可以這樣寫:
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names[2...] {
print(name)
}
// Brian
// Jack
for name in names[...2] {
print(name)
}
// Anna
// Alex
// Brian
當然也和結合半閉區間運算符,可以這麼寫:
for name in names[..<2] {
print(name)
}
// Anna
// Alex
判斷區間是否包含,可以這麼寫:(for語句中要注意死循環哈)
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true”
WWDC17 示例代碼:
序列協定(Sequence)
SE-0142
在 Swift 3 中,假設我們要為 Sequence 擴充一個方法,要這麼寫:
extension Sequence where Iterator.Element: Equatable {
func containsOnly(_ value: Iterator.Element) -> Bool {
return contains { (element) -> Bool in
return element == value
}
}
}
但在 Swift 4 中, 針對 Sequence 做了一些小改進,使我們代碼更加輕便,看起來更加清爽:
extension Sequence where Element: Equatable {
func containsOnly(_ value: Element) -> Bool {
return contains { (element) -> Bool in
return element == value
}
}
}
這是怎麼實作的呢?因為在 Swift 4 中,我們在聲明一個 associatedtype 的 placeholder 時,我們可以使用 where 語句了。
下面我們來對比一下 Swift 3 與 Swift 4 中 Sequence 的差別:
在 Swift 3 中 Sequence 協定是這麼寫的:
在 Swift 4 中進行改進後,是這麼寫的:
對比看完後,想必讀者一目了然。
下面針對 associatedtype 中使用 where 語句,我們再來看個例子:
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 4).
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
func makeIterator() -> Iterator
}
如果在 Swift 3 下寫,Xcode 會出現這樣的編譯錯誤:
有了上面這些特性後,我們在使用 Swift 4 時,可以省略一些備援限制,這裡直接上 WWDC17 的示例代碼:
在 Swift 3 中,是這樣寫的:
在 Swift 4 中,現在我們可以這麼寫:
泛型下标(Generic Subscripts)
SE-0148
在 Swift 4 中,現在支援泛型下标了,直接上代碼:
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 4).
extension Container {
subscript<Indices: Sequence>(indices: Indices) -> [Item]
where Indices.Iterator.Element == Int {
var result = [Item]()
for index in indices {
result.append(self[index])
}
return result
}
}
上述代碼我們為 Container 添加了下标取值能力,在這個泛型下标中有 3 個限制:
- 泛型參數 Indices 遵守 Sequence 協定
- indices 是 Indices 類型的一個執行個體
- 泛型 where 語句篩選 Indices.Iterator.Element 為 Int 類型
關于整型(Protocol-oriented integers)
SE-0104
字典與集合(Dictionary & Set enhancements)
SE-0165
Number 對象橋接(NSNumber bridging and Numeric types)
SE-0170
Swift 3 中,NSNumber 轉換有個 Bug,如:
let n = NSNumber(value: UInt32(543))
let v = n as? Int8
// v is 31
Swift 4 中已修複:
可變集合(MutableCollection)
SE-0173
現在可變集合增加了一個方法,我們可以直接使用 swapAt 方法,而非 swap 。
let university0 = University(name: "Qsting", founds: 1870, type: .one)
let university1 = University(name: "tingxins", founds: 1870, type: .one)
var mutableCollection = [university0, university1]
print(mutableCollection)
mutableCollection.swapAt(0, 1) //交換數組中0、1元素的位置
print(mutableCollection)
Change filter to return Self for RangeReplaceableCollection
SE-0174
參考連結
- https://developer.apple.com/videos/play/wwdc2017/402/
- https://github.com/apple/swift-evolution/tree/master/proposals
- https://github.com/ole/whats-new-in-swift-4
- https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/index.html
- https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html
廣告
歡迎關注微信公衆号
轉載于:https://www.cnblogs.com/tingxins/p/7153492.html