Видеокурсы по изучению языка программирования Swift. Подробнее

Словари

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

Словарь представляет собой контейнер, который хранит несколько значений одного и того же типа. Каждое значение связано с уникальным ключом, который выступает в качестве идентификатора этого значения внутри словаря. В отличие от элементов в массиве, элементы в словаре не имеют определенного порядка. Используйте словарь, когда вам нужно искать значения на основе их идентификатора, так же как в реальном мире словарь используется для поиска определения конкретного слова.

Заметка

Словари в Swift конкретны по отношению к типам ключей и значений которые они могут хранить. Они отличаются от классов NSDictionary и NSMutableDictionary из Objective-C, которые могут использовать любой объект в качестве ключей и значений, и не предоставляют никакой информации о характере этого объекта. В Swift, всегда понятно какие типы ключей и значений может хранить определенной словарь, либо через явное объявление типа, либо через вывод типов.

Сокращенный синтаксис словаря

В Swift тип словаря в полной форме пишется как Dictionary<Key, Value>, где Key это тип значения который используется как ключ словаря, а Value это тип значения который словарь может хранить для этих ключей.

Вы можете также написать словарь в сокращенной форме как [Key: Value]. Хотя две формы функционально идентичны, краткая форма является предпочтительной и используется в данном руководстве при обращении к типу словаря.

Литералы словаря

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

Пара ключ-значение является комбинацией ключа и значения. В литерале словаря, ключ и значение в каждой паре ключ-значение разделено двоеточием. Пары ключ-значение написаны как список, разделенный запятыми и окруженный парой квадратных скобок:

[ключ 1: значение 1, ключ 2: значение 2, ключ 3: значение 3]

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

var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

Словарь airports объявлен с типом [​String​: ​String​], что означает "словарь ключи которого имеют тип String и значения которого также имеют тип String".

Заметка

Словарь airports объявлен как переменная ( с помощью var ), а не константа ( с помощью let ), поскольку много аэропортов будет добавляться к словарю в примерах ниже.

Словарь airports инициализирован с помощью литерала словаря, содержащего две пары ключ-значение. Первая пара имеет ключ "YYZ" и значение "Toronto Pearson". Вторая пара имеет ключ "DUB" и значение "Dublin".

Этот словарь содержит две пары String: String. Этот тип ключ-значение подходит типу который мы присвоили переменной airports ( словарь содержащий только String ключи, и только String значения), и поэтому присвоение литерала словаря допустимо в качестве способа инициализации словаря airports двумя начальным элементами.

Подобно к массивам, вы можете не писать тип словаря если вы инициализируете его с помощью литерала словаря, чьи ключи и значения имеют соответствующие типы. Инициализация airports может быть записана в более краткой форме:

var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

Поскольку все ключи в литерале имеют одинаковый тип, и точно так же все значения имеют одинаковый тип, то Swift может вывести, что [String: String] является правильным типом для использования в словаре airports.

Доступ и изменение словаря

Вы можете получить доступ к словарю и изменять его либо через его методы и свойства, либо используя синтаксис индексов. Подобно массивам, вы можете узнать количество элементов в словаре через его read-only свойство count:

print("The airports dictionary contains \(airports.count) items.")
// напечатает "The airports dictionary contains 2 items."

Логическое свойство isEmpty можно использовать в качестве быстрого способа узнать, является ли свойство count равным 0:

if airports.isEmpty {
  print("The airports dictionary is empty.")
} else {
  print("The airports dictionary is not empty.")
}
// напечатает "The airports dictionary is not empty."

Вы можете добавить новый элемент в словарь с помощью синтаксиса индексов. Используйте новый ключ соответствующего типа в качестве индекса, а затем присвойте новое значение соответствующего типа:

airports["LHR"] = "London"
// словарь airports теперь содержит 3 элемента

Вы также можете использовать синтаксис индексов для изменения значения связанного с определенным ключом:

airports["LHR"] = "London Heathrow"
// значение для "LHR" поменялось на "London Heathrow"

В качестве альтернативы индексам, можно использовать метод словаря updateValue(forKey:), чтобы установить или обновить значение для определенного ключа. Подобно примерам с индексами вверху, метод updateValue(forKey:) устанавливает значение для ключа если оно не существует, или обновляет значение, если этот ключ уже существует. Однако, в отличие от индексов, метод updateValue(forKey:) возвращает старое значение после выполнения обновления. Это позволяет вам проверить состоялось ли обновление или нет.

Метод updateValue(forKey:) возвращает опциональное значение соответствующее типу значения словаря. Например, для словаря, который хранит String значения, метод возвратит String? тип, или " опциональный String". Это опциональное значение содержит старое значение для этого ключа, если оно существовало до обновления, либо nil если значение не существовало.

