程序迁移到swift 3.0的一些实用技巧

前言

在去年swift3.0发布了,新版本可以在Xcode 8中使用了,或者你可以直接从swift.org下载编译器。

从代码可读性来看,新版本有很多提升,函数调用的连续性,更好的命名约定和移除了部分c风格的元素。

从代码可读性来来看,NS前缀已经从Foundation类型中移除,例如NSBundle.mainBundle()现在改为Bundle.mainBundle() .

c风格的一元操作符++和--在3.0中已经不适用了:

// Only in Swift 2.2 and earlier
var number = 10
number++
++number
number--
--number

相对应的表达方式是number += 1 or number -= 1.

另外一个有趣的变化是移除了c风格的for-loop,我记得在学校中(使用c语言)写这种循环:

// Only in Swift 2.2 and earlier
let steps = 5
for var step = 0; step < steps; step++ {
 print(step)
}
// 0 1 2 3 4

主要的原因是存在了更好的对应写循环的方法for-instride().for-loop在理解上比较困难和缺少swift风格。当新的方法出现后,for-loop已经很少在代码库中使用了。

这篇文章将讲解典型的for-loop使用场景,同时说明迁移到 for-in, stride()或者简单的while() {} .

一、如何迁移 for-loop 到 for-in

for-loop 应用的典型场景在一个数字区间内迭代。这些数字可以是数组的索引等.

例如,让我们遍历数组的每一个元素:

// Only in Swift 2.3 and earlier
let birds = ["pigeon", "sparrow", "titmouse"]
for var index = 0; index < birds.count; index++ {
 print(birds[index])
}
// "pigeon" "sparrow" "titmouse"

可见,let index = 0; index < birds.count; index++ 的循环部分是冗长的。许多元素是多余的,整个表达式可以简化的。替换为手动的增量,整个操作可以用更具表达性的语法来自动化。

for-in 循环更简短和更具表达性。让我们迁移上面的代码:

let birds = ['pigeon', 'sparrow', 'titmouse']
for index in 0..<birds.count {
 print(birds[index])
}
// 'pigeon', 'sparrow', 'titmouse'

现在感觉好很多了。index in 0..<birds.count 更容易阅读和理解。0..<birds.count 这部分定义一个半开区间的 Range 类型。for-in 循环迭代0,1和2的范围值(不包括上限3)。

这不是全部! 你甚至可以跳过索引并直接访问数组元素:

let birds = ["pigeon", "sparrow", "titmouse"]
for bird in birds {
 print(bird)
}
// "pigeon" "sparrow" "titmouse"

可以看出,对于标准数组或集合迭代for-in对于for-loop是一个更好的替代。 至少在这种情况下,在Swift 3.0中删除for-loop的决定是合理的。

二、如何迁移 for-loop 到 stride

你可以合理地要求for-loop虽然是冗长的,但仍然是灵活的。 它对于更复杂的迭代是有用的。

让我们尝试一个场景。你要打印一个具有奇数索引元素的元素数组。一个 for-loop 可能看起来像这样:

// Only in Swift 2.3 and earlier
let colors = ["blue", "green", "red", "white", "black"]
for var index = 0; index < colors.count; index += 2 {
 print(colors[index])
}
// => "blue" "red" "black"

由于索引根据表达式 index += 2而每次增加2,所以只有奇数索引的元素会被显示:”blue”, “red” and “black”.

你可以尝试使用 for-in 并定义一个范围。但是需要奇数索引加上附加的验证:

let colors = ["blue", "green", "red", "white", "black"]
for index in 0..<colors.count {
 if (index % 2 == 0) {
 print(colors[index])
 }
}
// => "blue" "red" "black"

的确, if (index % 2 == 0) { ... } 条件句在这里看起来怎么样。

这种情况很符合使用 Swift 的stride(from: value, to: value, by: value)函数。定义开始,结束(不包括上限)和步长值,函数返回相应的数字序列。

让我们在我们的场景中应用stride:

let colors = ["blue", "green", "red", "white", "black"]
for index in stride(from: 0, to: colors.count, by: 2) {
 print(colors[index])
}
// => "blue" "red" "black"

stride(from: 0, to: colors.count, by: 2) 返回以0开始到5的数字(上限不包含5),步长为2。对于 for-loop,这是一个好的替代。

如果上限必须包含进来,这里有另外一种函数格式:

stride(from: value, through: value, by: value) 。第二个参数的标签是 through, 这个标签是用以指明是包含上限的。

三、其他情况坚持使用while

c风格for-loop的每个组件都有一个很好的属性:初始化,跳出严重和完全可配置的增量:

for <initialization>; <verification>; <increment> {
 // loop body
}

此外,你可以省略其中的任何组件,要是你能在for-loop的循环块打破循环。

