1. 程式人生 > >Xcode 7 beta釋出,Swift 2.0帶來哪些新變化?

Xcode 7 beta釋出,Swift 2.0帶來哪些新變化?

WWDC 2015首日,蘋果釋出了版本號為7A120f的Xcode 7 beta,包含了Xcode IDE、Swift 2編譯器、Instruments、模擬器和最新的OS X、iOS、watchOS SDK。

從Xcode 7 beta Release Notes可以看出,Swift 2.0包含了許多非常niubility的特性,現在,在Swift中支援錯誤處理,如丟擲(throw)、捕獲(catch)、管理(manage)等,並且可以和NSError無縫互動。而當新的API需要向後相容舊的系統版本時,如果當前API和將要部署的目標系統版本不一致,將會丟擲一個編譯時錯誤。而近來在TIOBE程式語言排行榜呈現“自由落體”趨勢的Objective-C也有著兩處修改。具體更新如下:
Swift 2.0和Objective-C的更新

錯誤處理:我們可以在Swift中構建一個函式用來丟擲,捕獲和管理錯誤。我們可以接觸和處理可恢復的錯誤,如“file-not-found”或者網路超時,Swift和錯誤處理可以和NSError無縫互動。
可用性檢查:如果你在一箇舊的部署平臺上呼叫的一個新的系統版本引入的API時將觸發一個編譯時錯誤。我們可以在if或者guard條件語句中使用#available()函式來檢查API函式的可用性:例如:

[cpp] view plaincopy

if #available(iOS 8.0, OSX 10.10, *) {  
 // 當版本匹配時使用Handoff APIs.  
 let activity =  
 NSUserActivity(activityType:"com.example.ShoppingList.view")  
 activity.becomeCurrent()  
} else {  
 //當版本不匹配時返回.  
}   

你可以在你的程式碼宣告中使用@available()屬性宣告來指定可用性資訊。 例如:

[cpp] view plaincopy

@available(iOS 8.0, OSX 10.10, *)  
func startUserActivity() -> NSUserActivity {  
 ...  
}   

指示startUserActivity()方法只在iOS8.0+,OSX10.10+以及以其他平臺的全版本可用。

協議的擴充套件性:現在可以為協議型別編寫擴充套件,這樣就可以為遵循該協議的任意類增加方法或者屬性,極大重用我們的程式碼。
協議預設實現:現在可以為協議擴充套件中指定的需求提供一個預設實現,這樣便可以使用諸如“mixin”和“trait”的模式。
新的defer語句:這個語句在程式碼生命週期結束時用來做清理的工作,該特性在併發開發時使用新的錯誤處理模型時非常有用。例如:

[cpp] view plaincopy

 let f = fopen("x.txt", "r")  
 defer { fclose(f) }  
 try foo(f) // f會關閉如果錯誤產生的話.  
 let f2 = fopen("y.txt", "r")  
 defer { fclose(f2) }  
 try bar(f, f2) // 如果錯誤產生f2關閉,接著f關閉。  
} // f2關閉, 如果沒有任何錯誤產生f關閉。  

新的guard語法:這個新的語法允許你在一個程式碼週期中構建一個提前的退出點。例如:

[cpp] view plaincopy

guard let z = bar() else { return }  

這裡的else語句被用於退出程式碼塊(和return、throw、break、continue等類似),或者終止呼叫一個@noreturn屬性修飾的函式。

增強化的模式匹配:switch/case的模式匹配現在在很多新的條件流程控制語句中可用,這包括if/case,while/case,guard/case和for-in/case、for/in,同時也允許使用“where”判斷。
新的do語句:在do語句中支援程式碼塊巢狀,例如:

[cpp] view plaincopy

do {  
 //new scope  
 do {  
 //another scope  
 }  
}  

