闭包在方法 mapValues 中是如何工作的?

How does the closure work in the method mapValues?

我正在尝试了解 mapValues method works in the following code from Calendar Heatmap

  1. 首先,函数加载字典:
private func readHeatmap() -> [String: Int]? {
    guard let url = Bundle.main.url(forResource: "heatmap", withExtension: "plist") else { return nil }
    return NSDictionary(contentsOf: url) as? [String: Int]
}

heatmap.plist 是一个 key/value 列表,如下所示:

    <key>2019.5.3</key>
    <integer>3</integer>
    <key>2019.5.5</key>
    <integer>4</integer>
    <key>2019.5.7</key>
    <integer>3</integer>
  1. 一个属性使用上面的函数初始化:
lazy var data: [String: UIColor] = {
    guard let data = readHeatmap() else { return [:] }
    return data.mapValues { (colorIndex) -> UIColor in
        switch colorIndex {
        case 0:
            return UIColor(named: "color1")!
        case 1:
            return UIColor(named: "color2")!
        case 2:
            return UIColor(named: "color3")!
        case 3:
            return UIColor(named: "color4")!
        default:
            return UIColor(named: "color5")!
        }
    }
}()
  1. 最后将上面定义的data属性用在下面的函数中:
func colorFor(dateComponents: DateComponents) -> UIColor {
    guard let year = dateComponents.year,
        let month = dateComponents.month,
        let day = dateComponents.day else { return .clear}
    let dateString = "\(year).\(month).\(day)"
    return data[dateString] ?? UIColor(named: "color6")!
}

Apple 的文档指出 mapValues returns 字典“包含该字典的键以及由给定闭包转换的值。”

我的问题是,在 data.mapValues { (colorIndex) -> UIColor in 中传入闭包的值 colorIndex 到底是什么?是来自 heatmap.plist 吗?我很困惑如何将 StringcolorFor(dateComponents: ) 函数传递到 date、date[dateString],但 colorIndex 是 Int。

本来data是这样的:

"2019.5.3" : 3
"2019.5.5" : 4
"2019.5.7" : 3

假设你做了 data.mapValues(f),其中 f 是一个函数,生成的字典将如下所示:

"2019.5.3" : f(3)
"2019.5.5" : f(4)
"2019.5.7" : f(3)

所以现在,字典的值类型变为f的return类型,而键类型保持不变。

what exactly is the value colorIndex passed into the closure?

它是 data 中的每个值。每个值都会被传递到闭包中一次。

为了更清楚地看到这一点,我写了一种可以实现 mapValues 的可能方式:

extension Dictionary {
    func myMapValues<T>(_ transform: (Value) throws -> T) rethrows -> [Key: T] {
        var retVal = [Key: T]()
        for entry in self {
            retVal[entry.key] = try transform(entry.value)
        }
        return retVal
    }
}

Is it from heatmap.plist?

间接地,是的。局部变量data(即[String: Int])的内容原本来自heatmap.plist,但mapValues直接对已经从文件中读取的data进行操作。

I'm confused how a String is passed into data, data[dateString] from the colorFor(dateComponents: ) function, but colorIndex is Int.

colorIndex 在这里无关紧要。 colorIndex 只是您传递给 mapValues 的函数的函数参数的名称。 mapValues此时已被调用,字典的值已被转换。

您可以将 String 传递给 data,因为 data 字典将 String 作为键。回想一下 mapValues 不会更改密钥类型。注意这个data和局部变量data是不一样的。我说的是类型 [String: UIColor].

lazy 属性 data