WWDC 2015首日,苹果发布版本号为7A120f的Xcode 7 beta,继续修改Swift语法。Swift 2.0包含了许多非常重要的新特性,最新的OS X 10.11、iOS 9和watchOS 2 SDK还采纳了一些Objective-C的特性来提高Swift的编程体验。
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:”