map()方法介绍
map()是Array提供的方法,通过接收一个函数作为传入参数,对数组中每个元素进行函数变换得到新的结果值。这样只需要提供X->Y的映射关系,就能将数组[X]变换到新数组[Y],而无需创建一个临时可变数组(注:即上面代码中的items变量)。
本例中,我们不再像之前一样用for来做循环,而是对jsonItems( JSON数据:存储于类型为字典的数组中)使用map()方法,并传入一个变换函数(闭包),将每个NSDictionary类型数组元素转换成我们所需的ListItem
实例:
return jsonItems.map { (itemDesc: NSDictionary) -> ListItem in let item = ListItem() if let icon = itemDesc["icon"] as? String { item.icon = UIImage(named: icon) } if let title = itemDesc["title"] as? String { item.title = title } if let urlString = itemDesc["url"] as? String, let url = NSURL(string: urlString) { item.url = url } return item}
这看起来只是个很小的改动,但是它让我们专注于怎样把NSDictionary转化成ListItem
,毕竟这是解决问题的核心。更为重要的是,避免了像在 ObjC 里做的那样,新建一个中间数组。我们应该尽可能地避免这种情况发生。错误数据目前代码还存在一个问题:即便输入的数据是不可用的,我们依然创建了一个ListItem实例(并返回添加到结果数组jsonItems当中)。所以,倘若某些NSDictionary是无效的,最终的输出数组中,就会添加一些毫无意义的ListItem()空实例。更重要的是,我们仍在杀死一些小马 :horse: 。当我们使用NSURL!时,代码允许我们创建那些没有NSURL的ListItem()实例(我们没有一个有效的url键值,所以访问item.url不起作用),当我们访问无效的NSURL!时,程序将会崩溃。为了解决这个问题,我们对变换函数稍加修改,当输入值无效时,返回一个值为nil的ListItem,这比返回一个错误或无内容的ListItem更为合适。
return jsonItems.map {
(itemDesc: NSDictionary) -> ListItem? in guard …/* condition for valid data */… else { return nil
}
let realValidItem = ListItem() … /* fill the ListItem with the values */ return realValidItem}
但是如果jsonItems.map里面传入的函数参数类型为NSDictionary -> ListItem?,最后我们得到的是一个[ListItem?]数组,那些原来是不可用NSDictionary的位置就被我们替换成了nil。比原要好一些了,但还不够。使用flatMap()这个时候就轮到flatMap()来救场了。flatMap()与map()相似,但flatMap()用的是T->U?变换而不是T->U转化,而且倘若变换后的数组元素值为nil 2
,则不会被添加到最后的结果数组里面。从语法上,你可以这么理解,flatMap就是先使用map处理数组,接着将结果数组“压平”(顾名思义),也就是从输出数组里剔除值为nil的元素。通过flatMap方法改写后的实例代码如下:
return jsonItems.flatMap {
(itemDesc: NSDictionary) -> ListItem? in guard let title = itemDesc["title"] as? String, let urlString = itemDesc["url"] as? String, let url = NSURL(string: urlString) else { return nil }
let li = ListItem()
if let icon = itemDesc["icon"] as? String { li.icon = UIImage(named: icon) } li.title = title li.url = url return li}
现在我们只返回所有键都存在 3并有效的ListItem对象(保证NSURL不为nil)。否则执行guard语句,返回nil值通知flatMap不要将这些无效元素添加到返回结果数组中。这样做就更好更安全了,对吧?,我们解决了数据异常的问题,当有错误输入时候,避免了无效的ListItem项添加到数组当中。