[WWDC17] What's New in Swift 4 ?

前言

本文主要是筆者小結 WWDC2017 中 《What's New in Swift》的 Session ,其中也摻雜了些《What’s New in Foundation》,僅做記錄。html

下面步入主題。git

私有訪問控制("Private" Access Control)

SE-0169github

在 Swift 4 中,private 修飾的屬性能夠在 Extension 中訪問了,不再要用 fileprivate 修飾屬性了😎。json

下面咱們來區分 Swift 3 與 Swift 4 中的區別。swift

Swift 3:api

access-control0

Swift 4:
數組

類與協議(Class and Subtype Existentials)

SE-0156微信

在 Swift 3 中,有些童鞋使用代理時,沒法同時繼承類和協議app

class-protocol-composition

Swift 4 中,針對此處進行了改進,直接上 WWDC17 示例代碼:ide

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。

swift-compiler-language

字符串改版(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 的。

sub-strings-error

關於 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 示例代碼:

one-sided-slicing

序列協議(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 協議是這麼寫的:

sequence-in-swift3

在 Swift 4 中進行改進後,是這麼寫的:

sequence-in-swift4

對比看完後,想必讀者一目瞭然。

下面針對 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 會出現這樣的編譯錯誤:

associated-type-error-swift3

有了上面這些特性後,咱們在使用 Swift 4 時,能夠省略一些冗餘約束,這裏直接上 WWDC17 的示例代碼:

在 Swift 3 中,是這樣寫的:

redundant-constraints-b1

redundant-constraints-b2

在 Swift 4 中,如今咱們能夠這麼寫:

redundant-constraints-a1

redundant-constraints-a2

泛型下標(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

廣告

歡迎關注微信公衆號

wechat-qrcode

相關文章
相關標籤/搜索