是否從Swift2.3升級到3.0呢?git
若是你有一個意義很是重大的Swift編碼庫(就像咱們在VTS中作的同樣),那麼別猶豫了,趕快更新吧。另外爲了項目的須要,Xcode的更新,跟隨蘋果的步伐,最新的技術,仍是麻溜的跟上把。github
可是若是你的Swift代碼不是很是的繁重,那麼你就直接忽略2.3吧。objective-c
下面有一些事情須要記住:swift
1.依賴庫很是重要,確保你的依賴庫支持2.3仍是3.0-大多數的lib/framework是二者都支持的(Alamofire,Charts).然而升級到3.0是你的惟一途徑。新的發展將會在Swift3.0展開。全部的swift2.3版本的相關依賴庫將會被凍結,也就是不在更新。閉包
2.Xcode8.x 將會移除對Swift2.3的支持。Swift2.3註定是大型工程的一個過渡品。因此咱們須要努力的升級到swift3.0app
3.若是你有一個私有的CocoaPods用於分享代碼在多個工程中,那麼你不得不立刻更新。dom
固然你能夠只更新到2.3,可是你只能推遲,由於在發佈Xcode9以前你必須移植到Swift3。async
將問題從Swift2.2遷移到2.3ide
這個遷移可能將Range<T>到CountableRange<T>.可是CountableRange<T>只存在於Swift3函數
遷移者將會添加評論 /* 遷移者 修復:使用變量類型爲: DispatchSpecificKey*/去使用dispatch_queue_set_specific() 這是惟一將來相關在Swift3遷移中。
將問題從Swift2.x遷移到3.0
Swift3.0是一個打破一切的版本。swift3意味着打破一切而且移除了全部不利於一個語言長期發展的不利因素。這固然也意味着不少的東西被改變了。你也須要去改變這些使你的工程更加兼容。
Swift 2.3
Swift2.3是一個很是小的更新。具體多麼小呢?實際上,這裏僅僅只有一個改變。OC代碼在編譯時爲空的檢查在蘋果的SDK中被更新。
// Swift 2.2 | |
let image = CIImage(MTLTexture: texture, options: options) | |
let extent = image.extent // can crash | |
// Swift 3.0 | |
let image = CIImage(MTLTexture: texture, options: options)! | |
// or | |
if let image = CIImage(MTLTexture: texture, options: options) { | |
… | |
} |
其餘的變化包括一些小的重命名和一些可選類型的初始化如今返回了他們應該返回的類型而再也不是可選類型。這些應用就想從bundle初始化nib同樣。
Swift3.0
重大的更改(你必須須要注意)
私有的定義已經被更改了,下面來介紹一下fileprivate
之前格式化的私有如今在Swift3.0中變成了fileprivate。一個fileprivate可使用在一個Extension中
可是一個私有private的變量不可使用在一個Extension的類中
public的定義也被改變了。下面來介紹一下open的定義
目前,聲明一個類或者屬性public提供了兩種實用性:
1.容許外部的modules使用class/member.
2.容許外部的modules繼承class/member.
在swift3中,public就是外部可用的,可是不能繼承。之前的功能被open給封裝了。
動詞和名詞
以d結尾的函數如今返回這個對象的一個實例
// Before | |
var myArray = [ 1 ,3, 2, 5, 4 ] | |
myArray.sort() // returns a new sorted version of `myArray` | |
myArray.sortInPlace() // sorts in place | |
// After | |
myArray.sort() // sorts in place | |
myArray.sorted() // returns a new sorted version of `myArray`. |
這個變化一樣適用於reverse和reversed,enumerate和enumerated等等
OC的布爾類型如今所有使用前綴 is ,Foundation 類型再也不使用NS前綴了(這將不會有衝突,例如NSString仍然有前綴,要否則這將會和String衝突)
Foundation類型如今可使用Swift的let和var定義很是nice的展現出來
//before | |
var myDate = Date() | |
myDate.addTimeInterval(60) // OK | |
//after | |
let myOtherDate = Date() | |
myOtherDate.addTimeInterval(60) // Error, as expected |
引入做爲一個成員
如今的C函數將會被引入做爲方法。導入者將會常常自動地推斷這些map。那就意味着使用老的C的API感受更天然了,更和諧在Swift。就拿point爲例。CoreGraphics API。CoreGraphics已經再也不更新了在這個版本中
// Before | |
let topLeft = bounds.origin | |
let bottomRight = CGPoint(x: bounds.size.width, y: bounds.size.height) | |
let path = CGPathCreateMutable() | |
CGPathMoveToPoint(path, &transform, topLeft.x, topLeft.y) | |
CGPathAddLineToPoint(path, &transform, CGRectGetMidX(bounds), bottomRight.y) | |
CGPathAddLineToPoint(path, &transform, bottomRight.x, topLeft.y) | |
CGPathAddLineToPoint(path, &transform, topLeft.x, topLeft.y) | |
CGPathAddLineToPoint(path, &transform, topLeft.x, bottomRight.y) | |
CGPathAddLineToPoint(path, &transform, bottomRight.x, bottomRight.y) | |
CGPathAddLineToPoint(path, &transform, bottomRight.x, topLeft.y) | |
CGContextAddPath(context, path) | |
// After | |
let topLeft = bounds.origin | |
let bottomRight = CGPoint(x: bounds.size.width, y: bounds.size.height) | |
let path = CGMutablePath() | |
path.move(transform: &transform, x: topLeft.x, y: topLeft.y) | |
path.addLine(transform: &transform, x: bounds.midX, y: bottomRight.y) | |
path.addLine(transform: &transform, x: bottomRight.x, y: topLeft.y) | |
path.addLine(transform: &transform, x: topLeft.x, y: topLeft.y) | |
path.addLine(transform: &transform, x: topLeft.x, y: bottomRight.y) | |
path.addLine(transform: &transform, x: bottomRight.x, y: bottomRight.y) | |
path.addLine(transform: &transform, x: bottomRight.x, y: topLeft.y) | |
context.addPath(path) |
駝峯標示的改變
在枚舉和屬性中。首字母大寫的駝峯標示已經被小寫所代替
// Before let red = UIColor.redColor().CGColor
// After let red = UIColor.red.cgColor
(我最喜歡的改變)重構了條件條款
你將不能在guard,if,while裏面使用where關鍵詞了。可是你仍然能夠將他應用在循環(for-in-where)
// Before | |
if let x = x where z == 2 { | |
// Do stuff | |
} | |
// After | |
if let x = x, z == 2 { | |
// Do stuff | |
} |
仍然還有一些改變在case的條款中
第一個參數標籤的一致性
第一個參數的名字默認是必須的如今
func remix(aSong: Song) { | |
... | |
} | |
// Before | |
let song = Song() | |
remix(song) | |
// After | |
let song = Song() | |
remix(aSong: song) |
(我最喜歡的改變)處理了隱式的打開可選類型
我認爲若是你有一個分享的語言,那麼在遷移的過程當中這個改變是值得的。那麼究竟是什麼呢?
OC類型之前只有隱式解包類型!的屬性。可是如今有了包裹類型?這能夠被用到任何地方除了這裏:
let legacyType = SomeObjCObject()
let starsArray = legacyType.stars // Array of [Star!]
更好的翻譯關於OC的API
命名更加的清晰明確了
let path = UIBezierPath() | |
let point = CGPoint(x: 2, y: 3) | |
let string = NSString("Hello world!") | |
// Before | |
path.moveToPoint(point) | |
string.characterAtIndex(3) | |
// After | |
path.move(to: point) | |
string.character(at: 3) |
現代化的調度:dispatching
// Before | |
let queue = dispatch_queue_create("com.test.myqueue", nil) | |
dispatch_async(queue) { | |
print("Hello World") | |
} | |
// After | |
let queue = DispatchQueue(label: "com.test.myqueue") | |
queue.asynchronously { | |
print("Hello World") | |
} |
集合類型有了新的展示形式
之前,當你想要在集合類型中從一個index一到另一個,你須要使用index的successor方法。可是如今你使用c.index(after:index)就可讓collection之間的移動成爲現實。collection如今有了一個任何可比較類型的index
myIndex.successor() => myCollection.index(after: myIndex) | |
myIndex.predecessor() => myCollection.index(before: myIndex) | |
myIndex.advance(by: …) => myCollection.index(myIndex, offsetBy: …) |
(下面的模塊除非是本身手動建立Range對象,不然我認爲沒有多大做用)
一方面,Range已經被劃分爲不少的類型。Range, ClosedRange, CountableRange, and CountableClosedRange.ClosedRange如今包括ranges擴寬了最大值類型(0...Int8.max).Range和ClosedRange 已經不能迭代了。他們如今須要一個可比較的對象做爲他們的結合(因此你能夠建立Range<String>)
OC的id已經被導入做爲Swift的Any 類型
引用蘋果的話是:
Since ‘id’ now imports as ‘Any’ rather than ‘AnyObject’, you may see errors where you were previously performing dynamic lookup on ‘AnyObject’.
因爲id類型被當作了Any類型而不是AnyObject,因此你可能會看到一些錯誤當你先前查找AnyObject的動態類型時候。
一些很小的改變(你也許都沒有注意到)
可選的操做符比較已經被移除
如今nil類型時能夠比較的。案例:[3,nil,1,2].sorted() // return [nil,1,2,3]
如今你須要解包可選類型在你比較以前(以下):
// Before | |
let a: Int = 4 | |
let b: Int? = 5 | |
if a > b { ... } | |
// After | |
guard let b = b, a > b else { ... } | |
// or | |
if let b = b { | |
if a > b { ... } | |
} | |
// or | |
if let b = b, a > b { ...} |
這也許是一件好事,可是可能拆除你的單元測試
閉包的參數名字和標籤
不少的閉包參數的名字已經被重命名或者已經做爲了可選
例如:
// before | |
words.sort(isOrderedBefore: >) | |
let sum = measurements.reduce(0, combine: +) | |
// after | |
words.sort(by: >) | |
let sum = measurements.reduce(0, +) |
flattern 重命名爲joined
處理UnsafePointer<T>
非對象的指針類型爲空行使用可選類型表示
Rounding floating (四捨五入浮點值是一個值的責任,如今)
之前咱們使用全局的C函數floor和ceil去四捨五入一個浮點值類型。這些函數仍然可使用可是已經考慮唄廢棄。
所以咱們應該採用以下方式:
(4.4).rounded() // == 4.0 | |
(4.5).rounded() // == 5.0 | |
(4.0).rounded(.up) // == 4.0 | |
(4.9).rounded(.down) // == 4.0 | |
(4.0).rounded(.down) // == 4.0 |
這裏還有另外的rounding的規則,以下:
泛型類型的別名(Generic type aliases)
操做符的聲明有了語法的改變
// Before | |
infix operator <> { precedence 100 associativity left } | |
// After | |
precedencegroup ComparisonPrecedence { | |
associativity: left | |
higherThan: LogicalConjunctionPrecedence | |
} | |
infix operator <> : ComparisonPrecedence |
OC的常量如今有了Swift類型
咱們再也不使用名字字符串做爲OC的內在操做符
// Before | |
// HealthKit has the following strings: | |
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMassIndex; | |
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyFatPercentage; | |
HK_EXTERN NSString * const HKQuantityTypeIdentifierHeight; | |
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMass; | |
HK_EXTERN NSString * const HKQuantityTypeIdentifierLeanBodyMass; | |
// They were previously imported as swift Strings | |
// After | |
// Instead of importing this as a string, Swift will import this like so: | |
enum HKQuantityTypeIdentifier : String { | |
case BodyMassIndex | |
case BodyFatPercentage | |
case Height | |
case BodyMass | |
case LeanBodyMass | |
} |
這些東西可能過小你根本沒有注意到
NSError 已經提供了橋樑
// Before | |
catch let error as AVError where error == .diskFull {
|
|
// AVError is an enum, so one only gets the equivalent of the code. | |
// There is no way to access the localized description (for example) or | |
// any other information typically stored in the ``userInfo`` dictionary. | |
} | |
// or | |
catch let error as NSError where error._domain == AVFoundationErrorDomain && error._code == AVFoundationErrorDomain.diskFull.rawValue { | |
// okay: userInfo is finally accessible, but still weakly typed | |
} | |
// And in usage: | |
catch let error as NSError where error._domain = AVFoundationErrorDomain { | |
if let time = error.userInfo[AVErrorTimeKey] as? CMTime { | |
// ... | |
} | |
} | |
// After | |
catch let error as AVError { | |
if let time = error.time { | |
// ... | |
} | |
} |
nulTerminatedUTF8CString 重命名爲utf8CString
移除了字符串的UnicodeScalar重複的初始化方法
Failable UnicodeScalar初始化如今返回的是可選類型
元組不在撒潑
// No longer allowed | |
func foo(a: Int, b: Int) {} | |
let x = (1, b: 2) | |
foo(x) |
沒有了currying func聲明的語法
// Before: | |
func curried(x: Int)(y: String) -> Float { | |
return Float(x) + Float(y)! | |
} | |
// After: | |
func curried(x: Int) -> (String) -> Float { | |
return {(y: String) -> Float in | |
return Float(x) + Float(y)! | |
} | |
} |
上面已經列舉了因此的Swift3的變化?
顯然不是。
這裏還有一些意見仍然在省查中,些許意見已經被推遲到3.x。我也選擇了一些我認爲很是小的不包括在一些附加或者改變。像removal和merger這些不常用的API
此外,我尚未必要更深層次的研究任何一個變化,而是對於每個變化選擇一些更高層次的審查。
有一些變化會在他們的範圍內發生連鎖反應。若是你對這個特殊的變化感興趣的話,你應該看看SwiftEVO工程
Changes under active review / awaiting review for this release
Changes deferred to a 3.x release
Things I’m sure we’re all glad were rejected: