校对:Crystal Sun
定稿:CMB

每当处理循环引用(retain cycles)时,需要考量对象生命周期来选择unowned或者weak标识符,这已经成为了一个共识。但是有时仍然会心存疑问,在具体的使用中应该选择哪一个,或者退一步讲,保守的只使用 weak 是不是一个好的选择呢?

本文首先对循环引用的基础知识做一个简要介绍,然后会分析 Swift 源代码的一些片段,讲解 unownedweak 在生命周期和性能上的差异点,希望看完本文以后,在的使用场景中,能使用正确的弱引用类型。

Read More

原文链接:Sorting Array and Dictionaries in Swift

Swift 中集合排序是简单的,每个实现Collection或者Sequence的协议的对象都可以使用sorted(by:)方法进行排序。

这个方法使用插入排序进行排序,序列中的元素需要遵从Comparable,并且没有提供可选的排序方法时,元素将被按照升序排列。

数组

定义一个包含各种水果的数组:

1
var fruits = ["orange","apple","melon","lemon","coconut","miracle fruit"]

排序代码很简单,使用下面的语句将获得排序后的数组:

1
fruits.sorted() // 输出: ["apple", "coconut", "lemon", "melon", "miracle fruit", "orange"]

可以传入大于操作符>改变排序顺序,序列将按照降序方式输出:

1
fruits.sorted(by:>) // Will print ["orange", "miracle fruit", "melon", "lemon", "coconut", "apple"]

显然我们也可以自定义比较方法,使得序列按照不同的标准排序,比如,以下的例子就是按照名字长度大小来排序的:

1
2
3
4
fruits.sorted{
$0.characters.count > $1.characters.count
}
// Will print ["miracle fruit", "coconut", "orange", "apple", "melon", "lemon"]

字典

字典遵从Collection,所以上面提到的对数组的操作,都可以运用到字典中。这里我们定义一个菜单和对应原材料的字典。

1
2
3
4
5
6
var recipes = [
"Lasagna" : ["Meat and tomato sauce","Lasagna pasta","Bechamel Sauce","Nutmeg","Parmigiano"],
"Vegetable Dumpling" : ["Dumpling dough","Vegetable filling"],
"Pizza" : ["Pizza dough","Tomato sauce","Olive oil","Mozzarella","Basil"],
"Curry Laksa" : ["Vegetable oil","Chicken stock","Chicken thighs","King prawns","Coconut milk","Fish balls"," Beansprouts","Thin rice noodles","Laska spicy paste"]
]

接下来对字典按照菜单名字升序处理:

1
2
3
4
recipes.sorted(by:{
(e1:(String,[String]), e2:(String,[String])) -> Bool in
e1.0 < e2.0
})

接着进行不同的排序方式,按照原材料的个数从高到低排序:

1
2
3
recipes.sorted(by:{
$0.value.count > $1.value.count
})

自定义对象序列可以进行排序的前提是,自定义对象只需要遵循Comparable协议,该协议实现了 5 个比较方法:<>==<=>=,每一个方法都返回比较结果的布尔值。

原文链接:Splitting Strings in Swift

在字符串的众多操作中,字符串的分割和修整是两个常见的操作。

在 Swift 中,可以使用两种方式来分割字符串,使用纯 Swift 的方式或者使用 Foundation 库的方法。

纯 swift 方式

纯 Swift 方式这样操作:把字符串对应的字符数组按照分割符分割为多个子字符数组,然后使用map把这些子字符数组转换为字符串:

1
2
3
4
5
let line = "Brevity is the soul of wit"
let words = line.characters.split(separator:" ").map(String.init)
words[0] // Brevity
words[5] // wit

或者需要在分割符上做更多的检查时,你可以这样写:

1
2
3
4
let words = line.characters.split{$0 == " "}.map(String.init)
words[0] // Brevity
words[5] // wit

关于 mapflatMap 的知识点,请查看这篇文章

