Как работает замыкание в методе mapValues? - PullRequest
1 голос
/ 04 августа 2020

Я пытаюсь понять, как работает метод 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>
Свойство инициализируется с помощью указанной выше функции:
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")!
        }
    }
}()
Наконец, свойство 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 возвращает словарь, содержащий ключи этого словаря с значения, преобразованные данным замыканием. "

Мои вопросы: какое именно значение colorIndex передается в замыкание в data.mapValues { (colorIndex) -> UIColor in? Это из heatmap.plist? Я не понимаю, как String передается в date, date [dateString] из функции colorFor(dateComponents: ), но colorIndex - это Int.

1 Ответ

3 голосов
/ 04 августа 2020

Изначально 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, уже прочитанным из файла.

I ' m запутался, как String передается в data, data[dateString] из функции colorFor(dateComponents: ), но colorIndex это Int.

colorIndex здесь не имеет значения. colorIndex - это просто имя параметра функции функции, которую вы передаете в mapValues. На этом этапе был вызван mapValues, и значения словаря были преобразованы.

Вы можете передать String в data, потому что словарь data имеет String s в качестве ключей. Напомним, что mapValues не меняет тип ключа. Обратите внимание, что эта data отличается от локальной переменной data. Я говорю о свойстве lazy data типа [String: UIColor].

...