可測試性:關於Swift2.0框架和App的測試現在不需要將內部功能程式碼路由到public程式碼了。在待測試程式碼中使用@testable import {ModuleName}語法使所有的內部私有和public出來的程式碼可用。App或者framework的target在編譯時需要啟用“Enable Testability”編譯設定。這個“Enable Testability”編譯屬性只能在Debug配置中可用,因為它需要匯出內部符號資訊從而妨礙程式碼優化。
對C函式指標的支援:以函式指標作為函式引數的C函式將會使用閉包或者全域性的函式的方式呼叫,由於這個限制,所以閉包不能捕獲其上下文環境。例如,標準C庫函式qsort將會按照如下方式呼叫:

[cpp] view plaincopy

var array = [3, 14, 15, 9, 2, 6, 5]  
qsort(&array, array.count, sizeofValue(array[0])) { a, b in  
 return Int32(UnsafePointer<Int>(a).memory - UnsafePointer<Int>(b).memory)  
}  
print(array)  

增強的診斷資訊:增加了一個新的警告資訊用來在儘可能的情況下鼓勵使用let而不是var。同時也增加了新的警告資訊來提示未使用的變數,無法觸發的switch case分支判斷等,同時對於switch語句耗盡的判斷更加智慧。
SIMD支援:Clang中擴充套件的矩陣演算法在swift中可以匯入並使用了,大資料量的圖形演算法或者其他系統級別的資料運算在Swift實現成為可能。
列舉中現在支援多泛型關聯值,例如:

[cpp] view plaincopy

enum Either<T, U> {  
 case Left(T), Right(U)  
}  

列印特定列舉型別值時現在可以顯示列舉值和附帶的值了,但是這個對於@objc型別的列舉型別或者含有多附帶值的列舉型別不支援。
現在允許對泛型型別編寫公共擴充套件(Public)了。例如:

[cpp] view plaincopy

public extension Array { … }  

非泛型的類可以繼承自泛型的類了。
Swift字串字面量的拼接,包括跨行文字,現在確保能夠進行編譯時優化。
可失敗便捷構造器現在允許在呼叫self.init前呼叫return nil語句。指定構造器在返回nil之前必須初始化所有的儲存屬性,這是一個已知的限制。
內嵌函式現在可以遞迴引用函式本身或者其他的內嵌函式。
if條件語句現在支援標籤化了,可以使用break去跳出一個標籤化的if判斷。注意不帶標籤的break語句只能使用在迴圈或者switch/case語句中而不能用在if中。
一個新的x?語句用來匹配可選型別。
一個新的@nonobjc屬性用來選擇性的禁止例項的匯出,這個和@objc相對應。
在標準庫中增加了一個新的函式:readLine()

Playground

富文字註釋:採用Markdown樣式的語法來解釋程式碼的功能。
內聯結果:在程式碼的下方直接顯示程式碼的輸出的結果。
資源:允許使用專案導航器面板向Playground中增加諸如圖片一樣的資源。
輔助程式碼:在Playground本身之外保留額外的程式碼用作輔助功能。
分頁:採用Bundle類似的方式來組織Playground結構。 
詳解Swift語言的改變

OS X 10.11、iOS 9和watchOS 2 SDK採納了一些Objective-C的特性用來提高Swift的程式設計體驗,如可空性、型別化集合和一些別的特性。
標準庫中重構了很多泛型的全域性函式(如map、filter和sort),採用協議擴充套件方式增加這些方法。這個好處是對於其他的關聯型別能很好的適配。
方法和函式現在使用同樣的引數命名規則了,我們可以用“_”符號來省略一個外部的引數名,為了簡化使用,用來指定引數名的簡化符號“#”被移除,因為Swift為預設引數提供了特殊的規則:

宣告:

[cpp] view plaincopy

func printFunction(str: String, newline: Bool)  
func printMethod(str: String, newline: Bool)  
func printFunctionOmitParameterName(str: String, _ newline: Bool)  

呼叫:

[cpp] view plaincopy

printFunction(“hello”, newline: true)  
printMethod(“hello”, newline: true)  
printFunctionOmitParameterName("hello", true)   

NS_OPTIONS型別現在遵循OptionSetType協議,這樣可以避免set樣式的介面呼叫:

避免採用如下位運算的呼叫方式:

[cpp] view plaincopy

// Swift 1.2:  
object.invokeMethodWithOptions(.OptionA | .OptionB)  
object.invokeMethodWithOptions(nil)  
if options & .OptionC == .OptionC {  
 // .OptionC被設定  
}  

