萬衆期待的 Swift 5 終於來了,蘋果爸爸答應的 ABI 穩定也終於來了。ios
小集新小夥伴 @NotFound-- 花時間將文檔翻譯出來,供你們參考。翻譯不當之處,請及時留言指出,咱們會持續更新。git
Swift 應用程序再也不包含用於 Swift 標準庫的動態連接庫
和用於運行 iOS 12.2
,watchOS 5.2
和 tvOS 12.2
的設備的構建變體中的 Swift SDK overlays
。所以,當爲 TestFlight
進行測試部署時,或者在爲本地開發分發瘦身應用的 archive
包時,Swift 應用程序能夠更小。github
要對比 iOS 12.2 和 iOS 12.1(或更早版本) 瘦身後 App 的文件大小差別,能夠設置 App 的 deployment target
爲 iOS 12.1
或更早版本,設置 scheme set
爲 Generic iOS Device
並生成一個 App 的歸檔。在構建完成後,在 Archives organizer
選擇中 Distribute App
,而後選擇 Development distribution
。確保在 App Thinning
下拉菜單中選擇一個特定設備,如 iPhone XS
。當分發完成後,在新建立的文件夾下打開 App Thinning Size Report
。iOS 12.2 系統的變體將小於 iOS 12.1 及更早的系統的變體。確切的大小差別取決於您的 App 使用的系統框架的數量。express
關於 App 瘦身更多的信息,能夠查看 Xcode Help 中的 What is app thinning?有關應用程序文件大小的信息,請參考 App Store Connect Help 中的 View builds and file sizesswift
@dynamicCallable
容許您使用一個簡單的語法糖像調用函數同樣來調用命名類型。主要的應用場景是動態語言互操做。(SE-0216)api
例如:數組
@dynamicCallable struct ToyCallable {
func dynamicCall(withArguments:[Int]){}
func dynamicCall(withKeywordArguments:KeyValuePairs <String,Int>){}
}
let x = ToyCallable()
x(1,2,3)
// 等價於`x.dynamicallyCall(withArguments:[1,2,3])`
x(label: 1, 2)
// 等價於`x.dynamicallyCall(withKeywordArguments: ["label": 1, "": 2])`
複製代碼
\.self
),這是一個引用自身完整輸入值的 WritableKeyPath。(SE-0227)let id = \Int.self
var x = 2
print(x[keyPath: id]) // Prints "2"
x[keyPath: id] = 3
print(x[keyPath: id]) // Prints "3"
複製代碼
enum X {
case foo(bar: Int...)
}
func baz() -> X {
return .foo(bar: 0, 1, 2, 3)
}
複製代碼
以前不是特地要支持這個特性,並且如今這樣寫會報錯了。xcode
取而代之的是,讓枚舉的 case
攜帶一個數組,並顯式傳遞一個數組安全
enum X {
case foo(bar: [Int])
}
func baz() -> X {
return .foo(bar: [0, 1, 2, 3])
}
複製代碼
在 Swift 5 中,帶有一個可選類型的表達式的 try?
將會展生平成的可選項,而不是返回嵌套的可選項。(SE-0230)bash
若是類型T
符合Initialized with Literals中的其中一個協議(如 ExpressibleByIntegerLiteral),且 literal
是一個字面量表達示時,則 T(literal)
會使用相應的協議建立一個類型 T
的字面量,而不是使用一個協議的默認字面量類型的值來調用 T
的 initializer
。
如,相似於 UInt64(0xffff_ffff_ffff_ffff)
這樣的表達式如今是有效的,則以前會因爲整型字面量的默認類型是 Int
,而致使溢出。(SE-0213)
提升了字符串插值
操做的性能、清晰性和效率。(SE-0228)
舊的 _ExpressibleByStringInterpolation
協議被刪除;若是您有使用此協議的代碼,則須要作相應更新。您可使用 #if
條件判斷來區分 Swift 4.2
和 Swift 5
的代碼。例如:
#if compiler(<5)
extension MyType: _ExpressibleByStringInterpolation { /*...*/ }
#else
extension MyType: ExpressibleByStringInterpolation { /*...*/ }
#endif
複製代碼
DictionaryLiteral 類型重命名爲 KeyValuePairs。(SE-0214)
橋接到 Objective-C
代碼的 Swift
字符串如今能夠在適當的時候從 CFStringGetCStringPtr返回一個 non-nil
值,同時從 -UTF8String
返回的指針與字符串的生命週期相關聯,而不是最相近的那個 autorelease pool
。若是程序正確,那應該沒有任何問題,而且會發現性能顯著提升。可是,這也可能會讓以前一些未經測試的代碼運行,從而暴露一些潛在的問題;例如,若是有一個對 non-nil
值的判斷,而相應分支在 Swift 5 以前卻從未被執行過。(26236614)
Sequence 協議再也不具備 SubSequence
關聯類型。先前返回 SubSequence
的 Sequence
方法如今會返回具體類型。例如,suffix(_:)如今會返回一個 Array
。(47323459)
使用 SubSequence
的 Sequence
擴展應該修改成相似地使用具體類型,或者修改成 Collection 的擴展,在 Collection
中 SubSequence
仍然可用。(45761817)
例如:
extension Sequence {
func dropTwo() -> SubSequence {
return self.dropFirst(2)
}
}
複製代碼
須要改成:
extension Sequence {
func dropTwo() -> DropFirstSequence<Self> {
return self.dropFirst(2)
}
}
複製代碼
或者是:
extension Collection {
func dropTwo() -> SubSequence {
return self.dropFirst(2)
}
}
複製代碼
UTF-16
切換到 UTF-8
,與 String.UTF16View 相比,這會提升相關聯的 String.UTF8View 的性能。從新對全部代碼進行評審以提升性能,尤爲是使用了 String.UTF16View
的代碼。如今,在使用 Swift 5 軟件包管理器時,Targets
能夠聲明一些經常使用的針對特定目標的 build settings
設置。新設置也能夠基於平臺和構建配置進行條件化處理。包含的構建設置支持 Swift
和 C
語言定義,C
語言頭文件搜索路徑,連接庫和連接框架。(SE-0238)(23270646)
在使用 Swift 5 軟件包管理器時,package
如今能夠自定義 Apple 平臺的最低 deployment target
。而若是 package A
依賴於 package B
,但 package B
指定的最小 deployment target
高於 package A 的最小 deployment target
,則構建 package A 時會拋出錯誤。(SE-0236)(28253354)
新的依賴鏡像功能容許頂層包覆蓋依賴 URL。(SE-0219)(42511642)
使用如下命令設置鏡像:
$ swift package config set-mirror \
--package-url <original URL> --mirror-url <mirror URL>
複製代碼
swift
測試命令可使用標誌 --enable-code-coverage
,來生成標準格式的代碼覆蓋率數據,以便其它代碼覆蓋工具使用。生成的代碼覆蓋率數據存儲在 <build-dir>/<configuration>/codecov
目錄中。
Swift 5 再也不支持 Swift 3
版本的軟件包管理器。仍然在使用 Swift 3 Package.swift 工具版本(tool-version
)上的軟件包應該更新到新的工具版本上。
對體積較大的包進行包管理器操做如今明顯更快了。
Swift 包管理器有一個新的 --disable-automatic-resolution
標誌項,當 Package.resolved
條目再也不與 Package.swift
清單文件中指定的依賴項版本兼容時,該標誌項強制包解析失敗。此功能對於持續集成系統很是有用,能夠檢查包的 Package.resolved
是否已過時。
swift run
命令有一個新的 --repl
選項,它會啓動 Swift REPL
,支持導入包的庫目標。這使您能夠輕鬆地從包目標中試用 API,而無需構建調用該 API 的可執行文件。
有關使用 Swift 包管理器的更多信息,請訪問 swift.org 上的 Using the Package Manager。
如今,在優化(-O
和 -Osize
)構建中,默認狀況下在運行時強制執行獨佔內存訪問。違反排他性的程序將在運行時拋出帶有「重疊訪問」診斷消息錯誤。您可使用命令行標誌禁用此命令:-enforce-exclusivity = unchecked
,但這樣作可能會致使未定義的行爲。運行時違反排他性一般是因爲同時訪問類屬性,全局變量(包括頂層代碼中的變量)或經過 eacaping
閉包捕獲的變量。(SR-7139)
Swift 3 運行模式已被刪除。-swift-version
標誌支持的值爲 4
、4.2
和 5
。
在 Swift 5 中,在 switch
語句中使用 Objective-C
中聲明的或來自系統框架的枚舉時,必須處理未知的 case
,這些 case
可能未來會添加,也多是在 Objective-C
實現文件中私下定義。形式上,Objective-C
容許在枚舉中存儲任何值,只要它匹配底層類型便可。這些未知的 case
可使用新的 @unknown default case
來處理,固然若是 switch
中省略了任何已知的 case
,編譯器仍然會給出警告。它們也可使用普通的 default case
來處理。
若是您已在 Objective-C
中定義了本身的枚舉,而且不須要客戶端來處理 unknown case
,則可使用 NS_CLOSED_ENUM
宏而不是 NS_ENUM
。Swift 編譯器識別出這一點,而且不需求 switch
語句必須帶有 default case
。
在 Swift 4
和 4.2
模式下,您仍然可使用 @unknown default
。若是省略 @unknown default
,而又傳遞了一個未知的值,則程序在運行時拋出異常,這與 Xcode 10.1
中的 Swift 4.2
上的行爲是一致的。(SE-0192)(39367045)
如今在 SourceKit
生成的 Swift 模塊接口中會打印默認參數,而不只僅是使用佔位符。
unowned
和 unowned(unsafe)
類型的變量如今支持可選類型。
UIAccessibility
結構的任何成員,則 Swift 編譯器會在 「Merge swiftmodule
」 構建步驟中崩潰。構建日誌包含一條消息:Cross-reference to module 'UIKit'
... UIAccessibility
... in an extension in module 'UIKit' ... GuidedAccessError 複製代碼
包含 NS_ERROR_ENUM
枚舉的其餘類型也可能出現此問題,但 UIAccessibility
是最多見的。(47152185)
解決方法:在 target
的 Build Setting -> Swift Compiler -> Code Generation
下,設置 Compilation Mode
的值爲 Whole Module
。這是大多數 Release
配置的默認設置。
爲了減少 Swift
元數據的大小,Swift 中定義的 convenience initializers
若是調用了 Objective-C
中定義的一個 designated initializer
,那隻會提早分配一個對象。在大多數狀況下,這對您的程序沒有影響,但若是從 Objective-C
調用 convenience initializers
,那麼 +alloc
分配的初始內存會被釋放,而不會調用任何 initializer
。對於不但願發生任何類型的對象替換的調用者來講,這多是有問題的。其中一個例子是 initWithCoder: :若是 NSKeyedUnarchiver 調用 Swift
實現 init(coder:)
而且存檔對象存在循環時,則 NSKeyedUnarchiver
的實現可能會出錯。
在未來的版本中,編譯器將保證一個 convenience initializer
永遠不會丟棄它所調用的對象,只要它經過 self.init
委託給它的初始化程序也暴露給 Objective-C
,或者是它在 Objective-C
中定義了,或者是使用 @objc
標記的,或者是重寫了一個暴露給 Objective-C
的 initializer
,或者是它知足 @objc
協議的要求。(46823518)
若是一個 keypath
字面量引用了 Objective-C
中定義的屬性,或者是在 Swift
中使用 @objc
和 dynamic
修飾符定義的屬性,則編譯可能會失敗,而且報 「unsupported relocation of local symbol 'L_selector'
」 錯誤,或者 key path 字面量沒法在運行時生成正確的哈希值或處理相等比較。
解決方法:您能夠定義一個不是 @objc
修飾的包裝屬性,來引用這個 key path
。獲得的 key path
與引用原始 Objective-C
屬性的 key path
不相等,但使用包裝屬性效果是相同的。
某些項目可能會遇到之前版本的編譯時迴歸。
Swift 命令行項目在啓動時因拋出 「dyld:Library not loaded
」 錯誤而崩潰。
解決方法:添加自定義的構建設置 SWIFT_FORCE_STATIC_LINK_STDLIB=YES
。
擴展綁定如今支持嵌套類型的擴展,這些嵌套類型自己是在擴展內定義的。以前可能會由於一些聲明順序而失敗,併產生 「未聲明類型」 錯誤。(SR-631)
在 Swift 5 中,返回 Self
的類方法不能再被使用返回非 final
的具體類類型的方法來覆蓋。此類代碼不是類型安全的,須要更新。(SR-695)
例如:
class Base {
class func factory() -> Self { /*...*/ }
}
class Derived: Base {
class override func factory() -> Derived { /*...*/ }
}
複製代碼
在 Swift 5 模式下,如今會明確禁止聲明與嵌套類型同名的靜態屬性。之前,能夠在泛型類型的擴展中執行這樣的聲明。(SR-7251)
例如:
struct Foo<T> {}
extension Foo {
struct i {}
// Error: Invalid redeclaration of 'i'.
// (Prior to Swift 5, this didn’t produce an error.)
static var i: Int { return 0 }
}
複製代碼
如今能夠在子類裏繼承父類中具備可變參數的初始化方法。
在 Swift 5 中,函數中的 @autoclosure
參數不能再做爲 @autoclosure
參數傳遞到另外一個函數中調用。相反,您必須使用括號顯式調用函數值:()
;調用自己包含在一個隱式閉包中,保證了與 Swift 4
相同的行爲。(SR-5719)
例如:
func foo(_ fn: @autoclosure () -> Int) {}
func bar(_ fn: @autoclosure () -> Int) {
foo(fn) // Incorrect, `fn` can’t be forwarded and has to be called.
foo(fn()) // OK
}
複製代碼
如今徹底支持在類和泛型中定義複雜的遞歸類型,而此前可能會致使死鎖。
在 Swift 5 中,當將可選值轉換爲泛型佔位符類型時,編譯器在解包值時會更加謹慎。這種轉換的結果如今更接近於非泛型上下文中的結果。(SR-4248)
例如:
func forceCast<U>(_ value: Any?, to type: U.Type) -> U {
return value as! U
}
let value: Any? = 42
print(forceCast(value, to: Any.self))
// Prints "Optional(42)"
// (Prior to Swift 5, this would print "42".)
print(value as! Any)
// Prints "Optional(42)"
複製代碼
protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ }
複製代碼
Swift 4.2 接受了第二種形式,但沒有徹底實現,有時可能在編譯時或運行時崩潰。(SR-5581)
didSet
或 willSet
中設置屬性自己時,會避免遞歸調用(不管是隱式或顯式地設置自身的屬性)。(SR-419)例如:
class Node {
var children = [Node]()
var depth: Int = 0 {
didSet {
if depth < 0 {
// Won’t recursively call didSet, because this is setting depth on self.
depth = 0
}
// Will call didSet for each of the children,
// as this isn’t setting the property on self.
// (Prior to Swift 5, this didn’t trigger property
// observers to be called again.)
for child in children {
child.depth = depth + 1
}
}
}
}
複製代碼
Xcode中 的 diagnostics
對 #sourceLocation
進行了支持。也就是說,若是您使用#sourceLocation
將生成的文件中的行映射回源代碼時,diagnostics
會顯示在原始源文件中的行數而不是生成的文件中的。
使用泛型類型別名做爲參數或 @objc
方法的返回類型,再也不致使生成無效的 Objective-C header
。(SR-8697)
歡迎關注咱們的公衆號:iOS-Tips,也歡迎加入咱們的羣組討論問題。能夠公衆號留言 ios
、flutter
等關鍵詞獲取入羣方式。