美文网首页走进swiftiOS DeveloperSwift开发技巧
Swift - Map all the things 映射所有东

Swift - Map all the things 映射所有东

作者: zhiyi | 来源:发表于2016-01-11 00:55 被阅读189次

我博客原文:http://zyden.vicp.cc/mapallthething/
欢迎转载,请注明出处,谢谢

上一篇文章中我们为数组引入了map()和flatMap(),详细讲解了他们的用法和优点,其实map和flatMap也适用于Optionals类型 和 其他很多的类型,今天我们来探索下他们的用法。

对比下Array 和 Optional

回忆一下,我们之前学习的在Array上使用map和flatMap的用法是这样的:

// Method on Array<T>
    map( transform: T ->          U  ) -> Array<U>
flatMap( transform: T ->    Array<U> ) -> Array<U>

这意味着如果提供一个转换方式:T->U的话,你可以将一个包含T的Array转换成一个包含U的Array。也就是说让Array<T>通过简单的调用map( transform: T->U ),就会返回一个Array<U>

类似的,map和flatMap在Optional<T>上的用法是这样的:

// Method on Optional<T>
    map( transform: T ->          U  ) -> Optional<U>
flatMap( transform: T -> Optional<U> ) -> Optional<U>

map() on Optionals

ok,我们来看看map()在Optional<T>类型上做了什么。同理于Array<T>,首先是拿到了Optional<T>(Array<T>)里的所有内容==(Array<T>的内容为数组里面所有T,Optional<T>里所有内容为该Optional的真实值和nil)==,然后根据我们所提供的转换方式(transform: T->U)进行转换后,再将结果包装成新的Optional<U>(Array<U>)。他们所做的事情其实是一样的。

看回我们的例子

我们来看看怎样在我们之前的代码里用上我们所说的方法。

记得在上一篇文章我们的示例代码中,我们的itemDesc["icon"]会返回一个String?,而我们的目的是将其作为图片名字转换成一个UIImage,只不过,UIImage(name:)需要接收一个String类型的参数而不是String?,所以我们保证在这个Optional String值非nil的情况下,并拿到Optional里真实的String去调用这个UIImage的构造函数。

当然在以前,我们可以使用Optional Binding来做:

let icon: UIImage?
if let iconName = itemDesc["icon"] as? String {
  icon = UIImage(named: iconName)
} else {
  icon = nil
}

为了更加简便,节省代码行数,我们还可以用 nil联结操作符 ??

let iconName = itemDesc["icon"] as? String
let icon = UIImage(named: iconName ?? "")

当iconName为nil时,将""赋值给iconName作为UIImage构造函数的参数:UIImage(named: ""),返回一个nil的image(UIImage?),保证了程序不crash,但是这样似乎有点扭曲了构造函数UIImage(named:)

我们用map试试

事实上我们需要的是当Optional<String>非nil的时候将其解包,并且将他的真实值作为参数传递给UIImage(named: )使其返回一个UIImage,所以这是这非常贴切的用法。
上代码:

let iconName = itemDesc["icon"] as? String
item.icon = iconName.map { imageName in UIImage(named: imageName) }

想法是对的,可是上面的代码必须是编译不过的!问题出在哪里呢?先解释下上面这段代码。我们让iconName这个Optional值调用map()方法,映射其非nil的值(真实值){换句话说:当iconName非nil时执行map闭包里的转换规则}成为参数imageName传入闭包,构造出一个UIImage对象。问题就出在如果imageName不是一个有效图片名字,或者因为某种原因取不到的话,UIImage就为nil,所以UIImage(named: )返回值本身就是一个UIImage?,再看看map()的定义:使转换T->U并返回U?。那么再看看我们的例子,UIImage?就相当于U,那么整个map完了后会返回的U?是什么?------UIImage??。哈哈这就是所谓的Double-Optional!

救星faltMap

flatMap做了什么转换?T->U?,因其使结果扁平化(flattens)而得名。。。。介绍这些就不再说了,回顾可以看回前一篇文章。在这里flatMap可以为我们去掉一层optional:

let iconName = itemDesc["icon"] as? String
item.icon = iconName.flatMap { imageName in UIImage(named: imageName) }

因此,在这个应用中,flatMap做了这些事情:
-如果iconName为nil的话,直接返回nil而不是作为一个UIImage?来返回
-如果iconName有值,flatMap将尝试使用iconName来创建UIImage,这时只有UIImage的构造函数失败了,才会返回nil,因此flatMap返回值为UIImage?
总而言之,只有在itemDesc["icon"] as? String结果非nil,并且UIImage(named: )成功的情况下,item.icon才有一个非空值。
这样做比使用??来欺骗构造方法更中规中矩。

魔法:使用init简化闭包

在Xcode7 后构造器可以通过.init这个property暴露出来,因此我们可以进一步地让代码更简化更紧凑。就是说UIImage.init是一个参数为String返回值为UIImage?的方法,我们可以直接地让他成为flatMap的参数,而简化掉闭包:

let iconName = itemDesc["icon"] as? String
item.icon = iconName.flatMap(UIImage.init)

。。。。这个用法我还没有理解得非常通,不过好像仅仅在IOS8以上生效,最后谢谢捧场!

相关文章

  • Swift - Map all the things 映射所有东

    我博客原文:http://zyden.vicp.cc/mapallthething/欢迎转载,请注明出处,谢谢 在...

  • 巴夏:水晶,你的正面信念强化者!

    巴夏: All things 所有的事情 All objects 所有的物品 All rituals 所有的仪式 ...

  • 06RxSwift的高阶函数Map

    map映射(A中的元素,B中都有唯一的元素与之对应,称为A到B的映射): 通过搜索Map.swift,查看.map...

  • Swift语法补充(四)

    Swift高阶函数介绍 Map:对集合元素进行映射($0取映射内每个值) Filter:映射过滤,筛选满足要求的新...

  • Map集合了解一下

    前言 Map映射Map映射的特点Map接口结构Map接口常见Api解析put(K key, V value)put...

  • 数据结构之集合与映射(二)

    本篇主要内容:映射Map及其实现,Map的应用,Map与Set的对比 映射Map 数据结构里的所谓映射是键值对的数...

  • 智慧书(6)

    勤则万事易,懒则万事难。 All things are easy to Industry,All things d...

  • MAP!!!map!!!映射

    号外! map方法在计算机中就是映射的意思。 那什么叫做映射呢? 比如有一个A 根据A变成(生成)B,就叫做映射。...

  • Java容器——HashMap简要分析

    Base on Java8 简介 HashMap是基于哈希表实现的映射(map)。此实现提供了所有可选映射操作,并...

  • 好了歌

    All Good Things Must End All men long to be immortals Yet...

网友评论

    本文标题:Swift - Map all the things 映射所有东

    本文链接:https://www.haomeiwen.com/subject/zhvqkttx.html