기본 데이터 타입
Bool
true
와false
만을 값으로 가지는 타입
Int, UInt
Int
- 정수 타입. 현재는 기본적으로 64비트 정수형.
UInt
- 양의 정수 타입. 현재는 기본적으로 64비트 양의 정수형.
Float, Double
Float
- 실수 타입. 32비트 부동소수형.
Double
- 실수타입. 64비트 부동소수형.
Character, String
Character
- 문자 타입. 유니코드 사용. 큰따옴표("") 사용.
String
- 문자열 타입. 유니코드 사용. 큰따옴표("") 사용.
- 여러줄 문자열은 큰따옴표 세 개 사용.
생각해보기
다음 코드에서 integer, floatingPoint, apple 상수는 각각 어떤 타입이 될까요? 상상해보고 확인해보세요~!
// **힌트 : type(of: )**
let integer = 100
let floatingPoint = 12.34
let apple = "A"
Any, AnyObject, nil
Any
Swift의 모든 타입을 지칭하는 키워드
Any 타입에 Double 자료를 넣어두었더라도 Any는 Double 타입이 아니기 때문에 할당할 수 없습니다. 명시적으로 타입을 변환해 주어야 합니다. 타입 변환은 차후에 다룹니다
AnyObject
모든 클래스 타입을 지칭하는 프로토콜
클래스와 프로토콜에 대한 설명은 차후에 합니다
AnyObject는 클래스의 인스턴스만 수용 가능하기 때문에 클래스의 인스턴스가 아니면 할당할 수 없습니다.
nil
없음을 의미하는 키워드
다른 언어의 NULL, Null, null 등과 유사한 표현입니다.
아래 코드에서 someAny
는 Any
타입이고, someAnyObject
는 AnyObject
타입이기 때문에 nil
을 할당할 수 없습니다.nil
을 다루는 방법은 옵셔널 파트에서 다룹니다.
컬렉션 타입
Array
Array는 멤버가 순서(인덱스)를 가진 리스트 형태의 컬렉션 타입입니다.
Array는 여러 리터럴 문법을 활용할 수 있어서 표현 방법이 다양합니다. let을 사용하여 Array를 선언하면 불변 Array가 됩니다.
// 빈 Int Array 생성
var integers: Array<Int> = Array<Int>()
integers.append(1)
integers.append(100)
//integers.append(101.1)
print(integers) // [1, 100]
print(integers.contains(100)) // true
print(integers.contains(99)) // false
integers.remove(at: 0)
integers.removeLast()
integers.removeAll()
print(integers.count) // 0
//integers[0] // 범위 초과 - 런타임 오류 발생
// Array<Double>와 [Double]는 동일한 표현
// 빈 Double Array 생성
var doubles: Array<Double> = [Double]()
// 빈 String Array 생성
var strings: [String] = [String]()
// 빈 Character Array 생성
// []는 새로운 빈 Array
var characters: [Character] = []
// let을 사용하여 Array를 선언하면 불변 Array
let immutableArray = [1, 2, 3]
// 불면 Array의 요소는 추가/삭제 불가 - 컴파일 오류 발생
//immutableArray.append(4)
//immutableArray.removeAll()
Dictionary
Dictionary는 키
와 값
의 쌍으로 이루어진 컬렉션 타입입니다.
Dictionary는 여러 리터럴 문법을 활용할 수 있어서 표현 방법이 다양합니다let을 사용하여 Dictionary를 선언하면 불변 Dictionary가 됩니다키에 해당하는 값을 다른 변수나 상수에 할당하고자 할 때는 옵셔널과 타입 캐스팅 파트에서 다룹니다
// Key가 String 타입이고 Value가 Any인 빈 Dictionary 생성
var anyDictionary: Dictionary<String, Any> = [String: Any]()
anyDictionary["someKey"] = "value"
anyDictionary["anotherKey"] = 100
print(anyDictionary) // ["someKey": "value", "anotherKey": 100]
// Key에 해당하는 값 변경
anyDictionary["someKey"] = "dictionary"
print(anyDictionary) // ["someKey": "dictionary", "anotherKey": 100]
// Key에 해당하는 값 제거
anyDictionary.removeValue(forKey: "anotherKey")
anyDictionary["someKey"] = nil
print(anyDictionary) // [:]
// 빈 Dictionary 생성
let emptyDictionary: [String: String] = [:]
// 초기 값을 가지는 Dictionary 생성
let initalizedDictionary: [String: String] = ["name": "yagom", "gender": "male"]
// let으로 선언한 불변 Dictionary는 수정 불가 - 컴파일 오류 발생
//emptyDictionary["key"] = "value"
// name 키에 해당하는 값이 Dictionary에 존재하지 않을 수 있으므로
// 컴파일 오류 발생 - 옵셔널 파트에서 상세히 다룹니다
//let someValue: String = initalizedDictionary["name"]
Set
Set는 순서가 없고, 멤버가 유일한 것을 보장하는 컬렉션 타입입니다.
Set는 집합연산에 많이 활용됩니다
// 빈 Int Set 생성
var integerSet: Set<Int> = Set<Int>()
integerSet.insert(1)
integerSet.insert(100)
integerSet.insert(99)
integerSet.insert(99)
integerSet.insert(99)
print(integerSet) // [100, 99, 1]
print(integerSet.contains(1)) // true
print(integerSet.contains(2)) // false
integerSet.remove(100)
integerSet.removeFirst()
print(integerSet.count) // 1
// Set는 집합 연산에 꽤 유용합니다
let setA: Set<Int> = [1, 2, 3, 4, 5]
let setB: Set<Int> = [3, 4, 5, 6, 7]
// 합집합
let union: Set<Int> = setA.union(setB)
print(union) // [2, 4, 5, 6, 7, 3, 1]
// 합집합 오름차순 정렬
let sortedUnion: [Int] = union.sorted()
print(sortedUnion) // [1, 2, 3, 4, 5, 6, 7]
// 교집합
let intersection: Set<Int> = setA.intersection(setB)
print(intersection) // [5, 3, 4]
// 차집합
let subtracting: Set<Int> = setA.subtracting(setB)
print(subtracting) // [2, 1]
생각해보기
/* 생각해보기
다음과 같은 경우에는 각각 어떤 컬렉션 타입을, 상수/변수 선언 중 어떤 것을 사용하면 유용할지 생각해 봅시다.
- 영어 알파벳 소문자를 모아두는 컬렉션
- 책의 제목과 저자 정리를 위한 컬렉션
- 우리반 학생 명부 작성을 위한 컬렉션
*/
열거형
정의 문법
스위프트의 열거형은 다른 언어의 열거형과는 많이 다릅니다. 잘 살펴보아야 할 스위프트의 기능 중 하나입니다.
enum은 타입이므로 대문자 카멜케이스를 사용하여 이름을 정의합니다
각 case는 소문자 카멜케이스로 정의합니다
각 case는 그 자체가 고유의 값입니다
각 케이스는 한 줄에 개별로도, 한 줄에 여러개도 정의할 수 있습니다
enum 이름 {
case 이름1 case 이름2 case 이름3, 이름4, 이름5 // ...
}
원시값
C 언어의 enum처럼 정수값을 가질 수도 있습니다. rawValue를 사용하면 됩니다.case별로 각각 다른 값을 가져야합니다
정수 타입 뿐만 아니라 Hashable
프로토콜을 따르는 모든 타입이 원시값의 타입으로 지정될 수 있습니다.
enum Fruit: Int {
case apple = 0
case grape = 1
case peach
// case mango = 0
}
print("Fruit.peach.rawValue == \(Fruit.peach.rawValue)")
// Fruit.peach.rawValue == 2
enum School: String {
case elementary = "초등"
case middle = "중등"
case high = "고등"
case university
}
print("School.middle.rawValue == \(School.middle.rawValue)")
// School.middle.rawValue == 중등
print("School.university.rawValue == \(School.university.rawValue)")
// School.middle.rawValue == university
원시값을 통한 초기화
rawValue를 통해 초기화 할 수 있습니다. rawValue가 case에 해당하지 않을 수 있으므로 rawValue를 통해 초기화 한 인스턴스는 옵셔널 타입입니다.
//let apple: Fruit = Fruit(rawValue: 0)
let apple: Fruit? = Fruit(rawValue: 0)
if let orange: Fruit = Fruit(rawValue: 5) {
print("rawValue 5에 해당하는 케이스는 \(orange)입니다")
} else {
print("rawValue 5에 해당하는 케이스가 없습니다")
} // rawValue 5에 해당하는 케이스가 없습니다
메서드
스위프트의 열거형에는 메서드도 추가할 수 있습니다.
enum Month {
case dec, jan, feb
case mar, apr, may
case jun, jul, aug
case sep, oct, nov
func printMessage() {
switch self {
case .mar, .apr, .may:
print("따스한 봄~")
case .jun, .jul, .aug:
print("여름 더워요~")
case .sep, .oct, .nov:
print("가을은 독서의 계절!")
case .dec, .jan, .feb:
print("추운 겨울입니다")
}
}
}
Month.mar.printMessage()
// 따스한 봄~
실습내용
- 태양계 행성을 SolarSystemPlanet 이라는 이름의 열거형으로 표현해 봅시다.
- SolarSystemPlanet 열거형의 각 케이스에 원시값을 할당해 봅시다.
- 원시값을 통해 SolarSystemPlanet 인스턴스를 생성해 봅시다.
Typealias
- 스위프트에서 기본으로 제공하는 데이터 타입이든, 사용자가 임의로 만든 데이터 타입이든 이미 존재하는 데이터 타입에 임의로 다른 이름(별칭)을 부여할 수 있습니다.
Swift 타입 깊게 알아보기
- Swift는 다른 언어에 비해 상당히 간단하며 매우 명확한 타입 시스템 아키텍처를 갖고 있습니다.
- swift에서는 모든 타입이 상속 없이 구조체입니다.
- 그 이유는 각 타입 간의 커플링을 가능한 한 느슨하게 하고 전체 타입 시스템에서 확장될 수 있도록 하기 위해서입니다. 덕분에 클린 아키텍처를 만들 수 있죠.
명명된 타입(Named Type)
- 명명된 타입은 클래스, 구조체, 열거형과 프로토콜 등 이름이 있는 타입입니다. 사용할 때 이름을 붙이는 모든 것이죠.
복합 타입(Compound Type)
- 튜플, 함수, 가변 매개 변수, 클로저 등 이름이 없는 타입입니다.
튜플
var greatTuple = (x: 10, y: 20)
greatTuple = (x: 12, y: 50)
greatTuple = (0,0)
print("\(greatTuple.0) == \(greatTuple.x)") // 0 == 0
- 위 코드의
greatTuple
변수는 Int, Int 타입을 가집니다. 겉모습만 좀 다를 뿐 실제 타입입니다. - 매개 변수를 그대로 두고 숫자 자체를 사용하면 다른 Int, Int 튜플을 넣거나 할당할 수 있습니다.
.0
이나.1
과 같은 값을 입력하면 되죠. 아니면 매개변수 이름을 다시 사용해도 됩니다. - 반환 타입을 튜플로 정의하는 것만으로도 함수에서 하나 이상의 값을 반환할 수 있습니다.
- 튜플 타입은 이름이 없지만 이름을 붙일 수도 있습니다. 위 코드의 typealias를 확인하세요.
- 두 개의 Int를 가진 튜플을
Point
라는 이름의 변수로 정의했습니다.
함수 타입
튜플처럼 함수 타입도 일반적으로 사용할 수 있습니다.
func processPerson (withID: Int) -> () {}
func processVIP (withID: Int) {} struct Person { firstname : String lastname : String } func nameForPerson (withID: Int) -> (name: String, age: Int) {} func nameForPerson (withID: Int) -> (Person) {} func nameForPerson (withID: Int) -> Person {} func detailsForPerson (withID: Int) -> (obj: Person, age: Int) {}
아무 것도 반환하고 싶지 않으면 아무 것도 쓰지 않으면 됩니다.
함수 이름과 중괄호 사이에 있는 것이 함수 타입입니다.
가변 매개 변수(Variadic Parameter)
많은 프로그래밍이 가변 매개 변수를 허용합니다.
func printAll(_ numbers: Int...) -> Int {
for number in numbers { print ( "the number \(number)") } }
위 함수에 네 개의 Int 매개 변수가 있습니다.
타입 식별자 뒤에 점을 세 개 붙이면 이 변수를 배열로 취급하면서 사용할 수 있습니다.
클로저
- 다음에 아라보자
Nested Types (중첩 타입)
- 보다 복잡한 타입의 컨텍스트내에서 사용하기 위해, 유틸리티 클래스 및 구조체를 정의하는 것이 편리할 수 있습니다.
- 이를 달성하기 위해 Swift는 중첩된 타입(Nested Types)을 정의할 수 있습니다. 즉, 지원하는 타입의 정의내에서 클래스 및 구조체, 열거형을 중첩할 수 있습니다.
- 타입을 다르 타입에 중첩시킬려면 지원하는 타입의 외부 중괄호 안에 해당 정의를 작성하세요. 타입은 필요한 수준만큼 중첩될 수 있습니다.
BlackjackCard 예제
- 아래 예제는 BlackjackCard(블랙잭카드)라는 구조체를 정의합니다. BlackjackCard는 Blackjack게임에서 사용되는 카드를 모델링합니다.
- BlackjackCard 구조체에는 Suit및 Rank라는 두개의 중첩된 열거타입이 있습니다.
- Blackjack에서는 Ace카드의 값이 1 또는 11입니다.
- 이 기능은 Values라는 구조체로 표현되며, Rank열거형 내에 중첩되어 있습니다.
Struct BlackjackCard
ㄴ enum Suit
ㄴ enum Rank
ㄴ Struct Value
댓글