Swift2.2中的新变化

原文链接点击这里

Swift2.2已经更新了,这次更新去除了一些难用的语法还添加了一些缺失的特性,并且还弃用了一些有争议的语言特性。这篇文章将详细介绍Swift2.2中的一些主要的变化和一些细微的改变,还会展示一些实际的代码例子来让你更快的上手Swift2.2。

1. ++ 和 – 被弃用了

Swift 2.2正式地弃用了++和–操作符,意味着他们仍然可用但当你用到时会得到哦一条警告。弃用一般是完全移除的第一步,因此在这种情况下在Swift 3.0中这两个操作符将会被移除掉。

在使用这两个操作符的地方,你需要用+= 1和-= 1来替换掉他们。这两个操作符(+= -=)会一直存在,不会移除。

你可能会好奇为什么两个长期使用的操作符会被移除掉,尤其是他们存在于C、C#,Java以及调侃它的笑话 C++ 中时。下面列出了一些原因,但不是所有:

  1. 写++而非+= 1没有显著的节省时间
  2. 虽然一旦你知道了它后用起来很容易,但是++对学习Swift的人来说并没有一个明确的含义,然而+=至少可以理解为”求和并赋值”
  3. C语言风格的for循环,这是++和–用的最多的地方,同样也被Swift弃用了,这也引出了我的下一点…

2. 传统的C风格for循环也被弃用了

对,你没看错:下面这种for循环将很快从Swift中完全移除掉:

for var i = 1; i <= 10; i += 1 {
  print("\(i) green bottles")
}

之所以称之为C风格的for循环,因为他们作为类C语言的特性已经存在了很长时间,概念上甚至在C语言之前都已经很久了。

虽然Swift也是(大概吧)类C语言,但他有一些比传统的for循环更新的、更聪明的替代品。结果就是:这个结构在Swift 2.2 中被弃用了并且”会在将来版本的Swift中移除掉”。

注意:当前的弃用警告并没有提示会在Swift 3.0移除,但我怀疑他会的。

要替换这些旧的for循环,使用其中一个替代选择即可。例如,上面的green bottles代码可以使用range的循环来重写,就像这样:

for i in 1...10 {
  print("\(i) green bottles")
}

记住,创建一个开始比结束值大的range是不对的,虽然你的代码会通过编译,但会在运行时崩溃掉。所以不要这么写:

for i in 10...1 {
  print("\(i) green bottles")
}

而是应该写成这样:

for i in (1...10).reverse() {
  print("\(i) green bottles")
}

另一个选择是直接使用数组的快速枚举,就像这样:

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for number in array {
  print("\(number) green bottles")
}

3. 数组和其他的slice类型现在有removeFirst()函数了

removeFirst()方法对数组的操作一直很有用,但是直到现在一直缺少一个移除数组开始位置元素的对应方法。

好啦,添加了removeFirst()方法的Swift 2.2来拯救你了。这个方法会删除数组中的第一个元素并把它返回给你。

回头去看green bottles这个例子,你会发现两个坏习惯:第一,我使用了var而不是let,第二是打印了英语语法上的信息”一个绿瓶子们”。

这些都不是误写的,因为我要用它来演示removeFirst()了

var array = Array(1...10)
array.removeFirst()

for number in array {
  print("\(number) green bottles")
}

注意:虽然removeLast()有一个返回可选的等效方法popLast(),removeFirst()并没有类似的可选等效方法。这意味着如果你对一个空数组调用这个方法,你的代码会crash掉

4. 现在你可以比较元组了(在合适的格式下)

元组是一系列由逗号分隔的值,元组的值可以包含参数名也可以不包含,比如下面这个:

let singer = ("Taylor", "Swift")
let alien = ("Justin" "Bieber")

在旧版本的swift中,你不能比较两个元组的值,除非写一些笨重的代码,就像下面这样:

func == (t1: (T, T), t2: (T, T)) -> Bool {
  return t1.0 == t2.0 && t1.1 == t2.1
}

需要些这样的样板代码的要求不是非常友好的,当然这也只对只有两个值的元组有效。在Swift 2.2 中,你不需要再写这样的代码了,因为元组可以直接进行比较了:

let singer = ("Taylor", "Swift")
let alien = ("Justin", "Bieber")

if singer == alien {
  print("Matching tuples!")
} else {
  print("Non-matching tuples!")
}

Swift 2.2的自动对比含两个元素的元组的效果就和我们刚写的函数功能一样。但它对六元元组同样适用,也就是有六个元素的元组。

