Swift5新特性 & XCode 10.2更新


swift語法更新

  1. SE-0200 原始字符串
    添加了創建原始字符串的功能,其中\""被解釋爲這些文字符號本身,而不是轉義字符或字符串終止符。這使得許多功能更加容易實現,比如正則表達式。
    要使用原始字符串,請在字符串前放置一個或多個#號,如下所示:
//正則表達式 regex1 == regex2
    let regex1 = "\\\\[A-Z]+[A-Za-z]+\\.[a-z]+"
    let regex2 = #"\\[A-Z]+[A-Za-z]+\.[a-z]+"#
    
 let keypaths = #"Swift 中的 keypaths 格式像這樣: \Person.name ."#
 
 //原始字符串中包含#
 let anotherString = ##"這是一個包含“#”的原始字符串"##
 //多行字符串的原始字符串
 let multiline = #"""
    這是一個多行字符串:,
    “我纔是
    多行字符串”。
    """#
 
 //原始字符串中插值
  let answer = 42
    let dontpanic = #"宇宙的終極答案是:\#(answer)."#
    

請注意,我如何使用\(answer)來使用字符串插值\(answer)將被解釋爲字符串中的字符,因此當您希望在原始字符串中進行字符串插值時,必須添加額外的`#'

2.SE-0235 在標準庫中引入“Result”類型,使我們能夠更簡單、更清晰地處理複雜代碼(如異步API)中的錯誤。
swift的“Result”類型實現爲具有兩種情況的枚舉:“success”和“failure”。兩者都是使用泛型實現的,這樣它們就可以有一個相關值,但是“failure”必須是符合swift的“Error”類型。(如果你之前使用過這個庫Result,你會發現他們幾乎一模一樣)

3.SE-0228字符串插值系統的升級:新增了用於調試struct的輸出方法,如果你需要自定義某結構體的輸出你需要擴展String.StringInterpolation並實現appendInterpolation()方法

struct User {
    var name: String
    var age: Int
}
extension String.StringInterpolation {
    mutating func appendInterpolation(_ value: User) {
        appendInterpolation("My name is \(value.name) and I'm \(value.age)")
    }
}

let user = User(name: "Guybrush Threepwood", age: 33)
 print("User details: \(user)")
 //輸出:User details: My name is Guybrush Threepwood and I'm 33
 
 //格式化插值到字符串
extension String.StringInterpolation {
    mutating func appendInterpolation(_ number: Int, style: NumberFormatter.Style) {
        let formatter = NumberFormatter()
        formatter.numberStyle = style

        if let result = formatter.string(from: number as NSNumber) {
            appendLiteral(result)
        }
    }
}

 let number = Int.random(in: 0...100)
  let lucky = "The lucky number this week is \(number, style: .spellOut)."
 print(lucky)
 //輸出:The lucky number this week is sixty-three.

在此基礎上用戶可以擴展更多類型的差之方法如:輸出小數位數,控制電話號碼格式,郵件格式等等,更多例子可以查看下方whats-new-in-swift-5-0

注意:舊_ExpressibleByStringInterpolation協議已被刪除; 任何使用此協議的代碼都需要針對新設計​​進行更新。一個#if compiler塊可用於條件化4.2和5.0之間的代碼,例如:

#if compiler(<5.0)
extension MyType : _ExpressibleByStringInterpolation { ... }
#else
extension MyType : ExpressibleByStringInterpolation { ... }
#endif

4.SE-0216新增語法糖 @dynamicCallable@dynamicallable是swift 4.2的@dynamicmemberlookup的擴展,其作用相同:使swift代碼更容易與動態語言(如python和javascript)一起工作。

5.SE-0192新增 @unknown 關鍵字,此關鍵詞可以用在switch語句中,Swift它要求所有switch語句覆蓋所有情況,但有時我們需要忽略一些枚舉值,我們使用default去處理忽略的情況,但當我們新增一個枚舉類型,我們的switch語句沒有更改,他也不再會提示錯誤,因爲default以及處理了新的情況,爲了更好地提示開發者使用@unknown default和原default具有相同的功能,並且編譯器回升弄成一個警告⚠️提醒用戶沒有處理所有情況:

enum PasswordError: Error {
        case short
        case obvious
        case simple
    }
    //這個方法沒有任何提示
    func showOld(error: PasswordError) {
        switch error {
        case .short:
            print("Your password was too short.")
        case .obvious:
            print("Your password was too obvious.")
        default:
            print("Your password was too simple.")
        }
    }
    
    func showNew(error: PasswordError) {
        switch error { //此行警告⚠️Switch must be exhaustive
        case .short:
            print("Your password was too short.")
        case .obvious:
            print("Your password was too obvious.")
        @unknown default:
            print("Your password wasn't suitable.")
        }
    }

6.SE-0230修改try的嵌套方式

struct User {
    var id: Int
    init?(id: Int) {
        if id < 1 {
            return nil
        }
        self.id = id
    }
    func getMessages() throws -> String {
        // complicated code here
        return "No messages"
    }
}

let user = User(id: 1)
let messages = try? user?.getMessages()

在swift4.2中上方代碼中messages的類型將會是一個String??類型,在swift5中你會得到一個String?類型,這意味着,鏈式調用不會再使可選值發生嵌套。

7.SE-0225整數類型新增函數isMultiple(of:)判斷是否是一個數的倍數

    let rowNumber = 4
    if rowNumber.isMultiple(of: 2) {
        print("Even")
    } else {
        print("Odd")
    }

8.SE-0218字典類型新增方法compactMapValues(),用於轉換字典value的類型(空值將被移除)

 let times = [
        "Hudson": "38",
        "Clarke": "42",
        "Robinson": "35",
        "Hartis": "DNF"
    ]
    //將[String:String]轉換成[String:Int]
 let finishers1 = times.compactMapValues { Int($0) }
  let finishers2 = times.compactMapValues(Int.init)
  // ["Hudson": 38, "Clarke": 42, "Robinson": 35]

9.SE-0213通過字面量強制初始化,
如果T符合其中一個ExpressibleBy*協議並且literal是一個文字表達式,那麼T(literal)將使用一個和T的類型相同的構造方法,而不是使用T的默認構造函數

struct Q: ExpressibleByStringLiteral {
  typealias StringLiteralType =  String
  var question: String

  init?(_ possibleQuestion: StringLiteralType) {
    return nil
  }
  init(stringLiteral str: StringLiteralType) {
    self.question = str
  }
}

_ = Q("ultimate question")    // 'nil'
_ = "ultimate question" as Q  // Q(question: 'ultimate question')

10.SR-5719在Swift 5模式下,@autoclosure參數不能再轉發到另一個函數調用中的@autoclosure參數。相反,必須使用()顯式調用函數值;調用本身被包裝在隱式閉包中,以確保與swift 4模式中的行爲相同。

func foo(_ fn: @autoclosure () -> Int) {}
func bar(_ fn: @autoclosure () -> Int) {
  foo(fn)   // ❌ `fn` can't be forwarded and has to be called
  foo(fn()) // ✅
}

11.SR-695在Swift 5模式中,返回Self的類方法不能再被返回非最終具體類類型的方法重寫。此類代碼不是類型安全的,需要更新。

class Base {
  class func factory() -> Self { ... }
}

class Derived : Base {
  class override func factory() -> Derived { ... }
}

12.SR-5581協議現在可以將它們的符合類型約束爲給定類的子類。支持兩種等效形式:

protocol MyView : UIView { ... }
protocol MyView where Self : UIView { ... }

請注意,Swift 4.2接受了第二種形式,但它沒有完全實現,有時可能會在編譯時或運行時崩潰。

swift5適配遇到的問題

升級xcode10.2後代碼幾乎無需調整,如果你使用了阿里的HandyJson,會因爲Swift 5 Type Metadata的變動導致編譯失敗,在本文編寫前該項目已提交更新,但版本號4.2.1未發生變化,意味着使用cocoapods集成的同學使用pod update將無法更新代碼。解決方法先移除podfile文件中的handyjson進行pod update,清空cocoapods緩存,添加handyjsonpodfile重新pod upate

XCode 10.2更新


  1. Interface Builder:雙擊故事板不再縮放。使用觸控板上的捏合手勢進行縮放或按住Option並滾動。
  2. LLDB調試:可以使用LLDB調試在閉包內的表達式$0,$1......
  3. LLDB現在支持C的可變長數組
  4. LLDB調試器有一個新的命令別名,v用於“幀變量”命令,用於在當前堆棧幀中打印變量。因爲它繞過表達式評估器,v比p或po優先級更高,並且速度更快
  5. Xcode使用SSH配置來確定應該使用哪個SSH密鑰來驗證遠程存儲庫。
  6. 更多內容瀏覽下方文檔Xcode 10.2 Release Notes

參考文檔

1.whats-new-in-swift-5-0
2.swift change Log
3.swift-5-released
4.Xcode 10.2 Release Notes

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章