Introduction
: 스위프트의 주요 Collection type은 Array, Set, Dictionary가 있다. 
Array는 ordered collection, Set은 Unordered, unique value collection이고 Dictionary는 Unordered, key-value 기반 collection이다.


Mutability Of Collections
: Mutability를 결정하는 기준은 collection을 var, let 중 무엇으로 선언했느냐에 따른다.
var로 선언하면 mutable이 되고, collection이 포함하고 있는 item들을 adding, removing, changing할 수 있다. 
let으로 선언하면 immutable이 되고, item들의 조작이 불가능하다.

*변경이 불가능한 collection에 대해 모두 immutable로 선언하는 것이 예상치 못한 side effect나 performance 측면에서도 유리하다.


Arrays
: 같은 type의 value들을 저장한다. 똑같은 값의 중복 저장이 가능하다. 
: Objective-C의 NSArray와 bridged(호환)된다. 

Creating an Empty Array

var someInts = [Int]()

print ("someInts is of type [Int] with \(someInts.count) items.")
// Prints "someInts is of type [Int] with 0 items."
// someInts는 [Int] 타입이 된다. Int 타입의 값들을 저장할 수 있는 배열이다.

Array가 이미 타입이 지정되었으면 타입을 명시할 필요없이 바로 'empty array literal'로 빈 배열을 생성할 수 있다. 

someInts.append(3)
// someInts는 1개의 Int 타입의 value를 저장하고 있다.
someInts = []
// someInts는 empty array가 된다. 하지만 여전히 [Int] 타입이다. 

Creating an Array with a Default Value
: Array 초기화시 size와 default값을 지정할 수 있다.

var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles 타입은 [Double]이고, [0.0, 0.0, 0.0] 값을 갖는다.

Creating an Array by Adding Two Arrays Together
: 기존 두개의 Array를 합쳐서 하나의 Array를 생성할 수 있다. 단, 기존 두개의 Array의 타입이 compatible해야 한다.(compatible이란 의미가, 꼭 같은 타입만을 의미하는것은 아닌것 같다. 상속 관계에 있는 클래스로 시도를 해봤으나 실패했다. Double, Int 타입도 실패했다. 하지만 same이 아닌 compatible이란 단어를 쓴것으로 보아 같은 타입이 아님에도 '+' 연산이 되는 type 메커니즘이 있는게 아닐까?)

var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles는 [Double]타입이다.
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles는 [Double]타입으로 추론되고, [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] 값을 갖는다.

Creating an Array with an Array Literal
: Array literal로 Array선언이 가능하다.

var shoppingList: [String] = ["Eggs", "Milk"]

shoppintList는 [String] 타입으로 선언되었기 때문에 array literal 안에는 String 타입의 value들이 들어가야 한다.
단, 타입을 명시하지 않을 수도 있다.

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

타입을 명시하지 않았지만 array literal에 들어있는 값들이 모두 String 타입이기 때문에, [String] 타입으로 추론된다.

Accessing and Modifying an Array
: array의 값을 접근하거나 변경하기 위해서 array의 메서드나 프로퍼티 또는 subscript syntax를 이용한다.

print("The shopping list contains \(shoppingList.count) items")

if (shoppingList.isEmpty) {
    print("The shopping list is empty")
} else {
    print("The shopping list is not empty")
}

append(_:) 메서드를 이용해 item을 array 끝에 추가할 수 있다.

shoppingList.append("Flour")

+= 연산자를 이용해 한개 이상의 item들을 추가할 수 있다.

shoppingList += ["Banking powder"]
shoppingList +=["Chocolate spread", "Cheese", "Butter"]

subscript syntax를 이용해서 값을 검색할 수 있다.

var firstItem = shoppingList[0]

또한 subscript syntax를 이용해 기존 index에 값을 변경할 수 있다.

shoppingList[0] = "Six eggs"

subscript syntax에 범위를 지정해서 값을 변경할 수 도 있다. 심지어 변경하려는 값들의 범위와 subscript syntax로 지정한 범위가 맞지 않아도 된다.