至于为什么Swift的元组比较只支持到6元元组(而不是6百万),这里有两个原因。首先,每一次额外的比较都会需要调用Swift标准库中的更多代码。另外,使用这么大的元组就是代码有问题了。应该换成使用结构体。

你可以通过改变上面的两个元组来看看元组是怎么进行比较的:

let singer = ("Taylor", 26)
let alien = ("Justin", "Bieber")

准备好接受Xcode长长的错误信息吧,但有趣的东西还在末尾呢:

note: overloads for ‘==‘ exist with these partially matching parameter lists: ......
((A, B), (A, B)), ((A, B, C), (A, B, C)), ((A, B, C, D), (A, B, C, D)), ((A, B, C, D, E), (A, B, C, D, E)), ((A, B, C, D, E, F), (A, B, C, D, E, F))

5. 元组的splat语法被弃用了

让我们在元组上多聊一会:另一个被弃用的特性是Swift自从2010年(对,Swift发布以前)就存在的,它被称作”the tuple splat”,并没有多少人用过它。这也是被弃用的原因之一,虽然主要还是因为这个语法会给阅读代码带来歧义,所以才被弃用。

鉴于你可能会好奇,那我们来看一下,下面的splat语法的例子:

func describePerson(name: String, age: Int) {
  print("\(name) is \(age) years old")
}

let person = ("Taylor Swift", age: 26)

describePerson(persion)

要记住:别太喜欢你刚学的新知识,因为他们在Swift 2.2中被弃用了,并且会在未来的版本中完全移除掉

6. 更多的关键字可以用来当做参数标签了

参数标签是Swift中一个核心的特性,我们来撸一下下面这段代码:

for i in 1.stride(through: 9, by: 2) {
  print(i)
}

如果没了through和by标签,这段代码就失去了其自我注释的特性:

1.stride(9, 2)中的9和2是个啥意思?在这个例子中,Swift还使用了参数标签把1.stride(through: 9, by: 2)和1.stride(to: 9, by: 2)区分开来,这两段代码会产生不同的结果。

在Swift 2.2中,你可以用更多的语言关键字来作为参数标签了。你可能觉得为什么这会是件好事呢,考虑一下下面的代码:

func printGreeting(name: String, repeat repeatCount: Int) {
  for _ in 0..< repeatCount {
    print(name)
  }
}
printGreeting("Taylor", repeat: 5)

这里用到了repeat关键字作为参数标签,这个函数会重复打印一个字符串多次。因为repeat是一个关键字,这段代码在Swift 2.2之前是会出错的,你得用别的代替repeat,这让人很不爽。

注意:仍然有一些关键字是不能用作参数标签的,特殊的如var,let以及inout。

7. var 参数被弃用

另一个被抛弃的,同样也是有原因的:var参数被弃用是因为它提供的用处微不足道,并且经常和inout搞混。这东西太不易理解了,以至于我不得不加入到我的Swift language tests,但当你读到这里的时候我可能已经删除掉了。

为了掩饰,下面是用var关键字修改后的printGreeting()函数:

func printGreeting(var name: String, repeat repeatCount: Int) {
  name = name.uppercaseString

  for _ in 0..< repeatCount {
    print(name)
  }
}

printGreeting("Taylor", repeat: 5)

与第一处不同的是前面的name变成了var name,并且name被换成了大写,所以会打印出”TAYLOR”五次。

没有了var关键字,name就变成了常量,uppercaseString这一行就会出错。

var和inout之间的区别非常细微:使用var关键字你可以在函数体内部修改一个参数的值,而inout会让你所做的改变在函数结束后依然有效。

在Swift 2.2中,var被弃用了,并将在Swift 3.0 中移除。如果你正在使用这个,直接在函数内给这个变量做一份拷贝就可以了,比如:

func printGreeting(name: String, repeat repeatCount: Int) {
  let upperName = name.uppercaseString

  for _ in 0..< repeatCount {
    print(upperName)
  }
}

printGreeting("Taylor", repeat: 5)

8.重命名了调试标识符:#line,#function,#file

Swift 2.1和更早的版本使用”screaming snake case”的符号:FILE,LINE,COLUMNFUNCTION,这些符号出现的地方会被编译器自动替换为文件名,行号,列号和函数名称

在Swift 2.2中,这些旧的符号已经被#file,#line,#column和#function替换掉了。你会相当熟悉如果已经使用了Swift 2.0的#available来检查iOS特性。正如Swift review官方所说的,它也引入了一条出现#意味着会触发编译器的替代逻辑的规则。

下面我修改了printGreeting()函数,来看一下新旧两种调试标识符的用法:

