是否从Swift2.3升级到3.0呢?
如果你有一个意义非常重大的Swift编码库(就像我们在VTS中做的一样),那么别犹豫了,赶快更新吧。另外为了项目的需要,Xcode的更新,跟随苹果的步伐,最新的技术,还是麻溜的跟上把。
但是如果你的Swift代码不是非常的繁重,那么你就直接忽略2.3吧。
下面有一些事情需要记住:
1.依赖库非常重要,确保你的依赖库支持2.3还是3.0-大多数的lib/framework是两者都支持的(Alamofire,Charts).然而升级到3.0是你的唯一途径。新的发展将会在Swift3.0展开。所有的swift2.3版本的相关依赖库将会被冻结,也就是不在更新。
2.Xcode8.x 将会移除对Swift2.3的支持。Swift2.3注定是大型工程的一个过渡品。所以我们需要努力的升级到swift3.0
3.如果你有一个私有的CocoaPods用于分享代码在多个工程中,那么你不得不马上更新。
当然你可以只更新到2.3,但是你只能推迟,因为在发布Xcode9之前你必须移植到Swift3。
将问题从Swift2.2迁移到2.3
这个迁移可能将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的规则,如下:
- toNearestOrAwayFromZero
- toNearestOrEven
- towardZero
- awayFromZero
泛型类型的别名(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
- Add sequence-based initializers and merge methods to Dictionary
- Allow using optional binding to upgrade self from a weak to strong reference
- Add AnyHashable to standard library
Changes deferred to a 3.x release
- Rotate algorithm
- Removal of .self
- Allow Swift types to provide custom Obj-C representations
- Remove bridging conversion behavior from dynamic casts
- Rationalizing sequence end-operation names
Bonus:
Things I’m sure we’re all glad were rejected:
- Removal of where from the Swift language
- Require self to access instance members
- Removal of access modifiers from extensions
来源:oschina
链接:https://my.oschina.net/u/2483082/blog/753483