if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
  print("The old value for DUB was \(oldValue).")
}
// напечатает "The old value for DUB was Dublin."

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

if let airportName = airports["DUB"] {
  print("The name of the airport is \(airportName).")
} else {
  print("That airport is not in the airports dictionary.")
}
// напечатает "The name of the airport is Dublin Airport."

Вы можете использовать синтаксис индексов для удаления пары ключ-значение из словаря путем присвоения nil значению для этого ключа:

airports["APL"] = "Apple International"
// "Apple International" несуществующий аэропорт для APL, так что удалим его
airports["APL"] = nil
// APL теперь был удален из словаря"

Кроме того, можно удалить пару ключ-значение из словаря с помощью метода removeValueForKey. Этот метод удаляет пару ключ-значение если она существует и затем возвращает значение , либо возвращает nil если значения не существует:

if let removedValue = airports.removeValueForKey("DUB") {
  print("The removed airport's name is \(removedValue).")
} else {
  print("The airports dictionary does not contain a value for DUB.")
}
// напечатает "The removed airport's name is Dublin Airport."

Итерация по словарю

Вы можете сделать итерацию по парам ключ-значение в словаре с помощью for-in цикла. Каждое значение в словаре возвращается как кортеж (ключ, значение),и вы можете разложить части кортежа по временным константам или переменным в рамках итерации:

for (airportCode, airportName) in airports {
  print("\(airportCode): \(airportName)")
}
// LHR: London Heathrow
// YYZ: Toronto Pearson

Чтобы подробнее узнать про цикл for-in, смотрите главу "Циклы for"

Вы также можете получить коллекцию ключей или значений словаря через обращение к его свойствам keys и values:

for airportCode in airports.keys {
  print("Airport code: \(airportCode)")
}
// Airport code: LHR
// Airport code: YYZ

for airportName in airports.values {
  print("Airport name: \(airportName)")
}
// Airport name: London Heathrow
// Airport name: Toronto Pearson

Если вам нужно использовать ключи или значения словаря вместе с каким-либо API, которое принимает объект Array, то можно инициализировать новый массив с помощью свойств keys и values:

let airportCodes = [String](airports.keys)
// airportCodes теперь ["YYZ", "LHR"]

let airportNames = [String](airports.values)
// airportNames теперь ["Toronto Pearson", "London Heathrow"]

Заметка

Тип словарь в Swift является неупорядоченной коллекцией. Порядок получения ключей, значений и пар ключ-значение при итерации по словарю, не уточняется.

Создание пустого словаря

Подобно массивам вы можете создать пустой словарь определенного типа с помощью синтаксиса инициализатора:

var namesOfIntegers = [Int: String]()
// namesOfIntegers является пустым [Int: String] словарем

В этом примере создается пустой словарь с типом [Int: String] для хранения удобных для восприятия имен числовых значений. Его ключи имеют тип Int, а значения - String.

Если контекст уже предоставляет информацию о типе, вы можете создать пустой словарь с помощью литерала пустого словаря, который пишется как [:] ( двоеточие внутри пары квадратных скобок):

namesOfIntegers[16] = "sixteen"
// namesOfIntegers теперь содержит 1 пару ключ-значение
namesOfIntegers = [:]
// namesOfIntegers теперь опять пустой словарь с типом [Int: String]

Хеш значения для типов ключей словаря

Тип должен быть хешируемым, чтобы можно было использовать его как тип ключа словаря, то есть тип должен предоставить возможность вычислять хеш-значение для самого себя. Хеш-значение - это значение типа Int, которое является одинаковым для всех объектов, которые проверяют равенство, такое, что если a == b, то и a.hashValue == b.hashValue.

В Swift все простые типы ( такие как String, Int, Double, и Bool) являются хешируемыми по умолчанию, так что все эти типы могут быть использованы как ключи для словаря. Элементы перечислений без связанных значений ( как описано в главе "Перечисления"), также хешируемы по умолчанию.

Заметка

Вы можете использовать свои собственные пользовательские типы в качестве типов для ключей словаря путем приведения их в соответствие протоколу Hashable из стандартной библиотеки Swift. Типы которые соответствуют протоколу Hashable должны предусматривать gettable Int свойство с именем hashValue, и должны предусматривать реализацию оператора "равно" (==). Значение возвращаемое от свойства hashValue не обязательно должно быть одинаковое при разных запусках одной и той же программы, и даже при запусках различных программ.

Для получения дополнительной информации о соответствии с протоколами, смотрите главу "Протоколы".

Swift: 
2.2