func printGreeting(name: String, repeat repeatCount: Int) {
  // old - deprecated!
  print("This is on line \(__FILE__) of \(__FUNCTION__")

  // new - shiny!
  print("This is on line \(#line) of \(#function)")

  let upperName = name.uppercaseString

  for _ in 0..< repeatCount {
    print(upperName)
  }
}

printGreeting("Taylor", repeat: 5)

多亏了代码补全,我应该加上你也可以使用#dsohandle了,但是如果你知道什么是dynamic shared object handles的话,你大概已经发现了这点变化了。

9. 字符串化的selector被弃用

Swift 2.2以前一个不受欢迎的功能是selector可以被写作字符串,像这样:

navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Tap!", target: self, action: "buttonTaped")

如果你仔细看会发现,我写的是”buttonTaped”而不是”buttonTapped”,但Xcode不会提示我出的错误,如果这个方法不存在的话。

这个问题在Swift 2.2中解决了:使用字符串作为selector被弃用了,并且你可以在上面的代码中这么写#selector(buttonTapped),如果buttonTapped方法不存在的话,你会得到一条编译错误,这又是一个需要在类编译前消除的错误。

10. 编译时Swift 版本检查

Swift 2.2 加入了一个新的编译配置项使得用不同版本Swift写的代码联合编译成一个单独文件变得简单。这看起来可能是不必要的,但是考虑到使用Swift编写库的人们,他们能把目标版本设在Swift 2.2并且期待别人都用它或者目标版本设在Swift 2.0并期待用户能用Xcode升级吗?

使用新的编译选项能让你写两种不同口味的Swift,正确的那个会依据Swift编译器的版本来进行编译。

例如:

#if swift(>=2.2)
print("Running Swift 2.2 or later")
#else
print("Running Swift 2.1 or earlier")
#endif

就像#if os()编译选项一样,这个可以调整由编译器生成的代码:如果你正在使用Swift 2.2的编译器,第二个print()就不会被注意到。这意味着如果你愿意你可以随便胡扯点什么:

#if swift(>=2.2)
print("Running Swift 2.2 or later")
#else
THIS WILL COMPILE JUST FINE IF YOU ARE
USING A SWIFT 2.2 COMPILER BECAUSE
THIS BIT IS COMPLETELY IGNORED!
#endif

11. 新的文档关键字:recommended,recommended over,和keyword

Swift支持MarkDown格式的注释来给你的代码添加额外的信息,所以你可以这么写:

/**
Say hello to a specific person
- parameters:
- name: The name of the person to greet
- returns: Absolutely nothing
- authors:
Paul Hudson
Bilbo Baggins
- bug: This is a deeply dull funtion
*/
func sayHello(name: String) {
    print("Hello, \(name)")
}

sayHello("Bob")

这些信息在代码补全中会使用到(“Say hello to a specific person” 会按照你书写的方式显示)并且在快速帮助中同样有用,其他的信息这时也会显示。

在Swift 2.2中,添加了三个新的关键字recommended,recommendedover和keyword.这几个关键字通过让你来指定哪个在Xcode中匹配的属性和方法应该被返回,从而使得代码补全更有用,但是现在看起来还没作用,所以这也只是一种猜测。

当它们突然可以用的时候,我希望你是像这么使用的:

/**
- keyword: greeting
- recommendedover: sayHelloToPaul
*/
func sayHello(name: String) { }

/**
Always greets the same person
- recommended: sayHello
*/
func sayHelloToPaul() { }

正如你看到的,recommended意思是更推荐另一个方法而不是这个,而recommendedover意思是更推荐这个方法而不是别的。

正如我所说,这在当前的Xcode 7.3版本中还是不可用的,但是我提交了一个bug给Apple,期待与能得到一些明确的说明这些关键字的作用,当我知道更多的时候我也会更新这个页面。

另一方面,Xcode 7.3有了新的代码补全特性:现在你可以打出几个字像是”strapp”来得到stringByAppendingString的高亮提示。或者”uitavc”来获UITableViewCell高亮提示,让你的脑袋适应这种文本快捷键还需要一些重新调整,但这确实给你编写代码的速度带来了显著的提升。

时间: 2025-01-02 05:38:43

Swift2.2中的新变化的相关文章

【译】.NET Core 3.0 中的新变化

.NET Core 3.0 是 .NET Core 平台的下一主要版本.本文回顾了 .Net Core 发展历史,并展示了它是如何从基本支持 Web 和数据工作负载的版本 1,发展成为能够运行 Web.桌面.机器学习.容器.IoT 等的版本 3.0. .NET Core 1 .NET Core 的历史可追溯到几年前,版本 1 是在 2016 年推出,旨在生成第一版开放源代码和跨平台(Windows.macOS 和 Linux)的 .NET.灵感来源于只能使用开放源代码框架的客户,以及需要在 Li

