Небольшое расширение для 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])

Заключение

Как и было сказано вначале, расширение достаточно небольшое, но упрощающее процесс разработки. Позвольте пожелать вам хорошего дня, а у меня на этом все.

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Ace Rodstin

Ace Rodstin

More from Medium

Molly Hurley Speaks to Students about Art, Politics, and Social Change

Metamorphosis

A Thousand Years version 5