본문 바로가기

SWIFT 공식문서 문법 알아보기/04. Collection Types

Swift 공식문서 해설 Collection Types - Dictionaries (4-3)

Dictionaries

딕셔너리는 같은 타입의 키와 같은 타입의 값을 정의된 연관성을 순서 없이 항목에 저장합니다. 각 값은 고유의 키와 관련되어있으며 딕셔너리 내에서 값에 대해 식별자로서의 역할을 합니다. 배열 내의 아이템들과 다르게 딕셔너리는 정해진 순서가없습니다. 현실에서의 사전과 같이 특정한 단어의 정의를 찾아보는 것과 마찬가지로 값에 대한 식별자에 기초해 필요로 하는 값을 찾습니다. 

NOTE

스위프트의 딕셔너리타입은 Foundation’s NSDictionary class와연관이있습니다.

딕셔너리와 Foundation and Cocoa에 대한 자세한 정보가 알고 싶다면 Bridging Between Dictionary and NSDictionary를 참조하세요.

Dictionary Type Shorthand Syntax

스위프트의 딕셔너리 타입은 <Key, Value> 형태로 쓰이고 키는 딕셔너리 키로서 사용할 수 있는 값의 타입이고 값은 딕셔너리가 이러한 키들을 저장할 수 있는 값에 대한 타입입니다. 

NOTE

딕셔너리 키는 set의 값 타입처럼 Hashable protocol에 반드시 따라야 합니다. 

딕셔너리의 축양형으로 [Key: Value]로 쓸 수도 있습니다. 비록 두 개의 형태가 기능적으로 같아도 딕셔너리에 대한 타입을 참조할 때 축약형이 더 선호되고 이 가이드 내내 계속 사용됩니다. 

Creating an Empty Dictionary

배열과 마찬가지로 초기화 구문을 사용함으로써 정확한 타입의 비어있는 딕셔너리를 만들 수 있습니다.

 

var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary

 

위의 예는 사람이 읽을 수 있는 정수형 값의 이름을 저장하기 위해 비어있는 딕셔너리 타입을 [Int: String] 만들었습니다. 키의 타입은 정수이고 값의 타입은 문자열입니다. 

문맥상에서 이미 타입에 대한 정보를 제공했다면 [:]로 비어있는 딕셔너리 literal을 가진 비어있는 딕셔너리를 만들 수 있습니다.

 

namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]

Creating a Dictionary with a Dictionary Literal

딕셔너리 literal을 가진 딕셔너리로 초기화할 수 있고 전에 보았던 배열 literal과 유사한 문장을 가지고 있습니다. 딕셔너리 literal은 딕셔너리 모음에서 한 개 혹은 그 이상의 키-값의 쌍을 쓰기 위한 축약형입니다.

키-값 쌍은 키와 값의 조합입니다. 딕셔너리 literal에서 각 키-값 쌍의 키와 값은 콜론으로 구분됩니다. 키-값 쌍은 쉼표로 구분되고 대괄호로 묶고 목록으로 작성됩니다.

 

[key 1: value 1, key 2: value 2, key 3: value 3]

 

아래 예는 국제공항의 이름을 저장하기 위해 딕셔너리를 만들었습니다. 이 딕셔너리에서 키는 3글자로 된 국제 항공 운송 협회 코드로 값은 공항 이름입니다. 

 

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

 

airports 딕셔너리는 [String: String] 타입으로 선언되었으며 키는 문자열이고 값 또한 문자열입니다. 

NOTE

아래 예처럼 더 많은 공항을 딕셔너리에 추가할 수 있기 때문에 airports는 상수가 아니라 변수로 선언되었습니다. 

airports 딕셔너리는 2개의 키-값 쌍을 포함하는 딕셔너리 literal로 초기화했습니다. 첫 번째 쌍은 "YYZ" 키를 가지고 있고 "Toronto Pearson"은 값입니다. 두 번째 쌍은 "DUB" 키를 가지고 있고 "Dublin"은 값입니다.

딕셔너리 literal은 2개의 String: String 쌍을 포함하고 있습니다.

키-값의 타입은 airports 변수 선언의 타입을 매치하고 (딕셔너리는 오직 문자열 키와 문자열 값만 갖습니다) 할당된 딕셔너리 literal에 airport 딕셔너리에 2개의 초기화 아이템의 초기화를 허용합니다.

만약 딕셔너리 literal을 키와 값이 일치하는 타입으로 초기화했다면 배열과 마찬가지로 딕셔너리 타입을 쓸 필요가 없습니다. airports의 초기화는 축약형으로 쓸 수도 있습니다. 

 

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

 

literal 안의 모든 키는 서로 같은 타입이고 마찬가지로 모든 값은 서로 같은 타입이기 때문에 스위프트는 airports 딕셔너리에 사용할 수 있는 정확한 타입은 [String: String]이라고 추론할 수 있습니다.

Accessing and Modifying a Dictionary

methods와 properties를 통해 딕셔너리를 접근과 변경할 수 있거나 subscript 문법을 사용할 수도 있습니다. 배열과 마찬가지로 딕셔너리에서 읽기만 가능한 count 속성을 활용하여 아이템의 개수를 확인할 수 있습니다.  

 