//현재 shoppingList에는 ["Six Eggs", "Milk", "Flour", "Banking powder", "Chocolate Spread", "Cheese", "Butter"] 7개 item들이 들어있다.

shoppingList[4..6] = ["Bananas", "Apples"]
// 4, 5, 6번째 index item인 "Chocolate Spread", "Cheese", "Butter"이 "Bananas", "Apples"로 바뀌면서 shoppingList의 갯수도 7개에서 6개로 줄어들었다. 

shoppingList.insert("Maple Syrup", at: 0)
// 첫번째 index item이 "Maple Syrup"이 되고 나머지 6개 item들은 하나씩 뒤로 밀린다. 총 갯수 7개.

let mapleSyrup = shoppingList.remove(at: 0)
// "Maple Syrup"이 제거 되고 다시 갯수는 6개가 된다. 

let apples = shoppingList.removeLast()
// "Apples"가 제거 된다. array의 마지막 item을 제거할 때는 remove(at:) 보다 removeLast()를 사용해라. index가 array의 범위를 벗어나면 runtime error가 발생한다.

Iterating Over an Array

for item ins shoppingList  {
    print(item)
}
// Six eggs, Mils, Flour, Baking Powder, Bananas가 출력된다.

for (index, value) in shoppingList.enumerated() {
    print("Item \(index + 1): \(value)
")
}
// index가 필요한 경우 Tuple을 사용한 enumerate를 한다.


Sets
: Set은 
Unordered, unique value collection이다. Objective-C의 NSSet과 bridged 된다.

Hash Values For Set Types
: Set에 저장되기 위해선 hashable type이어야 한다. 즉, hash value를 계산할 수 있는 type이어야 하고, a == b 이면, a.hashValue == b.hashValue 여야 한다.
Swift의 모든 basic type( String, Int, Double, Bool )들은 hashable 하다. Enumeration case value들도(associated value들 없이) 기본적으로 hashable 하다.  

* 자신이 만든 custom type이 dictionary key나 set value type으로 저장되길 원한다면, Hashable 프로토콜을 
conform해야 한다. hashable 프로토콜을 구현한다는 것은 hashValue를 property로 제공해야 한다는 것이다. 다만, hashValue는 꼭 프로그램내 또는 다른 프로그램에서 항상 같은 값을 가지고 있을 필요 없다.

Hashable 프로토콜은 Equatable 프로토콜을 conform하고 있으므로 equals operator(==)를 구현해야만 한다. '==' 구현은 다음 세가지 조건을 만족해야 한다.
1) a == a
2) a == b 는 b == a를 의미한다.
3) a == b 이고 b == c 이면 a == c 이다.

Set Types Syntax
: Set<Element> 일때, 'Element'는 해당 Set이 저장할 수 있는 Type 이라는 뜻이다.

Creating and Initializing an Empty Set

var letters = Set<Character>()

print("letters is of type Set<Character> with (letters.count) items.")

letters.insert("a")
letters = []
// letters는 empty set이 되지만, Set<Character> type을 유지한다.

Creating a Set with an Array Literal

var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
// 이처럼 type을 생략할 수도 있다.

Accessing and Modifying a Set

print("I have \(favoriteGenres.count) favorite music genres.")
// Prints "I have 3 favorite music genres."

if favoriteGenres.isEmpty {
    print("As far as music goes, I'm not picky.")
} else {
    print("I have particular music preferences.")
}

favoriteGenres.insert("Jazz")
// 4 items을 포함하게 된다.

if let removedGenre = favoriteGenres.remove("Rock") {
    print("\(removedGenre)? I'm over it.")
} else {
     print("I never much cared for that.")
}
// Rock이 있기 때문에 Rock이 제거되고 "Rock? I'm over it."이 출력된다. 3 items을 포함하게 된다.

if favoriteGenres.contains("Funk") {
    print("I get up on the good foot.")
} else {
    print("It's too funky in here.")
}
// 해당 item이 포함되었는지 check하기 위해 contains() 메서드를 사용한다.

Iterating Over a Set

for genre in favoriteGenres {
    print("\(genre)")
}
// Jazz, Hip hop, Classical을 출력.