例如,让我们打印一个数字数组的元素,直到数字0被遇到。可以使用C风格的for-loop:

// Only in Swift 2.2 and earlier
let numbers = [1, 6, 2, 0, 7], nCount = numbers.count
for var index = 0; index < nCount && numbers[index] != 0; index++ {
 print(numbers[index])
}
// => 1 6 2

验证部分 index < nCount && numbers[index] != 0 是用以检查是否0在数组中出现。如果出现,则跳出循环。

所以只有0之前的数字被打印出来:1,6和2。

for var index in 0..<nCount 是一个迁移选项。你只是需要使用条件 if numbers[index] == 0 ,当0出现的时候跳出循环:

let numbers = [1, 6, 2, 0, 7], nCount = numbers.count
for index in 0..<nCount {
 if (numbers[index] == 0) {
 break
 }
 print(numbers[index])
}
// => 1 6 2

但 break 语句出现,它会轻微减少阅读流程。但是我想要容易地阅读代码流程!

while(<condition>) {...} 循环可能是一个更好的替代方案。让我们看看上一个例子是如果被修改的:

let numbers = [1, 6, 2, 0, 7], nCount = numbers.count
var index = 0
while (index < nCount && numbers[index] != 0) {
 print(numbers[index])
 index += 1
}
// => 1 6 2

如果你有的情况无法使用 for-in 或者 stride() , 那么我推荐你使用 while(){}

四、统一参数标签行为

在Swift 2.2 和更早版本你可以在调用函数的时候忽略第一个参数的标签:

// Only in Swift 2.2 and earlier
func sum(firstItem: Int, secondItem: Int) -> Int {
 return firstItem + secondItem
}
sum(5, secondItem: 2) // => 7

对于我来说,这个忽略的做法给我带来困扰。你不得不忽略第一个参数的标签,然而剩下的参数却还保持有标签。这是一种不自然的规则。

幸运的是从3.0版本开始,所有参数将强制拥有标签。

让我们来迁移上一个例子:

func sum(firstItem: Int, secondItem: Int) -> Int {
 return firstItem + secondItem
}
sum(firstItem: 5, secondItem: 2) // => 7

myFun(firstParam: 1, secondParam: 2)看起来更好。你知道严格的参数含义。简单,一致和清晰的方式。

如果你因为某些原因想在Swift 3.0中调用函数的时候忽略第一个标签,使用_ 作为那个参数的参数标签:

func sum(_ firstItem: Int, secondItem: Int) -> Int {
 return firstItem + secondItem
}
sum(5, secondItem: 2) // => 7

然而从长远来看我不推荐这种做法。他破坏了Swift代码中函数/方法调用的一致性。

Swift 命名向导 有很多有用的命名方面的建议。

总结

Swift 3.0 做了一个很好的修改列表。其中大部分是重大的修改,所以你必须花些功夫来迁移Swift 2.3或者更旧的代码。

Swift 的制造者花了很多功夫来使这门语言用起来尽可能的舒服。

有时候,这个过程产生重大更改。幸运的是相比提高代码的可读性和跨语言语法的一致性来说,这是一个相对小的代价。

C风格的元素如for-loop,一元增量和减量运算被删除。对于这些结构Swift提供了更好的选择。

例如C语言风格的for循环很容易由for-in所取代。你可以使用stride()函数来进行更多可配置的迭代。

我最喜欢的改进是Swift 3.0引入了函数参数标签的一致性和清晰度。

简单易记的规则:始终指明参数的标签。

我建议你也访问Swift 3.0官方的迁移向导。

