前言
对于开发人员来说,Swift3.0的变化会令你的程序几乎处处报错,目前Swift还在发展阶段并不能向下兼容,但是试想一下如果Apple没有追求更好的精神又怎么会作出如此多的更改。今天的重点就是带翻译的介绍Swift3.0的变化。
Swift3.0的变化( 部分)
SE-0002: 删除currying的func声明语法
柯里化函数声明语法func foo(x: Int)(y: Int) 的用处有限,实现复杂,所以说我们应该删除它。
// Current:
func curried(x: Int)(y: String) -> Float {
return Float(x) + Float(y)!
}
// Proposed:
func curried(x: Int) -> (String) -> Float {
return {(y: String) -> Float in
return Float(x) + Float(y)!
}
}
SE-0003: 函数参数中不再使用var关键字
对于函数参数来说,var和inout修饰方法会产生很多语义上的混淆。虽然这两者都可以让这个参数变成可修改的,但是只有inout方法才能让这个参数修改后真正的写会原始地址中。为了避免出现这个语义的混淆,swift3.0里函数参数中不再使用var关键字。
(ps:Swift新特性元组(Tuple)和其关键字inout之前写的笔记里面有介绍inout的功能)
func foo(var i: Int) {
i += 1 // illegal
}
//上面方法会报错,可换成下面这种
func foo( i: Int) {
var i = i
i += 1
}
SE-0004: 移除自增运算符++和自减运算符—
Swift发展的早期,自增自减运算符就被引进了,它是从C语言搬过来的。当时增加这两个运算符的时候并没有太多的考虑。这份文件提供了一个新的外观,并最终建议我们完全移除它们,是因为它们自增自减运算符在运用的时候容易造成混淆。比如说 ++i,i++,--i,i--
// Current
x++
// Proposed
x += 1
SE-0005: 将Objective-C的API更好地接入到Swift中
SE-0006: 将API指南应用于标准库中
SE-0023: Swift API设计指南
大家都知道Swift诞生在Objective-C已经发展的比较成熟的情况下,为了保证oc开发人员能够比较成功的过渡到Swift,所以说在Swift的初期,很多的库名和方法名都尽量和oc的保持一致。Swift3.0做了很大的改变,有种在摆脱oc影子的趋势。举个🌰,Swift 2里面UIBezierPath API的一部分:
class UIBezierPath : NSObject, NSCopying, NSCoding {
convenience init(ovalInRect: CGRect)
func moveToPoint(_: CGPoint)
func addLineToPoint(_: CGPoint)
func addCurveToPoint(_: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)
func addQuadCurveToPoint(_: CGPoint, controlPoint: CGPoint)
func appendPath(_: UIBezierPath)
func bezierPathByReversingPath() -> UIBezierPath
func applyTransform(_: CGAffineTransform)
var empty: Bool { get }
func containsPoint(_: CGPoint) -> Bool
func fillWithBlendMode(_: CGBlendMode, alpha: CGFloat)
func strokeWithBlendMode(_: CGBlendMode, alpha: CGFloat)
func copyWithZone(_: NSZone) -> AnyObject
func encodeWithCoder(_: NSCoder)
}
Swift3.0里面相同的部分变成了:
class UIBezierPath : NSObject, NSCopying, NSCoding {
convenience init(ovalIn rect: CGRect)
func move(to point: CGPoint)
func addLine(to point: CGPoint)
func addCurve(to endPoint: CGPoint, controlPoint1 controlPoint1: CGPoint, controlPoint2 controlPoint2: CGPoint)
func addQuadCurve(to endPoint: CGPoint, controlPoint controlPoint: CGPoint)
func append(_ bezierPath: UIBezierPath)
func reversing() -> UIBezierPath
func apply(_ transform: CGAffineTransform)
var isEmpty: Bool { get }
func contains(_ point: CGPoint) -> Bool
func fill(_ blendMode: CGBlendMode, alpha alpha: CGFloat)
func stroke(_ blendMode: CGBlendMode, alpha alpha: CGFloat)
func copy(with zone: NSZone = nil) -> AnyObject
func encode(with aCoder: NSCoder)
}
SE-0007: 移除C语言风格的for循环(条件与增量下)
// Current
for var i = 0 ; i < 10 ; i++ {
print(i)
}
// Proposed
for i in 0 ..< 10 {
print(i)
}
SE-0008: 为可选序列增加一个Lazy的flatMap
已经被Swift 2.2接受!
SE-0016: 添加构造函数Int和UInt进行UnsafePointer和UnsafeMutablePointer之间的转换
SE-0017: 使用UnsafePointer去修改Unmanaged
标准库Unmanaged<Instance> struct 提供了一个类型安全的包装对象,这个对象不参与在ARC里面,它允许用户进行手动的retain或者release。
- 下面的方法就是用于Unmanaged和UnsafePointer之间的转换
SE-0019: Swift增加Testing
测试是现代软件开发的一个重要组成部分。集成的测试加入到Swift的Package Manager,将有助于确保一个稳定可靠的系统。
SE-0028: 更新Swift的debug标识符(例如:FILE等)
这一项建议重命名以下标示符:
SE-0029: 从函数应用中,移除“tuple splat”表达形式
Swift3.0之前,除了可以使用典型的方法调用函数之外,我们还可以通过传入N个作为函数参数列表。不过这个鲜为人知的特性正在swift3.0中被移除,因为它仅是纯粹的语法糖而已。
// Current
func swapMe<T>(inout a: T, inout b: T) {
let temp = a
a=b
b = temp
}
// Proposed
func swapMe<T>( a: inout T, b: inout T) {
let temp = a
a=b
b = temp
}
SE-0032: SequenceType添加first(where:)方法
SE-0033: 导入Objective-C的常量作为Swift类型
给出一个Objective-C文件的常量列表,添加一个属性,这个属性在Swift里面将作为一个枚举值或者一个结构体导入。使用RawRepresentable转换为原始类型。我们就可以使用更多类型安全的对象,这样也可以使我们的Swift(Objective-C)代码可读性更强,更容易上手。
SE-0034: 消除行控制的Debug标识符声明的歧义
在Swift的SE-0028改变被接受后,#line标识符指的是一个标识符映射到调用点的行数在文件中作为一个控制语句的一部分使用。这一项建议提议#setline去代替#line,为了符合这个要求:“一旦名称和语法是固定的,我们可以重命名指令和删除空格的规则”。
- Swift使用下面的语法来定义行控制语句:
line-control-statement → #line
line-control-statement → #line line-number file-name
line-number → A decimal integer greater than zero
file-name → static-string-literal
- 这项建议的具体设计如下:
line-control-statement → #setline
line-control-statement → #setline line-number file-name
line-number → A decimal integer greater than zero
file-name → static-string-literal
SE-0037: 注释和操作符之间的交互
在确定一个操作者是否有前缀、后缀、或者中缀的处理上这里有一些不一致的意见。他们有时被视为空白,有时为非空白,这取决于他们对操作者的左或右,和注视本身的内容。这项建议提出了一套统一的规则,如何在这些情况下,加以分析。
SE-0039: 使Playground字面量现代化(Modernizing Playground Literals)
- Color, image, and file的字面量目前表示为:
[#Color(colorLiteralRed: red, green: green, blue: blue, alpha: alpha)#]
[#Image(imageLiteral: localResourceNameAsString)#]
[#FileReference(fileReferenceLiteral: localResourceNameAsString)#]
- 简化构造函数,消除潜在的语法冲突,并遵循Swift其他标识符的先例,提议了标识符:#colorLiteral, #imageLiteral, and #fileLiteral.
color-literal → #colorLiteral(red: unit-floating-point-literal, green: unit-floating-point-literal, blue: unit-floating-point-literal, alpha: unit-floating-point-literal)
unit-floating-point-literal → floating point number greater or equal to zero, less than or equal to one
image-literal → #imageLiteral(resourceName: image-resource-name)
image-resource-name → static-string-literal referring to image resource name
file-literal → #fileLiteral(resourceName: file-resource-name)
file-resource-name → static-string-literal referring to local resource name
然而这些参数的标签不适合实际的初始化,所以说使用以下相应的初始化:
protocol _ColorLiteralConvertible {
init(colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float)
}
protocol _ImageLiteralConvertible {
init(imageLiteralResourceName path: String)
}
protocol _FileReferenceLiteralConvertible {
init(fileReferenceLiteralResourceName path: String)
}
// Current
@available(*, unavailable, renamed="MyRenamedProtocol")
// Proposed, using : instead of =
@available(*, unavailable, renamed: "MyRenamedProtocol")
SE-0043: 具有多个模式的“case”中的声明变量
当一个模式声明具有相同名字和类型的多个变量的时候,在Swift 2是会报错的(case
labels with multiple patterns cannot declare variables. ),Swift 3.0将移除错误。这种改变减少了重复的代码,因此减少了错误。当变量没有定义时,它与多模式匹配是一致的。
SE-0044: 导入成员
Swift导入C的声明,允许Swift的代码和C语言的库和框架进行交互。但是这样导入APIs 会觉得交互方面不是那么自然。这项建议旨在提供一种机制为C API作者指定导入的函数和变量作为导入Swift类型成员的能力。
- 举个🌰,Core Graphics C API
// Current
override func drawRect(rect: CGRect) {
let context: CGContext = UIGraphicsGetCurrentContext()!
let toCenter = CGPoint(x: bounds.width/2.0, y: bounds.height/2.0)
let angle = CGFloat(M_PI / 16)
var transform = CGAffineTransformIdentity
for _ in 0..<32 {
triangulateRect(bounds, inputTransform: transform, context: context)
transform = CGAffineTransformTranslate(transform, toCenter.x, toCenter.y)
transform = CGAffineTransformRotate(transform, angle)
transform = CGAffineTransformTranslate(transform, -toCenter.x, -toCenter.y)
}
CGContextSetLineWidth(context, bounds.size.width / 100)
CGContextSetGrayStrokeColor(context, 0.5, 1.0)
CGContextDrawPath(context, .Stroke)
}
func triangulateRect(bounds: CGRect, inputTransform: CGAffineTransform,
context: CGContext) {
var transform = inputTransform
// Triangle from top left corner, to bottom middle, to top right, and then
// draw the boundary
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)
}
// Proposed
override func drawRect(rect: CGRect) {
let context: CGContext = UIGraphicsGetCurrentContext()!
let toCenter = CGPoint(x: bounds.width/2.0, y: bounds.height/2.0)
let angle = CGFloat(M_PI / 16)
var transform = CGAffineTransform.identity
for _ in 0..<32 {
triangulateRect(bounds, inputTransform: transform, context: context)
transform = transform.translate(toX: toCenter.x, toY: toCenter.y)
.rotate(angle: angle)
.translate(toX: -toCenter.x, toY: -toCenter.y)
}
context.lineWidth = bounds.size.width / 100
context.strokeColor = CGColor(gray: 0.5, alpha: 1.0)
context.drawPath(mode: .Stroke)
}
func triangulateRect(bounds: CGRect, inputTransform: CGAffineTransform,
context: CGContext) {
var transform = inputTransform
// Triangle from top left corner, to bottom middle, to top right, and then
// draw the boundary
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)
}
SE-0046: 函数的所有参数声明方式要一致性,包括第一个参数声明方式
// 从第一个参数就必须指定参数名,除非使用"_"明确指出省略参数
func sum(num1:Int,num2:Int)->Int{
return num1 + num2
}
sum(num1: 1, num2: 2) // old: sum(1,2)或者sum(1, num2: 2)
SE-0047: 默认在非Void函数返回类型下,返回结果未使用时会有警告
Swift3.0 中方法的返回值必须有接收不然会报警告,为了避免开发人员忘记接收返回值的情况,但是有些情况下确实不需要返回值可以使用"_"接收来忽略返回值。也可以增加@discardableResult声明,告诉编译器我这个方法是可以不用接收返回值的。
SE-0048: 泛型类型别名
Swift3.0提议之前,typealias是单一的,这也就限制了它,只能将某个特定的类型,通过typealias来定义成新的名字,而不能将整个泛型类型进行重命名。举个🌰:
class Person<T> {}
typealias WorkId = String
typealias Worker = Person<WorkId>
Swift3.0提议了可以将整个泛型类型进行重命名:
class Person<T> {}
typealias Worker1<T> = Person<T>
SE-0049: 将声明式@noescape与@autoclosure改为类型属性
这一项提议的意义和SE-0031的提议一样:提高一致性和减少冗余的语言。
// Current
// declaration attribute
func f(@noescape fn : () -> ()) {}
func f2(@autoclosure a : () -> ()) {}
//Proposed
//type attribute.
func f(fn : @noescape () -> ()) {}
func f2(a : @autoclosure () -> ()) {}
SE-0053: 从函数参数中移除let
默认情况下函数参数是不可变的,显示的声明函数参数是let,显得语法冗余了,所以说提议从函数参数中移除let。
// Current
func foo(let x: Int) { ... }
// Proposed
func foo(x: Int) { ... }
SE-0054: 废弃ImplicitlyUnwrappedOptional类型
这项提议我们要减少隐式解包可选类型(ImplicitlyUnwrappedOptional)的使用,因为Swift的类型设计是十分安全的,隐式解包可选类型破坏了这种安全性,所以说我们要减少使用隐式解包可选类型。只可以在以下几个地方使用:
- 属性和变量声明
- 构造器声明
- 方法声明
- 角标声明
- 参数声明
未完待续……
推荐一篇文章:Swift3
本文所写的内容是看文档之后自己的理解,又不对的地方,欢迎指出。