【问题标题】:How does the closure work in the method mapValues?闭包在方法 mapValues 中是如何工作的?
【发布时间】:2020-08-04 00:34:02
【问题描述】:

我试图了解mapValues 方法在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>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 返回一个字典“包含该字典的键以及由给定闭包转换的值。”

我的问题是,传递给data.mapValues { (colorIndex) -&gt; UIColor in 闭包的值colorIndex 到底是什么?是来自heatmap.plist 吗?我很困惑 String 是如何从 colorFor(dateComponents: ) 函数传递到 date, date[dateString] 的,但 colorIndex 是 Int。

【问题讨论】:

    标签: ios swift closures plist


    【解决方案1】:

    原来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的返回类型,而键类型保持不变。

    传递给闭包的值colorIndex 究竟是什么?

    这是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
        }
    }
    

    是来自 heatmap.plist 吗?

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

    我很困惑如何将字符串从colorFor(dateComponents: ) 函数传递到datadata[dateString],但colorIndexInt

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

    您可以将String 传递给data,因为data 字典有Strings 作为键。回想一下mapValues 不会更改密钥类型。请注意,此 data 与局部变量 data 不同。我说的是lazy 属性data,类型为[String: UIColor]

    【讨论】:

    • 感谢您的回答。这是否意味着原来的[key: value]"2019.5.5" : 4 转换为"2019.5.5" : UIColor(named: "color5")?如果这里data属性的目的是输入一些下标data[dateString],并返回一个对应的UIColor,我不确定这里的plist是干什么用的。
    • @Kevvv 回复:你的第一个问题,是的。回复:“我不确定这里的 plist 是干什么用的。” plist 是为了提供后期绑定。当然,您可以在源代码中硬编码[String: UIColor] 字典,但要更改其内容,您必须重新编译。将数据放入文件中可以轻松进行更改。
    • 你可以直接返回try .init(uniqueKeysWithValues: zip(keys, values.map(transform)))
    • 说操作顺序是否正确 1) 写入 plist "2020.8.3" : 3 2) 字典被转换为相应的颜色 "2020.8.3" :UIColor(named: "color4") 和 3) data["2020.8.3"]
    • @Kevvv 第 1 步应该是从 plist 中读取字典。另请注意,由于 data 是惰性的,因此步骤 1 和 2 只会执行一次,但每次调用 colorFor 时都会执行步骤 3。
    猜你喜欢
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 2019-05-07
    • 1970-01-01
    相关资源
    最近更新 更多