[译] OpenStack Kilo 版本中 Neutron 的新变化

OpenStack Kilo 版本,OpenStack 这个开源项目的第11个版本,已经于2015年4月正式发布了.现在是个合适的时间来看看这个版本中Neutron到底发生了哪些变化了,以及引入了哪些新的关键功能. 1. 扩展 Neutron 开发社区 (Scaling the Neutron development community) 为了更好地扩展 Neutron 开发社区的规模,我们在Kilo开发周期中主要做了两项工作:解耦核心插件以及分离高级服务.这些变化不会直接影响 OpenStac

Swift2.3 --&gt; Swift3.0 的变化

Swift3.0语法变化 首先和大家分享一下学习新语法的技巧: 用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Syntax- 让Xcode帮我们把Swift2.3的代码转换为Swift3.0. 手动调出Xcode自动转换Swift2.3 到 Swift3.0 弹出语言版本选择界面,选择Covert to Swift3,Next:  进入选择模块界面: 选择模块界面 建议只选择自己创建的模块,第三方框架的模块最好不要使用Xco

[转]Material Design Library 23.1.0的新变化与代码实战

Design Library出来已经快有一个月了,当时大概看了一下介绍这个新版本变化的译文,内容不多,给我印象最深的就是Percent lib.AppBarLayout 和NavigationView的变化,当然还有Design Lib的一些控件内部实现的变化没有介绍,从而使得在使用新版本的控件时候难免因为版本的不同会发生一些异常,而本人正好在上个星期对一个项目换库时发现了这个问题,什么问题呢? NavigationView使用注意的问题 就是NavigationView的内部实现发生了改变,它

Extjs6中的新特性

Ext JS在Sencha框架中引入了许多新的和令人兴奋的改进.这些变化为基于所有现代浏览器.设备和屏幕尺寸带来了新的功能和可用性. 工具包(ToolKits) Ext JS 6最大的变化就是将Ext JS和Touch合并为一个单一的框架.之前的框架的核心(数据.控制器.模型等等)已被调和为一个单一的公共平台.这样,数据和逻辑就能共享,从而帮助开发人员进一步去优化他们的应用程序. 那些具有独特功能的东西将会被分解为两个绝然不同的两个工具包:古典(Classic)和现代(Modern).这些工具包

TASK_KILLABLE:Linux 中的新进程状态【转】

转自:https://www.ibm.com/developerworks/cn/linux/l-task-killable/index.html 新的睡眠状态允许 TASK_UNINTERRUPTIBLE 响应致命信号 Linux® kernel 2.6.25 引入了一种新的进程状态,名为 TASK_KILLABLE,用于将进程置为睡眠状态,它可以替代有效但可能无法终止的 TASK_UNINTERRUPTIBLE 进程状态,以及易于唤醒但更加安全的 TASK_INTERRUPTIBLE 进程状

Material Design Library 23.1.0的新变化与代码实战

Design Library出来已经快有一个月了,当时大概看了一下介绍这个新版本变化的译文,内容不多,给我印象最深的就是Percent lib.AppBarLayout 和NavigationView的变化,当然还有Design Lib的一些控件内部实现的变化没有介绍,从而使得在使用新版本的控件时候难免因为版本的不同会发生一些异常,而本人正好在上个星期对一个项目换库时发现了这个问题,什么问题呢? NavigationView使用注意的问题 就是NavigationView的内部实现发生了改变,它

.NET Framework 4 中的新 C# 功能

C# 编程语言自 2002 年初次发布以来已经有了极大的改善,可以帮助程序员编写更清晰易懂.更容易维护的代码.这种改善来自于不断加入的新功能,例如泛型类型.可为空的值类型.lambda 表达式.迭代器方法.分部类以及其他大量有用的语言结构.而且,这些改变还经常伴随着为 Microsoft .NET Framework 库提供相应的支持. C# 4.0 延续了这种不断提高易用性的趋势.这款产品大大简化了许多常见任务,包括泛型类型.传统的互操作以及处理动态对象模型.本文旨在为深入调查探讨这些新功能.

拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar..)

转载 请注明 明桑Android Android 5.0 Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言.看起来很受欢迎,可它的普及似乎不那么顺利,刚过去不久的Google I/O 2015都已经推出了新的Android M预览版.即使是这样,原生版本的Android推广似乎一直没取得google预期的结果-不管怎样,作为开发者我们关心的无非是这个平台是否好用,能否开发出精致而又有趣的应用.好在Material Design我认为是成功的,官方在And