도래울

Swift 배열과 딕셔너리 본문

개발/iOS

Swift 배열과 딕셔너리

도래울 2016. 7. 12. 10:58

1. 배열

Swift에서 배열을 정의 하는 방법은 세 가지로 나눌수 있겠군요.

1
2
3
var implicitArray = ["Eggs", "Milk"]
var explicitArray_1: [String] = ["Eggs", "Milk"]
var explicitArray_2: Array<String> = ["Eggs", "Milk"]

간단한 변수 선언에서 했던 것처럼 형태가 정의되지 않은 변수를 선언한 뒤에 배열 형태의 값을 초기에 할당하여 이 변수가 배열임을 암묵적으로 선언하는 방법이 첫번째네요.

두번째는 이 변수가 [String]타입의 변수임을 선언하는 방법이 있네요. 대괄호는 배열임을, 그 안에 배열이 어떠한 타입의 값이 들어가는지를 표시하네요. 낯설지만 어떻게 생각하면 직관적이기도 한 방법이네요. 세번째로는 배열임을 Array<>로 선언하고, <>안에 타입명을 넣어주는 방법이네요. 이 방법은 C에서 CArray 클래스로 배열을 사용했던 방법과 유사한것 같네요.



이렇게 배열을 선언하면 이 변수는 하나의 클래스처럼 배열 안의 값을 접근 할 수 있게 하는 메소드들을 가지고 있습니다. 예를 위해 다음과 같은 하나의 배열을 선언해 봅시다.

1
var shoppingList = ["Eggs", "Milk"]



배열 안에 몇 개의 값이 있는지는 shoppingList.count 메소드를 통해 알아낼 수 있습니다.

1
2
3
var numberOfList = shoppingList.count
println("The shopping list contains \(numberOfList) items.")
// prints "The shopping list contains 2 items."



배열이 비어있는지 아닌지는 shoppingList.isEmpty 메소드를 통해 알아낸다고 하네요.
1
2
3
4
5
6
if shoppingList.isEmpty {
    println("The shopping list is empty")
} else {
    println("The shopping list is not empty")
}
// prints "The shopping list is not empty

당연히 현재 shoppingList 배열에는 "Eggs"와 "Milk"가 들어있으므로 비어있지 않기때문에 false를 반환할 것이고 else안의 println()을 실행하겠군요.



배열의 끝에 새로운 값을 추가하는 방법은 두 가지가 있습니다. append 메소드를 사용하거나, 혹은 '+=' 오퍼레이터를 활용하거나.

1
2
3
4
5
6
shoppingList.append("Flour")
// shoppingList now contains 3 items.
shoppingList += ["Baking Powder"]
// shoppingList now contains 4 items.
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList now contains 7 items.

처음에 shoppingList.append()를 통해 "Flour"을 삽입하여 "Milk" 다음에 삽입 된것을 확인할 수 있네요. 그 다음으로는 '+=' 오퍼레이터를 이용하여 "Baking Powder"를, 그리고 '+=' 연산자로 한꺼번에 여러개의 값을 삽입할 수도 있네요.



배열 안의 값을 읽는데는 별도의 메소드 없이 흔히 C와 JAVA에서 배열의 값을 읽어오던 서브스크립트 문법(Subscript syntax) 그대로 사용할 수 있습니다.

1
2
var firstItem = shoppingList[0]
// firstItem is equal to "Eggs"

위의 shoppingList에 있는 인덱스 0에 해당하는 값을 firstItem에 잘 저장한 것이 보이는군요.



마찬가지로 어떠한 위치에 있는 값을 바꾸는 데에도 동일한 방법을 사용할 수 있습니다. 뿐만 아니라, 여러 개의 값을 동시에 바꿀 수 있는데, 저장될 인덱스 값의 범위와 저장할 값의 갯수가 차이가 나도 바꿀수 있다는군요.

1
2
3
4
shoppingList[0] = "Six eggs"
// the first item in the list is now equal to "Six eggs" rather than "Eggs"
shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList now contains 6 items.

위의 shoppingList 배열과 비교했을 때, 0번 인덱스에 해당하는 값이 "Eggs"에서 "Six eggs"로 바뀌었습니다. 또, 4~6번 인덱스에 있던 "Chocolate Spread", "Cheese", "Butter" 3개의 값들이 "Bananas", "Apples" 2개로 대치되면서 배열의 크기가 자동으로 줄어듦을 확인할 수 있습니다.



우리는 특정 위치에 값을 삽입할 수도 있습니다.

1
2
3
shoppingList.insert("Maple Syrup", atIndex: 0)
// shoppingList now contains 7 items.
// "Maple Syrup" is now the first item in the list.

shoppingList.insert() 메소드를 활용하여 "Maple Syrup"을 인덱스 0에 해당하는 곳에 삽입합니다. 그 자리에 있던 값들은 하나씩 뒤로 밀리는군요.



마찬가지로 특정 위치에 삽입을 한다면 삭제도 가능하겠죠.

1
2
3
4
let mapleSyrup = shoppingList.removeAtIndex(0)
// the item that was at index 0 has just been removed
// shoppingList now contains 6 items, and no Maple Syrup
// the mapleSyrup constant is now equal to the removed "Maple Syrup" string

shoppingList.removeAtIndex() 메소드는 해당 인덱스의 값을 배열에서 삭제하면서 해당 값을 반환하는 역할을 하는군요. 이 외에도 다양한 메소드들을 가지고 있음을 직접 확인해 볼 수 있을 것입니다.