Set은 unordering collection이기 때문에 ordered iterating을 하기 위해서는 sorted() 메서드를 사용해야 한다. sorted() 메서드는 '<' operator 기준으로 정렬시킨 array를 반환한다.

for genre in favoriteGenres.sorted() {
    print("\(genre)")
}
// Classical, Hip hop, Jazz 순으로 출력된다.


Performing Set Operations
: set operation들을 통해서 교집합, 합집합, 여집합 등을 체크할 수 있다.

Fundamental Set Operations


let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]

oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]

Set Membership and Equality

- '==' operator는 두 set이 모두 같은 value들을 포함하고 있는지 체크한다.
- isSubset(of:), isSuperset(of:)를 통해 포함관계(equal도 포함)를 파악할 수 있다.
- isStrictSubset(of:), isStrictSuperset(of:)은 equal은 해당되지 않는 포함관계를 파악할 수 있다.
- isDisjoint(with:)를 통해 두 set이 서로소 인지 체크할 수 있다.


Dictionaries
: <key, value> 이면서 unordering collection이다. Objective-C의 NSDictionary 타입과 bridged 된다.

Dictionary Type Shorthand Syntax
: dictionary의 keyType은 hashable 프로토콜을 conform해야 한다. dictionary 타입은 '[Key:Value]'로 표현할 수 있다.

Creating an Empty Dictionary

var namesOfIntegers = [Int: String]()

namesOfIntegers[16] = "sixteen"
namesOfIntegers = [:]
// namesOfIntegers는 empty dictionary로 초기화 되었더라도 기존 type인 '[Int: String]'을 유지한다.

Creating a Dictionary with a Dictionary Literal

var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 타입을 명시하지 않고 Dictionary 초기화가 가능하다.

Accessing and Modifying a Dictionary

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

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

airports["LHR"] = "London"
// airports는 이제 3 item을 포함한다.

airports["LHR"] = "London Heathrow"
// "London" 값을 "London Heathrow"로 대체된다. 

위 subscript를 사용해서 value를 set하는 것을 updateValue(_:forKey:) 메서드로 대체할 수 있다. 다만, 
updateValue(_:forKey:) 메서드는 oldValue가 존재하면 return 한다.

if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
    print("The old value for DUB was \(oldValue).")
}
// "
DUB" key에 "Dublin" 값이 저장되어 있기 때문에 oldValue에 "Dublin"이 return 된다.
// "The old value for DUB was Dublin" 출력.

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" 출력

airports["APL"] = "Apple International"
airports["APL"] = nil
// nil 값을 대입하면 해당 Key, Value는 Dictionary에서 제거 된다. 

위 nil을 대입해서 해당 값을 제거하는것을 removeValue(forKey:) 메서드로 대체할 수 있다. 이 메서드는 해당 값이 있으면 제거하고 제거된 값을 return한다. 해당값이 없으면 nil을 return 한다. 

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.")
}
// 
"DUB" key에 대한 "Dublin Airport"이 removedValue에 대입된다.
// "The removed airport's name is Dublin Airport." 출력

Iterating Over a Dictionary

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

for airportCode in airports.keys {
    print("Airport code: \(airportCode)")
}
// key만 iterating이 가능하다.

for airportName in airports.values {
    print("Airport name: \(airportName)")
}
// value만 iterating이 가능하다.

Dictionary의 keys, values를 통해 array를 초기화 할 수 있다.

let airportCodes = [String](airports.keys)
// airportCodes는 ["YYZ", "LHR"]로 초기화 된다.

let airportNames = [String](airports.values)
// airportNames는 ["Toronto Pearson", "London Heathrow"]로 초기화 된다.

Dictionary는 unordering collection이다. ordering iterating을 하려면 keys 또는 values의 sorted() 메서드로 iterating을 해야한다. 

'IOS > Swift' 카테고리의 다른 글

[Swift 4.0] Functions  (0) 2017.04.01
[Swift 4.0] Control Flow  (0) 2017.04.01
[Swift 4.0] Strings and Characters  (0) 2017.01.22
[Swift 4.0] Basic Operators  (0) 2017.01.16
[Swift 4.0] The Basics  (0) 2017.01.13
Posted by 홍성곤
,