Swift在1.2版本的变化

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的视图在打开文档时不会再出现对齐错误。
时间: 2024-11-25 13:02:50

Swift在1.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 generated libraries. OpenSSL 1.1.x has moved into what they call the “unified build system” and changed themselves the names of the libraries. This was d

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

关于 jQuery Mobile jQuery Mobile是为了填补jQuery在移动设备应用上的一个新项目.它应用了HTML5和CSS3. 主要特性 基于jQuery构建. 采用与jQuery一致的核心和语法,还使用了jQuery UI的代码和模式. 兼容绝大部分手机平台 轻量级的库 模块化构建 HTML5标记驱动的配置 渐进增强原则 响应设计 强大的Ajax导航系统 易用性 支持触摸和鼠标事件 统一的UI组件 强大的主题化框架 基本应用 默认情况下,移动浏览器,会像在大屏幕的Web浏览器那

linux问题-CentOS7和以往版本的变化

1.systemd的服务管理程序:systemctl是主要的工具,它融合之前service和chkconfig的功能于一体.可以使用它永久性或只在当前会话中启用/禁用服务.systemctl可以列出正在运行的服务状态,如下: UNIT LOAD ACTIVE SUB DESCRIPTION proc-sys...t_misc.automount loaded active waiting Arbitrary Executable File Fo sys-devi...block-sr0.devi

.NET Framework 版本功能变化

作为一个.net的programer,我们常使用的VS,在创建项目时候,除了特定情况:比如要使用Linq,WCF,WPF,我们一般情况下都没特意的要求用哪个.net framework.那么他们每个版本区别在哪呢?我们是否应该每次都用最新的版本呢?且看: .NET Framework 1.0 不是真正意义的.net framework:发布日期:2002年2月13日,仅包含CLR和基类库的第一个版本 .NET Framework 1.1 .NET Framework 第一个主要版本.(自1.0版

Vue版本过渡变化

到了2.0以后,有哪些变化: 在每个组件模板,不在支持片段代码 之前: <template id="aaa"> <h3>我是组件</h3><strong>我是加粗标签</strong> </template> 现在:  必须有根元素,包裹住所有的代码 <template id="aaa"> <div> <h3>我是组件</h3> <stron

golang各版本的变化

https://golang.org/doc/https://golang.org/doc/go1.6https://golang.org/doc/go1.5https://golang.org/doc/go1.4https://golang.org/doc/go1.3https://golang.org/doc/go1.2https://golang.org/doc/go1.1

窥探Swift系列博客说明及其Swift版本间更新

Swift到目前为止仍在更新,每次更新都会推陈出新,一些Swift旧版本中的东西在新Swift中并不适用,而且新版本的Swift会添加新的功能.到目前为止,Swift为2.1版本.去年翻译的Swift书籍是1.0版本,所以上面一些东西并不在适用.虽然Swift语言仍在更新,但是其整体的基础框架已经形成,大的改动应该不会有,版本的更新更多的是语言新功能的添加和完善,所以并不用担心现在学的Swift会过时.更新也就是在原有的基础上去更新,所以学学Swift还是很有必要的.新的Swift版本中引入了好

iOS开发——Swift实用技术篇&amp;检查系统版本

Swift如何检查系统版本 指责Swift是“没有C的Objective-C”的说法不够准确,是因为Swift和Objective-C缺少相似之处,而不是没有C.Swift根本不是类C语言. 毫无疑问Swift从Haskell.Rust.Python.D语言等现代编程语言里获得灵感,但你最好把它理解成拒绝了C语言中一些坏掉地方的语言: · C语言是默认类型不安全的.Swift则默认为安全(因此Swift中的指针操作函数命名中加上unsafe)(译者注:见在Swift中使用遗留的C API). ·

深入浅出 Swift 3

Swift 是苹果公司推出的一门全新的编程语言.最初,它被用于编写苹果设备上(iOS,macOS,watchOS 和 tvOS)的应用程序.后来,苹果公司将 Swift 开源,从这时候起 Swift 便可以在 Linux 上运行,这也就意味着 Swift 正在向一门全端语言发展. 从 Swift 推出到 2016 年,已经走过了两年的时间,这么长的时间内,Swift 已经进化到了第三个大版本(腾云科技ty300.com).这期间伴随着很多的变化,而对于初学编程的你,无需考虑这些内容,Swift