Foundation 方式

如果项目中允许导入 Foundation 库,和大多数情况一样, NSString 已经有可以使用的方法了,components 方法可以把字符串分割为多个子字符串:

1
2
3
4
5
6
import Foundation
let words = line.components(separatedBy: " ")
words[0] // Brevity
words[5] // wit

原文链接:String trimming in Swift 3

在另外一篇短文中,我们介绍了如何在 Swift 中对字符串进行分割, 这篇短文介绍如何修整字符串,去掉字符串首尾的空格和其他不需要的字符。

使用 Foundation 中的NSString,可以轻松地做到上面需要的功能。
在下面的代码段中,我们删掉莎士比亚名句字符串结尾的空格符号和换行符:

1
2
3
4
5
import Foundation
var aline = " This above all: to thine own self be true \n"
aline.trimmingCharacters(in: .whitespacesAndNewlines)
//This above all: to thine own self be true

Swift 提供一些默认的CharacterSet字符集,供大家选择,使用时候替换掉上面代码段中的whitespacesAndNewlines即可:

说明
.controlCharacters Unicode 通用分类Cc 和 Cf 中的字符.
.whitespaces Unicode 通用分类 Zs 中的字符和制表符 (U+0009).
.whitespacesAndNewlines Unicode 通用分类 Z*, U+000A ~ U+000D, and U+0085.
.decimalDigits 十进制数字字符
.letters Unicode 通用分类 L & M 中的字符.
.lowercaseLetters Unicode 通用分类 Ll 中的字符.
.uppercaseLetters Unicode 通用分类 Lu 和 Lt 中的字符.
.nonBaseCharacters Unicode 通用分类 M* 中的字符.
.alphanumerics Unicode 通用分类 L, M, 和 N* 中的字符.
.decomposables 独立的 Unicode 字符,可以用来表示为组合字符序列(比如连接口音的单词)
.illegalCharacters 非字符或者在 Unicode 标准 V3.2 版本中未定义的字符.
.punctuationCharacters Unicode 通用分类 P* 中的字符.
.capitalizedLetters Unicode 通用分类 Lt 中的字符.
.symbols Unicode 通用分类 S* 中的字符.
.newlines 包含换行符字符集(U+000A ~ U+000D, U+0085, U+2028, 和 U+2029).
.urlUserAllowed URL 中用户子模块中允许的字符集.
. urlPasswordAllowed URL 中密码子模块中允许的字符集.
.urlHostAllowed URL 中宿主子模块中允许的字符集.
.urlPathAllowed URL 中路径子模块中允许的字符集.
.urlQueryAllowed URL 中查询子模块中允许的字符集.
. urlFragmentAllowed URL 中碎片子模块中允许的字符集.

另外,你也可以自定义字符集,指定任意的字符作为删除的字符:

1
2
var myCharset= CharacterSet("#%&")
aline.trimmingCharacters(in: myCharset)

服务器端程序经常会在启动时候传入一些命令行参数执行不同的功能,最典型命令是开始和结束命令:

1
2
-> % yourserver start
-> % yourserver stop

在 C 语言中,入口函数main自带两个参数用于获取命令行参数:

1
int main( int argc, char *argv[] ) /* 带参数形式 */

argc告诉我们命令行参数的数量,二维指针argv指向这些参数值的实际地址。开发过服务器端代码的同学对这个知识应该是相当了解了。那么在 Swift 中应该怎么获取呢?

Read More

从 Swift 开源到现在,只有短短的几个月时间,Swift 却已经被移植到了许多新的平台上,还有一些新的项目已经使用了 Swift。这类移植,每个月都在发生着。

在不同平台下混合使用 Swift 和 C 的可行性,看起来是一件非常难的实践,只有非常有限的实践资源,当然这是和你去封装一个原生库对比起来看的,你可以在你代码运行的平台上轻松地封装一个原生库。

Read More