From 88cf8370b842932047b57c9805ddfde08adfba23 Mon Sep 17 00:00:00 2001 From: mr-tyrion Date: Thu, 28 Aug 2014 18:35:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=94=B9=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=8B=B9=E6=9E=9CBlog:"Optional=20Case=20Study"=E7=9A=84?= =?UTF-8?q?=E7=BF=BB=E8=AF=91=EF=BC=8C=E4=BF=AE=E6=AD=A3=E4=BA=86=E2=80=9C?= =?UTF-8?q?06=20Access=20Control=E2=80=9D=E7=9A=84=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/SUMMARY.md | 3 +- ....md => 06_Access_Control_and_Protected.md} | 2 +- source/chapter4/07_Optional_Case_Study.md | 127 ++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) rename source/chapter4/{06_access_control_&_protected.md => 06_Access_Control_and_Protected.md} (95%) create mode 100644 source/chapter4/07_Optional_Case_Study.md diff --git a/source/SUMMARY.md b/source/SUMMARY.md index eb54a93f..5b0b6a6f 100755 --- a/source/SUMMARY.md +++ b/source/SUMMARY.md @@ -46,4 +46,5 @@ * [WWDC里面的那个“大炮打气球”](chapter4/03_Ballons.md) * [Swift与C语言指针友好合作](chapter4/04_Interacting_with_C_Pointers.md) * [引用类型和值类型的恩怨](chapter4/05_Value_and_Reference_Types.md) - * [访问控制和protected](chapter4/06_access_control_&_protected.md) \ No newline at end of file + * [访问控制和Protected](chapter4/06_Access_Control_and_Protected.md) + * [可选类型完美解决占位问题](chapter4/07_Optional_Case_Study.md) \ No newline at end of file diff --git a/source/chapter4/06_access_control_&_protected.md b/source/chapter4/06_Access_Control_and_Protected.md similarity index 95% rename from source/chapter4/06_access_control_&_protected.md rename to source/chapter4/06_Access_Control_and_Protected.md index f03e47ac..97269bce 100644 --- a/source/chapter4/06_access_control_&_protected.md +++ b/source/chapter4/06_Access_Control_and_Protected.md @@ -33,7 +33,7 @@ Swift的访问控制等级和继承无关,是单维度、非常清楚明了的 ----------------- 本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。 -##### 本文由翻译自Apple Swift Blog :[access control & protected](原文地址:https://developer.apple.com/swift/blog/) +##### 本文由翻译自Apple Swift Blog :[Access Control and Protected](原文地址:https://developer.apple.com/swift/blog/?id=11) diff --git a/source/chapter4/07_Optional_Case_Study.md b/source/chapter4/07_Optional_Case_Study.md new file mode 100644 index 00000000..037b7f2d --- /dev/null +++ b/source/chapter4/07_Optional_Case_Study.md @@ -0,0 +1,127 @@ +> 翻译:[老码团队翻译组-Tyrion](http://weibo.com/u/5241713117) +> 校对:[老码团队翻译组-Ayra](http://weibo.com/littlekok/) + +# 可选类型完美解决占位问题 +----------------- + +本页包含内容: + +- [为Dictionary增加objectsForKeys函数](#add-function) +- [Swift中更简便的方法](##easy-function) +- [内嵌可选类型](#nested-optional) +- [提供一个默认值](#provide-default) + +可选类型是Swift中新引入的,功能很强大,这篇博文我们将讨论在Swift里如何通过可选类型来保证强类型的安全性。我们创建一个Objective-C API的Swift版本作为例子,但实际上Swift本身并不需要这样的API。 + + + +#### 为Dictionary增加objectsForKeys函数 + +在Objective-C中,```NSDictionary```有一个方法```-objectsForKeys:NoFoundMarker:```, 这个方法需要一个键值值的```NSArray```数组作为参数,同时返回一个包含相关值的数组。从文档里我们可以看出:"返回数组中的第N个值和参数输入数组中的第N个值相对应",那如果有某个键值在字典里不存在呢?于是就以```notFoundMarker```作为返回提示,比如第三个键值没有找到,那么在返回数组中第三个值就是```notFoundMarker```,而不是字典中的第三个值,但是这个值只是提醒原字典中没有找到,但在返回数组中该元素存在,且用```notFoundMarker```作为占位符,因为其不能直接使用,所以在Foundation框架中有个专门的类处理这个情况:```NSNull```。 + +在Swift中,```Dictionary```类没有```objectsForKeys```的函数,为了说明问题,我们动手加一个,并且使其成为操作字典值的通用方法。我们可以使用```extension```来实现: + +``` +extension Dictionary{ + func valuesForKeys(keys:[K], notFoundMarker: V )->[V]{ + //接下来实现 + } +} +``` + +以上就是我们实现的Swift版本,这个Objective-C版本有很大区别, 在Swift中,因为其强类型的原因限制了返回的结果数组只能包含单一类型的元素,所以我们不能放```NSNull```在字符串数组中,但是,Swift有更好的选择,我们可以返回一个可选类型数据,我们所有的值都封包在可选类型中,而不是```NSNull```, 我们只用```nil```即可。 + + +``` +extension Dictionary{ + func valuesForKeys(keys: [Key]) -> [Value?] { + var result = [Value?]() + result.reserveCapacity(keys.count) + for key in keys{ + result.append(self[key]) + } + return result + } +} +``` + + +#### Swift中更简便的方法 + +小伙伴们可能会问,为什么Swift中不需要实现这么一个API呢?其实其有更简单的实现,如下代码所示: + +``` +extension Dictionary { + func valuesForKeys(keys: [Key]) -> [Value?] { + return keys.map { self[$0] } + } +} +``` + +上述方式实现的功能和最开始的方法实现的功能相同,虽然核心的功能是封装了```map```的调用,这个例子也说明了为什么Swift没有提供轻量级的API接口,因为小伙伴们可以通过简单的调用```map```就可以实现。 + +接下来,我们实验几个例子: + +``` +var dic: Dictionary = [ "1": 2, "3":3, "4":5 ] +var t = dic.valuesForKeys(["1", "4"]) //结果为:[Optional(2), Optional(5)] +t = dic.valuesForKeys([])//结果为:[] +``` + + +#### 内嵌可选类型 + +现在,如果我们为每一个结果调用```last```方法,看下结果如何? + +``` +var dic: Dictionary = [ "1": 2, "3":3, "4":5 ] +var t = dic.valuesForKeys(["1", "4"]).last //结果为:Optional(Optional(5)) +t = dic.valuesForKeys([])//结果为:Optional(nil) +``` + +小伙伴们立马迷糊了,为什么会出现两层包含的可选类型呢?,特别对第二种情况的```Optional(nil)```,这是什么节奏? + +我们回过头看看```last```属性的定义: + +``` +var last:T? { get } +``` + +很明显```last```属性的类型是数组元素类型的可选类型,这种情况下,因为元素类型是```(String?)```,那么再结合返回的类型,于是其结果就是```String??```了,这就是所谓的嵌套可选类型。但嵌套可选类型本质是什么意思呢? + +如果在Objective-C中重新调用上述方法,我们将使用```NSNull```作为占位符,Objective-C的调用语法如下所示: + +``` +[dict valuesForKeys:@[@"1", @"4"] notFoundMarker:[NSNull null]].lastObject +// 5 +[dict valuesForKeys:@[@"1", @"3"] notFoundMarker:[NSNull null]].lastObject +// NSNull +[dict valuesForKeys:@[] notFoundMarker:[NSNull null]].lastObject +// nil +``` + +不管是Swift版本还是Objective-C版本,返回值为```nil```都意味数组是空的,所以它就没有最后一个元素。 但是如果返回是```Optional(nil)```或者Objective-C中的```NSNull```都表示数组中的最后一个元素存在,但是元素的内容是空的。在Objective-C中只能借助```NSNull```作为占位符来达到这个目的,但是Swift却可以语言系统类型的角度的实现。 + + +#### 提供一个默认值 + +进一步封装,如果我字典中的某个或某些元素不存在,我们想提供一个默认值怎么办呢?这很简单实现: + +``` +extension Dictionary { + func valuesForKeys( keys:[Key], notFoundMarker: Value)->[Value]{ + return self.valueForKeys(kes).map{ $0 ?? notFoundMarker } + } +} +``` + +``` +dict.valuesForKeys(["1", "5"], notFoundMarker: "Anonymous") +``` + +和Objective-C相比,其需要占位符来达到占位的目的,但是Swift却已经从语言类型系统的层面原生的支持了这种用法,同时提供了丰富的语法功能。这就是Swift可选类型的强大之处。同时注意上述例子中用到了空合运算符```??```。 + +----------------- +本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。 + +##### 本文由翻译自Apple Swift Blog :[Optionals Case Study: valuesForKeys](https://developer.apple.com/swift/blog/?id=12)