배열의 초기화는 다음과 같이 선언합니다.

1
var emptyArray = [String]()

위 방법은 물론 암시적 형태의 배열 변수 선언이겠죠. 크기가 0인 배열이므로 append 메소드를 통해 배열의 크기를 증가시키면서 값을 입력해야 할 것입니다. 0인 인덱스도 존재하지 않으므로 서브스크립트 문법으로 접근할 수 있는 값이 없으므로 emptyArray[0] = "Eggs"와 같은 값의 삽입이 불가능 하겠죠.



또한 값을 추가한 뒤에, 다시 초기화 할 경우는 아래와 같이 수행할 수 있습니다.

1
2
3
4
emptyArray.append("Eggs")
// emptyArray now contains 1 value of type String
emptyArray = []
// emptyArray is now an empty array, but is still of type [String]

이와 같이 수행할 경우 다시 빈 배열이 되지만 이전에 String으로 선언했던 배열이므로 저장할 수 있는 타입은 여전히 String이 됩니다.


Swift의 배열은 특정한 값들로 특정한 사이즈의 배열을 바로 만들 수 있는 초기화 메소드(initializer)또한 제공합니다.

1
2
var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
위와 같이 선언할 경우 3의 크기를 갖는 모든 값이 0.0으로 초기화되어 있는 배열이 생성됩니다. [0.0, 0.0, 0.0]


또한 기존의 배열을 이용하여 새로운 배열도 생성 할 수 있습니다.
1
2
3
4
var anotherThreeDoubles = [Double](count: 3, repeatedValue: 2.5)
// anotherThreeDoubles is inferred as [Double], and equals [2.5, 2.5, 2.5]
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

[0.0, 0.0, 0.0] 배열과 [2.5, 2.5, 2.5] 배열을 합치면서 새로운 배열 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]를 생성했습니다!


2. 딕셔너리

딕셔너리는 배열과는 달리 인덱스에 해당하는 값을 원하는 형태로 선택할 수 있는 데이터 구조체라 볼 수 있겠죠. 이름 그대로 사전처럼 어떠한 문자열을 찾아 그 내용을 찾아 볼 수 있겠죠. 이를테면 airport["ICN"] = "Incheon"과 같은 형태로 말이죠. 이처럼 [Key: Value]형태로 짝을지어 구성할 수 있게 됩니다. "ICN"은 Key가, "Incheon"은 Value가 되겠죠.

마찬가지로 딕셔너리도 배열과 같이 다음과 같은 형태로 선언할 수 있습니다.

1
2
3
var implicitDictionary = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
var explicitDictionary_1: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
var explicitDictionary_2: Dictionary<String, String> = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]


딕셔너리의 메소드들은 배열과 비슷하지만 다른 특성을 가진것도 있습니다.

딕셔너리 또한 서브스크립트 문법을 활용이 가능하지만 배열과는 달리 존재하지 않는 key값은 접근하지 못하는 것이 아니라 새로운 값을 바로 삽입이 가능합니다. 예를 들어 다음과 같은 딕셔너리가 존재한다고 해 봅시다.

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



"LHR"이라는 존재하는 Key를 참조해 삽입해 보도록 하죠.

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

"LHR"은 존재하지 않지만 오류없이 정상적으로 삽입이 됨을 알 수 있습니다. 배열의 경우에는 존재하지 않는 범위의 인덱스를 참조하여 삽입하는게 불가능하죠.



다시 같은 값으로 참조하여 "London" 대신 "London Heathrow"를 입력하면 어떻게 될까요?

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

참조할 Key가 존재하면 그 Key에 해당하는 Value를 바꿔줌을 확인 할 수 있군요.


딕셔너리의 삽입은 메소드를 통해서도 활용이 가능합니다.

1
2
3
4
5
if let oldValue = airports.updateValue("Incheon", forKey: "ICN") {
    println("The old value for ICN was \(oldValue).")
} else {
    println("Insert [\"ICN\": \"Incheon\"]")
}

airports.updateValue(value, key)메소드는 존재하는 key일 경우는 대체를, 아닐 경우에는 삽입을 동시에 하는 메소드입니다. 이 값은 존재하지 않을 경우 nil값을 반환할 수 있는 optional 값을 반환하는데 이 optional에 대한 이야기는 다음 장에서 해보도록 해요.



마찬가지로 존재 하지 않는 key에 대해서 찾으려고 할 경우에도 에러를 출력하지 않고 nil 값을 반환합니다.

1
2
3
4
5
if let airportName = airports["HKG"] {
    println("The name of the airport is \(airportName).")
} else {
    println("That airport is not in the airports dictionary.")
}

"HKG"라는 Key는 존재하지 않지만 정상적으로 코드는 동작하여 else에 있는 println()을 실행하게 됩니다.


마지막으로 해당 Key와 Value를 삭제할때는 다음과 같은 방법으로 이루어집니다.

1
airports["ICN"] = nil

단순히 값에 nil을 할당하는 것 만으로도 딕셔너리에서 삭제가 됩니다.

또한 다음과 같은 메소드로도 삭제가 되는군요.

1
2
3
4
5
6
if let removedValue = airports.removeValueForKey("DUB") {
    println("The removed airport's name is \(removedValue).")
} else {
    println("The airports dictionary does not contain a value for DUB.")
}
// prints "The removed airport's name is Dublin Airport."


딕셔너리의 초기화는 배열과 동일하게 진행됩니다.

Comments