Небольшое расширение для Foundation, упрощающее разработку.

В процессе разработки довольно часто программист сталкивается со словарем типа [String: Any] (ответ сервера в виде json) или [AnyHashable: Any] (userInfo при получении push уведомления). В то же время иногда необходимо сформировать словарь данного типа, при этом нежелательно каждый раз указывать ключ в виде String. Небольшое расширение для словаря, представленное ниже, решает данную проблему и несколько упрощает процесс разработки.
Определение ключей в отдельном enum
Намного удобней обращаться к словарю с помощью case'ов перечисления вместо обычных строк. Это, во-первых, уменьшает вероятность ошибки и, во-вторых, упрощает вызов, поскольку autocomplete подсказывает возможные варианты. Для реализации достаточно объявить новый enum в расширении к словарю и соответсвующий subscript:
В результате получить значение словаря можно как с помощью строки, так и с помощью case'а перечисления:
let dict: [String: Any] = ["data": 1, "id": 2, "type": 3]
let result = dict["type"]
let sameResult = dict[.type]
Приведение к нужному типу
Довольно часто можно встретить код подобного рода:
let dict: [String: Any] = ["data": 1, "id": 2, "type": 3]
let result = dict["id"] as? Int
Куда удобней вынести downcast в расширение, благо язык swift имеет широкие возможности для реализации. Необходимо объявить subscript с обобщением (generic):
При наличии такого subscript'а нет необходимости приведения значения к нужному типу. Соответственно используются все возможности swift'а по неявному определению типа:
let dict: [String: Any] = ["data": 1, "id": 2, "type": 3]
someMethod(optionalIntegerArgument: dict[.id])XCTAssertEqual(dict[.type], 3)let result: Int? = dict["type"]
let sameResult: Int? = dict[.type]
Формирование словаря
Также иногда стоит и обратная задача — формирование словаря, например, типа [String: Any] (отправка данных серверу в виде параметров запроса). При этом снова стоит предпочесть case'ы перечисления вместо строчных ключей. Но поскольку перечисления могут быть разными и объявлены в любом удобном (подходящем) месте программы, то требуется некоторый метод, выполняющий mapping значений перечисления к строкам:
По-сути данное расширение позволяет выполнять mapping к любому rawValue, реализующему Hashable протокол, не только к строкам. Поэтому расширение является чуть более универсальным. Тем не менее поставленная задача решена достаточно изящно:
enum Payment: String {
case cash, card, credit
}
let dict: [Payment: Double] = [.cash: 10, .card: 20, .credit: 0]
let result = dict.mappedToRawValues
XCTAssertEqual(result, ["cash": 10.0, "card": 20.0, "credit": 0.0])
Заключение
Как и было сказано вначале, расширение достаточно небольшое, но упрощающее процесс разработки. Позвольте пожелать вам хорошего дня, а у меня на этом все.