print("The airports dictionary contains \(airports.count) items.")
// Prints "The airports dictionary contains 2 items."

 

Boolean 속성을 가지고 있는 isEmpty를 사용해서 count의 속성이 0인지 빠르게 확인이 가능합니다.

 

if airports.isEmpty {
print("The airports dictionary is empty.")
} else {
print("The airports dictionary is not empty.")
}
// Prints "The airports dictionary is not empty."

 

subscript 문장을 사용해서 딕셔너리에 새로운 아이템을 추가할 수 있습니다. subscript 문장으로 적절한 타입을 가진 새로운 키를 사용함으로써 적절한 타입의 값을 할당할 수 있습니다. 

 

airports["LHR"] = "London"
// the airports dictionary now contains 3 items

 

subscript 문장을 사용해서 특정 키와 관련 있는 값을 바꿀 수도 있습니다. 

 

airports["LHR"] = "London Heathrow"
// the value for "LHR" has been changed to "London Heathrow"

 

subscripting의 대안으로 딕셔너리의 특정한 키의 값을 정하거나 갱신하기 위해 updateValue(_:forKey:) method를 사용합니다. 아래의 subscript와 같은 예는 만약 키값이 존재하지 않아 값을 설정하거나 키값은 존재하는데 값을 경신시켜야 할 때 updateValue(_:forKey:) method는 값을 사용합니다. 그러나 subscript, 와다르게updateValue(_:forKey:) method는 갱신을 한 후 오래된 값을 반환시킵니다. 이러한 현상은 갱신이 발생했는지 안 했는지 확인을 할 수 있습니다. 

The updateValue(_:forKey:) method는 딕셔너리의 값 타입의 옵셔널 값을 반환합니다. 예를 들어 딕셔너리가 문자열 값을 저장한다면 method는 String?, 혹은 “optional String” 값을 반환합니다. 옵셔널 값은 키의 이전 값을 포함하고 갱신 전에 존재했거나 값이 없다면 nil을 갖습니다. 

 

if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
print("The old value for DUB was \(oldValue).")
}
// Prints "The old value for DUB was Dublin."

 

subscript 문장을 활용해서 딕셔너리로부터 특정키에 대한 값을 받을 수 있습니다. 값이 존재하지 않는 키도 요청이 가능하기 때문에 딕셔너리의 subscript는 딕셔너리의 값 타입의 옵셔널 값을 반환받습니다. 만약 요청된 키에 값이 포함되어있다면 subscript는 키에 존재하는 값을 포합 하는 옵셔널 값을 반환받습니다. 그렇지 않으면 subscript는 nil 값을 반환합니다. 

 

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

 

nil값을 할당하여 키-값 문구 쌍을 제거하기 위해 subscript 문구를 사용할 수 있습니다. 

 

airports["APL"] = "Apple International"
// "Apple International" is not the real airport for APL, so delete it
airports["APL"] = nil
// APL has now been removed from the dictionary

 

다른 방법으로 딕셔너리로부터 키-값 쌍을 제거하기 위해 removeValue(forKey:) method를 사용할 수 있습니다. 이 method는 키-값 쌍을 제거하고 값이 존재하거나 제거된 값을 반환하거나 값이 없을 경우 nil을 반환합니다. 

 

if let removedValue = airports.removeValue(forKey: "DUB") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary does not contain a value for DUB.")
}
// Prints "The removed airport's name is Dublin Airport."

Iterating Over a Dictionary

for-in loop로 딕셔너리 키-값 쌍을 반복할 수 있습니다. 딕셔너리에서 각각의 아이템은 (키, 값) 튜플로 반환되며 반복의 일부로서 튜플의 구성원을 일시적인 상수 혹은 변수로 분해할 수 있습니다. 

 

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

 

for-in loop에 대해 더 알고 싶다면 for-in loop를 참조하세요.

 

Swift 공식문서 해설 Control Flow - For-In Loops, While Loops (5-1)

스위프트는 다양한 control flow 문장을 제공합니다. while loop는 어떤 일을 여러 번 시키는 데 사용하고 if, guard, switch 구문은 특정 상황에 따라 다른 코드를 실행시키며 break, continue와 같은 문장은 코..

iosbeginner.tistory.com

 

키와 값 속성으로 접근한다면 딕셔너리의 키 혹은 값의 반복 모음을 받을 수 있습니다. 

 

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와 함께 딕셔너리의 키와 값을 사용해야 하는 경우가 필요로 하다면 키 혹은 값의 속성을 새로운 배열로 초기화합니다.

 

let airportCodes = [String](airports.keys)
// airportCodes is ["LHR", "YYZ"]

let airportNames = [String](airports.values)
// airportNames is ["London Heathrow", "Toronto Pearson"]

 

스위프트의 딕셔너리 타입은 정의된 순서가 없습니다. 딕셔너리의 키 혹은 값을 특정 순서로 반복하기 위해서는 키 혹은 값의 속성의 sorted() method를 사용하세요.