選項設定支援字面量語法和set樣式的呼叫,如contains:

[cpp] view plaincopy

object.invokeMethodWithOptions([.OptionA, .OptionB])  
object.invokeMethodWithOptions([])  
if options.contains(.OptionC) {  
 // .OptionC is set  
}  

在Swift中一個新的Option設定型別可以採用結構體遵循OptionSetType協議的方式編寫。如果該型別中指定了一個rawValue屬性和static let的常量定義,那麼標準庫將會為其他選項提供預設實現:

[cpp] view plaincopy

struct MyOptions: OptionSetType {  
 let rawValue: Int  
 static let TuringMachine = MyOptions(rawValue: 1)  
 static let LambdaCalculus = MyOptions(rawValue: 2)  
 static let VonNeumann = MyOptions(rawValue: 4)  
}  
let churchTuring: MyOptions = [.TuringMachine, .LambdaCalculus]   

do/while迴圈被重名為repeat/while,這樣更加顯而易見:

Swift 1.2:

[cpp] view plaincopy

do {  
...  
} while <condition>  

Swift 2.0:

[cpp] view plaincopy

repeat {  
...  
} while <condition>   

println和print被合併成一個print函式,並帶有一個預設的引數:

Swift 1.2:

[cpp] view plaincopy

func print(<stuff to print>)  
func println(<stuff to print>)  

Swift 2.0:

[cpp] view plaincopy

func print(<stuff to print>, appendNewline: Bool = true)  

Swift的文件註釋現在基於Markdown語法。

引數縱覽語法:

[cpp] view plaincopy

- Parameters:  
 - x: ...  
 - y: ...  

單獨引數語法:

[cpp] view plaincopy

- parameter x: ...  
- parameter y: ..  

返回值:

[cpp] view plaincopy

- returns: ...  

其他需要在QuickHelp中高亮的語法欄位,可以參考Markdown語法。

CFunctionPointer<T -> U> 型別被移除,C函式現在使用新的@convention(c)屬性宣告,和其他函式型別一樣,@convention(c) T->U是一個非空的除非是它是可選的。@objc_block屬性由@convention(block)取代。
型別標註不能用於模式匹配,而需要作為標註宣告的一部分:

這意味著,以前的這樣的寫法:

[cpp] view plaincopy

var (a : Int, b : Float) = foo()  

需要被重構為:

[cpp] view plaincopy

var (a,b) : (Int, Float) = foo()  

其實這個改動原因是為了和元組用法相區分。

在Objective-C的列舉型別匯入到Swift時,已經廢棄的列舉元素將不會影響可用元素的使用,這個可能需要Swift中一些列舉名稱的改變。
從C中匯入的列舉型別都表示為RawRepresentable,這包括哪些沒有被宣告為NS_ENUM和NS_OPTIONS列舉值,作為這個變化的一部分,所有這些列舉型別中的value屬性都需要重名為rawValue.
find被重名為indexOf(),sort被重名為sortInPlace()以及sorted()重名為sort().
String.toInt()重名為Int(String)的可失敗構造器,因為構造器語法更適合型別轉換。
String型別不再遵循SequenceType,可以使用.characters,.utf8和.utf16對應字符集的運算。
在泛型函式中聲明瞭型別引數但是在函式中沒有使用時將產生一個編譯時錯誤,例如:

[cpp] view plaincopy

func foo<T>() { } // error: generic parameter ’T’ is not used in function signature   

修復了Swift中泛型需求列印時“T==T”的錯誤。
修復了跨檔案協議遵循時符號不可見或者重複的錯誤。
在Swift中增加了@objc(propertyName)屬性,當該屬性匯入到Objective-C時可以採用這個propertyName作為getter/setter訪問器的預設名,例如:

[cpp] view plaincopy

class MyClass : NSObject {  
 @objc(theProperty) property: String // Objective-C屬性被命名為“theProperty”  
 // Objective-C getter訪問器被命名為“theProperty”  
 // Objective-C setter訪問器被命名為“setTheProperty:”  
}