Xcode 6.3 Beta Release Notes看出,Xcode 6.3 Beta包含了很多颇为值得开发者期待的改变,共计50多处改动,同时修改了Objective-C的语法,足见苹果对Swift语言的重视。而其代码迁移工具可以帮助开发者将其代码从Swift 1.1(Xcode 6.1)升级至Swift 1.2(Xcode 6.3),具体执行编辑菜单(Edit)->转换(Convert)-至(To)Swift1.2即可。 具体更新如下:

Swift语言的增强

  • Swift现在支持目标增量编译,例如当一个文件改变时不会重新编译Target中的每一个文件。这个基于固有依赖分析。所以你依然会看到有很多文件在必要情况下被重编。如果你发现需要重编但没有重编的情况,请报一个Bug出来。清理Target后再编,会按照往常的流程进行。

  • 增加了一个新的Set数据类型,它提供了元素唯一化,且有完整语义的通用数据类型集合。它和NSSet类型桥接,提供和Array和Dictionary相类似的功能。

  • if let语句现在被扩展为可以支持多条条件判断:

1
2
3
if let a = foo(), b = bar() where a < b,  
let c = baz() {  
 }

它允许你测试多种选择,并且包含一个bool判断。当然这种情况不包含嵌套判断。

let常量现在生成时不需要立即初始化,新的规则是let常量必须在被首次使用前初始化即可(和var一样)。或者说它只能被初始化,也就是说在初始化后它不能再被改变或者重新赋值,可用的模式如下:

1
2
3
4
5
6
7
let x: SomeThing  
 if condition {  
 x = foo()  
 else {  
 x = bar()  
 }  
 use(x)

这个正常的来说需要var变量用法,尽管这里没有任何修改的操作。

  • "Static"静态方法和属性现在允许在class中使用(作为“class final”的别名)。你现在可以在类中声明一个静态存储属性,它享有全局存储空间和首次使用再初始化的惰性构造功能。协议Protocal现在会声明一个static的类型要求而不是声明一个class的要求。

  • 对于表达式闭包的类型引用有了几点改进:

  1. 含有单返回语句的闭包现在类型检查时以单表达式闭包处理。

  2. 匿名的且含有非空返回类型的单表达式现在可以用在Void上下文中。

  3. 多表达式的闭包类型的情况可能无法被类型推断出来,这归功于缺乏返回类型的情况能被正确的推断出来。

  • Swift中的枚举类型现在可以通过@objc关键字导出到Objective-C中。@objc的枚举类型必须定义一个整型的原始类型,并且该枚举不能泛型化或者不能使用关联值。由于Objective-C中的枚举类型没有命名空间,所以导出到Objective-C中的枚举类型以枚举名字和case项目名字的组合的方式使用。 比如在Swift中的声明:

1
2
3
4
@objc  
 enum Bear: Int {  
 case Black, Grizzly, Polar  
 }

导出到Objective-C:

1
2
3
typedef NS_ENUM(NSInteger, Bear) {  
BearBlack, BearGrizzly, BearPolar  
};
  • Objective-C语言的扩展语法现在可以判断出Objective-C API中指针或者block的是否为空,同时允许不带ImplicitlyUnwrappedOptional协议地导出Objective-C API函数。

  • Swift现在可以部分支持导入C的联合类型,包括unions、bitfileds、SIMD vector类型以及其他Swift的不支持的C特性。这些不被支持的元素不能在Swift中的直接访问,但是在Swift中,Objective-C或者C可以以参数或者返回类型的方式使用。这包括Foundation NSDecimal类型、GLKit GLKVector和GLKMatrix类型,以及其他一些类型。

  • 被导入的C结构体现在在Swift中有一个默认的构造器,它会将结构体中的所有的元素初始化为0,例如:

1
2
3
import Darwin  
 var devNullStat = stat()  
 stat("/dev/null", &devNullStat)

如果一个结构体的元素不能被正确的初始化为0(比如被标记为新的_nonnull标示符时),这个默认的构造器将会终止。

  • String的索引类型间新的转换API现在可以用了,如String、String.UnicodeScalarView、String.UTF16View以及String.UTF8View, 同时每个String View转换为String的函数也可使用。

  • 类型值在println函数或者字符串内插算法中现在可以打印完整的类型名称了:

1
2
3
toString(Int.self) // 打印 “Swift.Int"  
 println([Float].self) // 打印 "Swift.Array”  
 println((Int, String).self) // 打印 "(Swift.Int, Swift.String)"
  • 一个新的“@noescape”属性可以用在函数的闭包参数上,这意味着这个参数是唯一可被调用的(或者用在函数调用时以参数的方式出现),其意思是它的生命周期比函数调用的周期短,这有助于一些小小的性能优化,但最重要的是它屏蔽了闭包中对self.的需求。这使得函数的控制流比其他更加透明。在未来的beta版本中,标准库函数将普遍采用这种特性,比如autoreleasepool():

1
2
3
4
5
func autoreleasepool(@noescape code: () -> ()) {  
   pushAutoreleasePool()  
   code()  
   popAutoreleasePool()  
 }
  • 相比Swift 1.1,Swift 1.2在很多方面的性能上有本质的提高,比如多维数组算法更快,未优化的代码更加快速。

  • 表达式类型的错误诊断有了很大的提高。

  • 很多通用表达式的检查效率有很大提高,这个有助于降低编译时间和减少“expression too complex”的错误。

Swift语言的改变

  • “确保转换”和“可失败转换”的概念现在被分为两个操作符。可失败转换现在使用as!运算符,这个!感叹号可以让代码的读者更清晰的明白本次转换可能失败并触发一个运行时错误。“as”操作符会保持向上转换(比如“someDerivedValue转换为Base”)或者类型标注(“0 转换为Int8”),它保证了转换不会失败。

  • 结构体和类构造器中的let不可变属性现在被规范为更加标准的通用模型:lets类型初始化后将永不会被改变或重新赋值。以前的实现是,可以在构造器中任意修改,而现在它们只允许被初始化和提供值操作。如果一个属性在声明时已经赋值,那么它会被所有的构造器认为已经含有初始值。

  • 从桥接Objective-C类 (NSString/NSArray/NSDictionary)到它Swift中值类型的隐式转化被移除。这将是Swift的类型系统更加简单和可预测。这意味着:

1
2
3
4
5
import Foundation  
func log(s: String) { println(x) }  
let ns: NSString = "some NSString" // Okay  
log(ns) // 错误  
// "'NSString' 不能转换为 'String'"

为了完成桥接转换,需要用显式转化符标注:

1
log(ns as String) // succeeds

从Swift类型到Objective-C类型的桥接隐式转换依然被允许,比如:

1
2
3
func nsLog(ns: NSString) { println(ns) }  
 let s: String = “some String”  
 nsLog(s) // okay: implicit conversion from String to NSString is still permitted
  • @autoclosure现在标注在参数上,而不是标注在参数的类型上。比如:

1
2
3
4
//以前我们这样写:  
 func assert(predicate : @autoclosure () -> Bool) {… }  
//现在需要这样写:  
 func assert(@autoclosure predicate : () -> Bool) {… }
  • 使用在函数参数上的 @autoclosure属性现在含有@noescape新属性的功能,这个改进限制了@autoclosure作为控制流程以及惰性计算的能力。

  • 柯里化函数现在可以指定参数标签了:

1
2
3
4
func curryUnnamed(a: Int)(_ b: Int) { return a + b }  
curryUnnamed(1)(2)  
func curryNamed(first a: Int)(second b: Int) -> Int { return a + b }  
curryNamed(first: 1)(second: 2)
  • Swift现在可以检测在Swift类型系统中覆盖和重写的差异以及通过Objective-C运行时可见的影响。比如,下面Objective-C类中对属性的setter和类扩展中对方法的“setProperty”它们之间的冲突现在可以被诊断:

1
2
3
4
5
6
7
8
9
class A : NSObject {  
 var property: String = "Hello" // 注意: Objective-C 方法 'setProperty:’  
 // 以前这里“属性”这里是通过setter声明  
 }  
 extension A {  
 func setProperty(str: String) { } // 错误:方法"setProperty"  
 // 重复声明了Objective-C方法  
 //'setProperty:'  
 }

同样地检查在Objective-C中重写:

1
2
3
4
5
6
7
class B : NSObject {  
func method(arg: String) { } // 注意:重写操作  
// 这里含有类型:'(String) -> ()'  
}  
class C : B {  
func method(arg: [String]) { } // 错误: 重写的选择器方法含有不匹配的类型'([String]) -> ()'  
}

和协议的适配性一样:

1
2
3
4
5
6
7
8
class MyDelegate : NSObject, NSURLSessionDelegate {  
 func URLSession(session: NSURLSession, didBecomeInvalidWithError: Bool){ }  
 // 错误:Objective-C 方法 'URLSession:didBecomeInvalidWithError:'  
 //由方法提供: 'URLSession(_:didBecomeInvalidWithError:)'  
 // 和可选类型的需求方法相冲突:  
 // 'URLSession(_:didBecomeInvalidWithError:)' 在协议  
 // 'NSURLSessionDelegate'  
 }

Swift语言Bug修复

  • 动态转换符(“as!”, “as?“和“is”)现在可以用在Swift的协议类型上,只要该协议类型没有关联类型。

  • 在Playground增加的一致性需求现在可以按照预期工作了,比如:

1
2
3
4
5
6
7
8
9
10
struct Point {  
 var x, y: Double  
 }  
 extension Point : Printable {  
 var description: String {  
 return "(\(x), \(y))"  
 }  
 }  
 var p1 = Point(x: 1.5, y: 2.5)  
 println(p1) // prints "(1.5, 2.5)”
  • 导入的没有文档化的NS_ENUM类型,比如UIViewAnimationCurve,现在可以通过init(rawValue:) 构造器从它的原始整型类型转换出来而不会重设为nil,为解决这个问题而用替代方法unsafeBitCast编写的代码现在可以使用原始值构造器编写了。比如:

1
2
3
let animationCurve =  
nsafeBitCast(userInfo[UIKeyboardAnimationCurveUserInfoKey].integerValue,  
UIViewAnimationCurve.self)

现在可以写为:

1
2
let animationCurve = UIViewAnimationCurve(rawValue:  
userInfo[UIKeyboardAnimationCurveUserInfoKey].integerValue)!
  • 在枚举类型中负浮点数可以用作原始值了。

  • 指向Objective-C类,或者Swift中继承自Objective-C对象的无主引用,在该无主引用指向的对象释放后无主引用被重新赋值时不会再Crash。

  • 含有观察访问器的变量或者属性如果它可以从初始值表达式中推断出类型就无需显式指定类型。

  • NSClassFromString函数搜索失败时其结果和nil的比较现在工作正常。

  • 子类中的重写基类含有可选类型的方法时,如果涉及到可选类型的转换将不会导致Crash。

1
2
3
4
5
6
class Base {  
 func foo(x: String) -> String? { return x }  
 }  
 class Derived: Base {  
 override func foo(x: String?) -> String { return x! }  
 }

关于Objective-C语言的增强

Objective-C API中可以表示参数,返回值,属性,变量等等的“nullability”属性。比如,下面是表达很多UITableView API的为空特性:

1
2
3
4
5
-(void)registerNib:(nonnull UINib *)nib forCellReuseIdentifier:(nonnull  
SString *)identifier;  
-(nullable UITableViewCell *)cellForRowAtIndexPath:(nonnull  
SIndexPath)indexPath;  
@property (nonatomic, readwrite, retain, nullable) UIView *backgroundView;

这个nullability标示符影响了Objective-C API在Swift的可选类型值,nonnull标示符标示的类型将会以非可选的类型的导入,这个用来替代隐式解封可选类型如(e.g., UINib!)。而nullable标示符标示的类型则会以可选类型导入(如UITableViewCell?),所以下面的API在Swift中表现如下:

1
2
3
func registerNib(nib: UINib, forCellReuseIdentifier identifier: String)  
func cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell?  
var backgroundView: UIView?

可空特性标示符也可以用在指针类型,包括C指针,block指针和C++成员指针,使用双下划线方式,比如:

1
void enumerateStrings(__nonnull CFStringRef (^ __nullable callback)(void));

这里,它自身的回调函数是nullable的,但是它的回调函数的返回类型为nonnull,所以这个API在Swift以如下方式使用:

1
func enumerateStrings(callback: (() -> CFString)?)

总的来说,可空特性标示符有三种,可以用双下划线(用在任何指针类型),或者没有下划线的(用在Objective-C属性,方法结果类型或者方法参数类型)。

  • 特别是在Objective-C API中,很多指针倾向于nonnull,因此Objective-C提供了“audited”域(通过新的#pragma),它会认为未被标注的指针为nonnull,比如下面的例子等同于上面第一个例子,但是它用的是“audited”域来简化语句表达:

1
2
3
4
5
6
7
8
#pragma clang assume_nonnull begin  
 // …  
 -(void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString  
*)identifier;  
 -(nullable UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath)indexPath;  
 @property (nonatomic, readwrite, retain, nullable) UIView *backgroundView;  
 // …  
 #pragma clang assume_nonnull end
  • 为了保证代码的连续性,我们强烈建议你在所有的Objective-C头文件使用“audited”域来表述其api的可空性,同时避免null_unspecified情况,建议使用在将可空性引入到现有的头文件时采用该功能作为过渡工具。

  • Objective-C增加的nullability注解不会影响它的向后兼容性也不会影响代码的编译。比如nonnull在有些情况下依然可以以nil结束,诸如消息路由到一个为nil的接收器,但是,nullability注解只是提高Swift的编程体验,它会在Objective-C中产生一个新的警告,诸如朝一个nonnull的参数赋一个nil的话,这使得Objective-c API更加高效以及使用的正确。

  • Objective-C可以通过null_resettable来表达属性的空属性,该属性setter访问器允许将其设置为nil(设置该属性为默认值),但是它的getter访问器不会提供一个nil值(因为它提供了默认值),有一个这样的属性如UIView’s tintColor,如果没有tint颜色指定时它会提供一个默认的tint颜色值,如:

1
@property (nonatomic, retain, null_resettable) UIColor *tintColor;

这样的API在Swift使用隐式强制解封的方法使用:

1
var tintColor: UIColor!

C指针类型的参数或者Block指针类型可以使用noescape新属性标志,它用来标明这个指针参数不会离开这个函数或者方法而使用。这种情况下,可以安全的传递一个局部变量地址,noescape block指针在Swift中将会被映射为@noescape参数:

1
void executeImmediately(__attribute__((noescape)) void (^callback)(void);

将被影射到Swift为:

1
func executeImmediately(@noescape callback: () -> Void)
  • LLDB现在包含了一个printf()函数去计算C/C++/Objective-C表达式,这个将在arm64设备上提升表达式计算的体验,但是可能和用户在.lldbinit定义的表达式前缀冲突,如果你发现在表达式计算时出现错误,这可能就是root cause。

  • XCode 6.3将Apple LLVM编译器更新为6.1.0,这个新的编译器版本包含了对C++14标准的全部支持,包括大量的增强的警告诊断和新的优化,对于arm64架构的支持进行了有效的重构来支持ARM的实现, 这个将明显影响矩阵内联函数计算。

  • 为arm64 vfma/vfms内联函数预定的参数被移除,虽然这个改变不会产生一个编译时错误,但是它会中断代码运行时操作,我们需要明确这个变化来减少风险。默认的,编译器现在会对使用这种内联属性提供警告并维持固有的行为,在尽可能的情况下,你需要接受这个变化并且定义USE_CORRECT_VFMA_INTRINSICS宏为1告诉编译器接收警告,当然你也可以可以USE_CORRECT_VFMA_INTRINSICS宏为0来屏蔽警告并保持固有行为。但是请不要保留这样的代码太久,因为我们计划在未来的版本中移除对这种旧行为的支持。

  • 含有自动尺寸标志的视图以及包含在UITableView、UICollectionView或NSScrollView的视图在打开文档时不会再出现对齐错误。

Swift在1.2版本的变化的更多相关文章

  1. 【jQuery基础学习】10 简单了解jQuery Mobile及jQuery各个级别版本的变化

    关于 jQuery Mobile jQuery Mobile是为了填补jQuery在移动设备应用上的一个新项目.它应用了HTML5和CSS3. 主要特性 基于jQuery构建. 采用与jQuery一致 ...

  2. OpenSSL所有版本的变化,从1.1开始架构有所变化,生成的lib名称也有所不同了,以及对Qt的影响

    The complete explanation is that 1.0.x and 1.1.x do not have the same naming conventions for the gen ...

  3. iOS8.3发布了Swift 1.2带来哪些新变化

    苹果前几日在面向开发者推送iOS 8.3 Beta的同时,还发布了版本号为6D520o的Xcode 6.3 Beta,其中便包含了iOS 8.3 Beta和OS X v10.10 SDK,并进一步提升 ...

  4. Vue版本过渡变化

    到了2.0以后,有哪些变化: 在每个组件模板,不在支持片段代码 之前: <template id="aaa"> <h3>我是组件</h3>< ...

  5. swift - xcode - pod升级版本和降级版本

    1. 查看当前版本 pod --version 2.如果安装过pod,更新命令 新版 sudo gem install -n /usr/local/bin cocoapods --pre 旧版 sud ...

  6. Pytorch 0.3加载0.4模型及其之间版本的变化

    1. 0.4中使用设备:.to(device) 2. 0.4中删除了Variable,直接tensor就可以 3. with torch.no_grad():的使用代替volatile:弃用volat ...

  7. php5.3.3版本前后变化中php-v和sbin/php-fpm -v

    重装php-fpm试试,遂去http://php-fpm.org/download/想下载个新版本的php-fpm, 结果发现版本大于5.3.3的PHP内部已经集成了php-fpm,不用再另行安装了. ...

  8. golang各版本的变化

    https://golang.org/doc/https://golang.org/doc/go1.6https://golang.org/doc/go1.5https://golang.org/do ...

  9. Cisco ASA 8.3前及8.3后版本Access-list 变化

    8.2及之前 access-list:源地址是真实IP地址,目的地址是映射地址packet-tracer:源地址为真实IP地址,目的地址为映射地址 8.3及之后access-list:源地址和目的地址 ...

随机推荐

  1. NPOI用WorkbookFactory读写 2007以上格式文件(xlsx)

    //我用的最新的2.2.1版本 //第一步:引用DLL,5个全导入,包括ICSHARP.ZIP,是个开源压缩工具包.XLSX是压缩格式,需要它来解压 //第二部: using NPOI.SS.User ...

  2. python 基础(八) os模块

    OS模块 概念:包含了普遍的操作 系统的功能 一.函数 函数名 函数说明 os.name 获取操作系统类型 nt->Windows posix->Linux/Unix os.listdir ...

  3. 转 PHP 正则表达式 以及案例

    2.Perl兼容的语法扩充 Perl兼容的正则表达式的模式类似于Perl中的语法,表达式必须包含在定界符中,除数字.字母.反斜线外的任何字符都可以作为定界符.例如,表达式’/^(?i)php[34]/ ...

  4. pycharm 虚拟环境virtualenv迁移到别的机器 无法读取包的问题

    将virtualenv迁移到别的机器时,发现pycharm 总是无法读取目录下所在的包,后来经过实验终于找到了问题所在: 将自己所建的虚拟环境目录下的orig-prefix.txt中保存的路径,改成新 ...

  5. hihocoder1829 Tomb Raider

    思路: 暴力枚举. 实现: #include <iostream> #include <set> #include <vector> using namespace ...

  6. java实现打开Windows控制台窗口

    在写Python程序的时候突发奇想了一下,能不能用java代码实现打开控制台窗口呢? 经过查询网络资料和java API文档,终于实现了: package com.primeton.cmd; impo ...

  7. 关于sqlserver帐号被禁用问题

    若发现sqlsrver所有帐号不小心被禁用了,这个时候怎么办?用重装吗?不用,仔细看小白是怎么一步一步解开这个谜题的.首先需要Windows帐号设置里重新添加一个新帐号.并将其添加到管理员组里面,然后 ...

  8. CSS-学习笔记五

    1.  权重: 内联:A ID:B Class:C 标签:D 继承:0 2.  文字阴影text-shadow 3.  文字缩进text-index 4.  文本换行 5.  文本溢出 6.  圆角 ...

  9. vba 时间

    Sub tt1() Dim d1, d2 As Date d1 = #//# d2 = #//# Debug.Print "相隔" & (d2 - d1) & &q ...

  10. 博客高亮代码及使用OpenLiveWriter修改之前博客

    简述:  最近查阅前辈资料的时候,看到写的博客很有条理,回头看下自己的乱做麻花,然后来时研究: 他们的代码看起来很漂亮然后我就查资料,在网页版上一直没法出来像他们的格式,后查资料看来的使用客户端工具才 ...