英文原文链接:https://rainsoft.io/useful-tips-for-migrating-to-swift-3-0/

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者使用Swift能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Ubuntu 16.04上安装 Swift 3.0及问题解答

    我们对"让 Swift 3.0 在更多的 Linux 系统上运行"这件事充满了热情,因此我们开始在 Ubuntu 16.04,即 Xenial Xerus,X86 系统上构建 Swift 3.0.安装过程十分简单,只需要添加我们的 APT 仓库,并使用 apt-get 就可以了.二进制文件会被安装到 /opt/swift/swift-3.0 目录下,所以在安装 3.0 版本后需要更新 path 路径.编辑手记:对于我们为什么使用 /opt/swift 而不是 /usr/bin/ 目录,

  • Swift 3.0在集合类数据结构上的一些新变化总结

    一.Array数组的更改 array数组中修改的API示例如下: //创建大量相同元素的数组 //创建有10个String类型元素的数组,并且每个元素都为字符串"Hello" //swift2.2 //var array3 = [String](count: 10, repeatedValue: "Hello") //swift3.0 var array3 = [String](repeating: "Hello", count: 10) //创

  • 程序迁移到swift 3.0的一些实用技巧

    前言 在去年swift3.0发布了,新版本可以在Xcode 8中使用了,或者你可以直接从swift.org下载编译器. 从代码可读性来看,新版本有很多提升,函数调用的连续性,更好的命名约定和移除了部分c风格的元素. 从代码可读性来来看,NS前缀已经从Foundation类型中移除,例如NSBundle.mainBundle()现在改为Bundle.mainBundle() . c风格的一元操作符++和--在3.0中已经不适用了: // Only in Swift 2.2 and earlier

  • 把WebLogic EJB程序迁移到JBoss上

    WebLogic服务器是一款顶级的商业应用程序服务器.但是对于小规模的开发者来说,开发源代码的.基于标准的应用程序服务器JBoss是可以用来替换类似WebLogic或WebSphere等商业应用程序服务器的.不幸的是,在WebLogic中开发的应用程序不能在JBoss中部署.JBoss迁移服务为我们提供了把应用程序迁移到JBoss上的支持.作为代替,通过把厂商特定的部署文件信息迁移到JBoss上,是可能把应用程序迁移到JBoss上的.为了演示如何把应用程序迁移到JBoss的过程,我们将把一个在W

  • swift 3.0中realm封装类示例代码

    前言 如果你用够了FMDB或者CoreData,不妨试试realm,本文主要给大家介绍了关于swift 3.0中realm封装类的相关内容,分享出来供大家参考学习,下面来一起看看吧. 最新更新,特别感谢@deepindo /// 查询排序后所有数据,关键词及是否升序 static func selectScoretByAll<T: Object>(_: T.Type ,key: String, isAscending: Bool) -> Results<T>{ return

  • swift 3.0 正则表达式查找/替换字符的实现代码

    1.什么是正则表达式 正则表达式,又称正规表示法.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念. 正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串. 在很多文本编辑器里,正则表达式通常被用来检索.替换那些符合某个模式的文本. 2.正则表达式的字符组成 普通字符[a~z].特殊字符(称为"元字符") 3.支持 几乎所有的程序设计语言都支持正则表达式,例如:OC,swift,java,c#,

  • Swift 3.0基础学习之类与结构体

    前言 和其他语言不同的是,Swift不需要为自定义的类和结构体创建接口和实现文件.只需要创建单一文件用来创建类和结构体,其他的外部接口的代码系统会自动生成.下面这篇文章主要介绍了关于Swift 3.0类与结构体的内容,感兴趣的朋友一起来看看吧. 类和结构体区别 Swift的类和结构体具有以下相同的特点: 可以定义属性来保存值 可以定义方法来提供功能 可以定义下标来使用他们的值 可以定义初始化器来配置他们的初始化状态 可以在默认的实现上扩展他们的功能 遵从协议来提供标准的功能 类具有结构体没有的额

  • swift 3.0 实现短信验证码倒计时功能

    下面一段代码给大家分享swift 3.0 实现短信验证码倒计时功能,具体实例代码如下所示: class TCCountDown { private var countdownTimer: Timer? var codeBtn = UIButton() private var remainingSeconds: Int = 0 { willSet { codeBtn.setTitle("重新获取\(newValue)秒", for: .normal) if newValue <=

  • Swift 3.0将UILabel数字颜色设置为红色的方法

    实现需求 这篇文章源于群友的一个问题:如何把『注:此商品只能整件(12的倍数发货),已选1袋,还差11袋』这段文字中的数字使用红色在 UILabel 中显示? 实现思路 我们可以使用UILabel 的 attribute string 属性,通过正则表达式匹配获取数字的范围,然后添加对应的 attribute. 实现代码 下面是实现代码,使用 swift 3.0 编写: //根据正则表达式改变文字颜色 func changeTextChange(regex: String, text: Stri

  • Swift 3.0基础学习之闭包

    前言 闭包是功能性自包含模块,可以在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其他一些编程语言中的 lambdas 比较相似.下面这篇文章就来详细介绍了关于Swift 3.0中的闭包,感兴趣的一起来看看吧. 开始 闭包的书写格式如下: { (parameters) -> return type in statements } 如 reversedNames = names.sorted(by: { (s1: String, s2: Str

  • 浅谈swift 4.0中private所发生的变化

    前言 当Swift首次引入访问级别时,对此进行了一些混淆和不解.虽然开发人员对于添加对Swift编程语言的访问控制感到兴奋,但是private关键字的行为与其他编程语言的行为不同. 之前在swift 3.0的时候,如果把声明的变量或方法加上private前缀,那么它就只能在当前的class里使用,extension 中也不能使用.改成fileprivate,却又可以在其他类中实例化后使用,属性的作用域就会更大,可能会不小心造成属性的滥用. 所以在Swift 4 中,private 的属性的作用域

随机推荐