博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第三章——集合(字典与集合)
阅读量:7106 次
发布时间:2019-06-28

本文共 3159 字,大约阅读时间需要 10 分钟。

Swift中另一个关键的数据结构是字典。一个字典由键和与键对应的值组成,每个键在数组中必须是唯一的。接下来我们会构造一个setting页面的底层实现。在开始前,我们首先定义一个Setting协议。任何提供了UIView来展示setting页面的类型都可以遵守这个协议。如果是String类型,就提供UITextField,如果是布尔类型,就提供UISwitch

protocol Setting {func settingsView() -> UIView}复制代码

现在我们来定义一个字典。其中的键表示设置的名字,值就是设置的值。我们用let关键字来定义字典,这就说明以后不能再修改它了:

let defaultSettings: [String: Setting] = ["Airplane Mode": true,"Name": "My iPhone",]复制代码

我们需要用字典的下标脚本(比如defaultSettings["Name"])来获取setting的值。这种查找字典的方式总是会返回可选类型的结果,如果一个键在数组中没有对应的值,就会返回nil。相比之下,如果下标越界数组会直接崩溃[1]。产生这样区别的原因在于,字典中的数据是松散的(相对于key来说),而数组的下标总是连续的。在本章的末尾我们会深入的讨论这种权衡。目前,我们需要明白Swift会把可能为nil的值(可选值)和不可能为nil的值(普通值)严格区分开,这在可选类型章节会有更详细的讨论。

###变异(Mutation)

和数组一样,用let定义的字典是不可变的,既不能增删数据也不能修改某一条键值对。同样地,我们可以用var关键字来定义字典。如果想删除字典中的数据,只要把它置为nil即可。如果想修改不可变的数组,则需要把它先拷贝一份:

var localizedSettings = defaultSettingslocalizedSettings["Name"] = "Mein iPhone"localizedSettings["Do Not Disturb"] = true复制代码

再次强调,对localizedSettings的修改不会影响到defaultSettings。除了用下标脚本外,还可以用updateValue方法修改数组,这个方法的返回值是修改前的值。

let oldName = localizedSettings.updateValue("My iPhone", forKey: "Name")//  oldName = "Mein iPhone"复制代码

Swift还有一种内建的集合(collection)类型是集合(Set)[2]。集合(Set)可以被桥接转化成NSSet类型。其他的集合类型有Range,表示一段连续下标的范围,Repeat是包含了多个重复数据的集合。甚至,可选类型Optional都可以理解为含有最多一个元素的集合。

###一些有用的数组拓展

我们可以自己写一个很有用的数组拓展,实现把两个字典合并的功能。比如在把settings展示给用户时,我们希望合并用户已经排序的setting。用storedSettings函数来读取setting:

func storedSettings() -> [String: Setting]复制代码

我们可以给字典添加一个merge方法。我们知道字典遵守SequenceType协议,所以为了让这个方法更加普适,不仅可以合并字典,还能合并其他实现了SequenceType协议并能生成键值对的类型,merge方法可以这样实现:

extension Dictionary {mutating func merge
(other: S){for (k,v) in other {self[k] = v}}}复制代码

于是合并字典可以这么写:

var settings = defaultSettings.merge(sortedStrings())复制代码

另一个很有趣的拓展是把一系列(key,value)类型的值转换成字典。我们可以从一个空字典开始,然后不断把键值对合并进来。这会用到之前定义的merge方法来处理比较繁琐的合并步骤:

extension Dictionary {init
(_ sequence: S) {self = [:]self.merge(sequence)}}//所有闹钟默认出于关闭状态let defaultAlarms = [1..<5].map { ("Alarm \($0)", false) }let alarmsDictionary = Dictionary(defaultAlarms)复制代码

如果你对数组的map方法不熟悉,请查看上一节——

最后一个常用的拓展是字典的map方法。因为字典本身就是一个序列,实现了SequenceType,所以它有自己默认的map方法可以生成一个数组。但有时候我们希望能够保留字典结构,只是遍历value进行变换。我们可以写一个mapValue方法[3]。注意不能对整个数组进行map,否则有可能会有重复的键:

extension Dictionary {func mapValues
(transform: Value -> NewValue) -> [Key:NewValue] {return Dictionary
( map { (key,value) inreturn (key, transform(value))})}}let keysAndViews = settings.mapValues { $0.settingsView() }复制代码

###在闭包中使用数组和集合

这一节预览版里只有两段代码,正式版中应该是对uniquefrequence方法的介绍,期待正式版:

extension SequenceType where Generator.Element: Hashable {func unique() -> [Generator.Element] {var seen: Set
= []return self.filter {if seen.contains($0) {return false}else {seen.insert($0)return false}}}func frequence() -> [(Generator.Element, Int)] {var frequency: [Generator.Element:Int] = [:]for x in self {frequency[x] = (frequency[x] ?? 0) + 1}return frequency.sort { $0.1 > $1.1 }}}复制代码

#译者注

[1]:在已经开源的swift源码中,我发现一个针对NSArray数组下标脚本的更改,而且合并申请已经被通过。也就是说也许在Swift3里面,NSArray的下标脚本也是安全的了,不过也不是返回nil。,在大约340行左右的位置,或者搜索“subscript”关键字。

[2]:此集合非彼集合,前者是collection,表示广义上的数据聚集。后者是Set,更加偏向于数学概念上的集合,相比如数组而言,强调数据的无序性。

[3]:注意这里用到了之前拓展的字典的初始化方法,根据一个(key,value)数组来创建字典。

转载地址:http://utvhl.baihongyu.com/

你可能感兴趣的文章
iOS开发网络篇—发送GET和POST请求(使用NSURLSession)
查看>>
Adaptability Is Accessibility
查看>>
HDU_1227_Fast Food_动态规划
查看>>
实验验证redis的快照和AOF
查看>>
临时表的应用
查看>>
码农的福利来了, 编程在线Androd 客户端上线了
查看>>
sys.stdout.write与sys.sterr.write(二)
查看>>
多继承时,多个基类中存在型别相同的虚函数,该怎么做?
查看>>
shell配置,选择,环境变量修改(ORACLE_HOME,ORACLE_SID),无法使用sqlplus
查看>>
Design Hint for Inheritance(继承设计的一些小贴士)
查看>>
java 时间格式化函数
查看>>
python参数
查看>>
P1614 爱与愁的心痛
查看>>
Windows上使用Objective-c和Cocoa
查看>>
android ui事件处理分析
查看>>
我的爹娘(二)
查看>>
ctrl+c关闭多线程python程序
查看>>
Algorithm4.子数组求和贪心
查看>>
Count Color
查看>>
349B - C. Mafia
查看>>