출처: 스위프트 프로그래밍 - 야곰
var height = 180.5
print(type(of: height)) //Double
스위프트는 암시적 데이터 타입 변환을 지원하지 않습니다.
이니셜라이저(init)를 통해 새로운 인스턴스를 생성하는 과정입니다.
실제로 인스턴스를 수정하거나 값을 변경하는 작업이 아닙니다. 인스턴스는 메모리에 똑같이 남아 있고 그저 컴퓨터에 힌트를 주는 것뿐입니다.
Int 구조체는 이니셜라이저가 다양하게 이미 정의되어 있다.
StringProtocl 타입의 데이터 text를 Int 타입으로 변경 시, 적절치 못한 매개변수가 전달된다면(예를 들어 A123) 새로운 인스턴스가 생성되지 않을 수 있다.
var value: Double = 3.3
var convertedValue: Int = Int(value)
convertedValue = 5.5 //오류, Cannot assign value of type 'Double' to type 'Int'
var stringValue: String = "123"
var integerValue: Int? = Int(stringValue)
print(integerValue) //Optional(123)
stringValue = "A123"
integerValue = Int(stringValue)
print(integerValue) //오류, nil == Optional.none
is와 as 연산자 활용하기
is
class Coffee {
let name: String
let shot: Int
var description: String {
return "\(shot) shot(s) \(name)"
}
init(shot: Int) {
self.shot = shot
self.name = "coffee"
}
}
class Latte: Coffee {
var flavor: String
override var description: String {
return"\(shot) shot(s) \(flavor) latte"
}
init(flavor: String, shot: Int) {
self.flavor = flavor
super.init(shot: shot)
}
}
class Americano: Coffee {
let iced: Bool
override var description: String {
return "\(shot) shot(s) \(iced ? "iced" : "hot") americano"
}
init(shot: Int, iced: Bool) {
self.iced = iced
super.init(shot: shot)
}
}
let coffee: Coffee = Coffee(shot: 1)
print(coffee.description)
let myCoffee: Americano = Americano(shot: 2, iced: false)
print(myCoffee.description)
let yourCoffee: Latte = Latte(flavor: "green tea", shot: 3)
print(yourcoffe)
print(coffee is Coffee) //true
print(coffee is Americano) //false
print(coffee is Latte) //true
print(myCoffee is Coffee) //true
print(yourCoffee is Coffee) //true
print(myCoffee is Latte) //false
print(yourCoffee is Latte) //true
print(type(of: coffee) == Coffee.self) //true
print(type(of: myCoffee) == Coffee.self) //false
print(type(of: yourCoffee) == Coffee.self) //false
if let actingOne: Americano = coffee as? Americano { //부모가 자식으로 X
print("This is Americano")
} else {
print(coffee.description) //1 shot(s) coffee
}
if let actingTwo: Coffee = coffee as? Coffee { //부모가 부모로 || 같은 타입으로 -> as도 가능
print("This is just Coffee") //This is just Coffee
} else {
print(coffee.description)
}
메타 타입
Meta Type: 타입의 타입 타입을 값처럼
표현할 수 있다.protocol SomeProtocol {}
class SomeClass: SomeProtocol {}
let intType: Int.Type = Int.self
let stringType: String.Type = String.self
let stringValueType: String = "StringValue".self
let classType: SomeClass.Type = SomeClass.self
let protocolProtocol: SomeProtocol.Protocol = SomeProtocol.self
var someType: Any.Type
someType = intType
print(someType) //Int
someType = stringType
print(stringType) //String, 타입을 표현하는 값
print(stringValueType) //StringValue, 값
someType = classType
print(someType) //SomeClass
someType = protocolProtocol
print(someType) //SomeProtocol
부모클래스의 타입을 자식클래스의 타입으로 캐스팅하는 것
if let actingThree: Americano = myCoffee as? Americano { //자식이 부모로 O
print("This is Americano") //This is Americano
} else {
print(coffee.description)
}
Any는 모든 타입, AnyObject는 클래스 타입
기본 데이터 타입은 모두 해시 가능한 값이다 (Hashable 프로토콜을 따른다.)
UInt(-부호를 포함하지 않는 0을 포함한 양의 정수)
시스템 아키텍처에 따라 8, 16, 32, 64비트가 있다
print(Int.max) //9223372036854775807 19자리
print(Int.min) //-9223372036854775808
print(UInt.max) //18446744073709551615
print(UInt.min) //0
print(Int64.max) //9223372036854775807
print(Int64.min) //-9223372036854775808
print(Int32.max) //2147483647 10자리
print(UInt8.max) //255
print(Int8.max) //127
print(Int8.min) //-128
var boolean: Bool = true
boolean.toggle() //false
- double:
부호1 + 지수11비트 + 가수52비트 = 64비트
정밀도는 15이다
- float:
부호1 + 지수8 + 가수23 = 32비트
정규화를 통해 24까지 표현이 가능하다
10^7 < 2^24 < 10^8 정밀도는 7이다
유니코드9 단 하나의 문자
let happyImoji: Character = "😄"
print(happyImoji) //😄
유니코드9 문자열
유니코드 스칼라는 UInt32값으로 표현되는 21비트 숫자
var introduce: String = String()
introduce.append("ㅈㅏㄱㅣㅅㅗㄱㅐ")
print(introduce + "ㅅㅣㅈㅏㄱ")
print(introduce.count) //8
print(introduce.isEmpty) //false
let unicodeScalarValue: String = "\u{2665}"
print(unicodeScalarValue) //♥
Float.random(in: 1.5...4.3) //1.9126894
var array: [Int] = [0, 1, 2, 3, 4]
print(array.randomElement()) //Optional(1)
print(array.shuffled()) //[4, 2, 0, 3, 1] 원본 유지
print(array) //[0, 1, 2, 3, 4]
array.shuffle() //원본 변경
print(array) //[4, 3, 1, 0, 2]
var string: String = "string"
print(string.shuffled())
### Never?
let number: Int = 10
print(#"ㅌㅡㄱ수ㅁㅜㄴ자 미ㅅㅏㅇㅛㅇ \" ㅁㅜㄴ자ㅇㅕㄹ 보ㄱㅏㄴ버ㅂ\#(number)"#) //ㅌㅡㄱ수ㅁㅜㄴ자 미ㅅㅏㅇㅛㅇ \" ㅁㅜㄴ자ㅇㅕㄹ 보ㄱㅏㄴ버ㅂ10
#으로 감싸면 \"이 깨져서 보인다
typealias Person = (name: String, age: Int<, height: Double)
let me: Person = ("ㄴㅏ", 12, 123.4)
let sister: Person = ("ㄴㅏㅁ", 14, 234.5)
print("\(me.name) + \(me.1)") //ㄴㅏ + 12
print("\(sister.height), \(sister.0)") //234.5, ㄴㅏㅁ
- Array<String>
- [String]
배열의 내장함수
var names: Array<String> = ["yagom", "chulsoo", "younghee", "yagom"]
//var names: [String] = ["yagom", "chulsoo", "younghee", "yagom"] // 위와 동일한 표현 [String], Array<String>
var emptyArray: [Any] = []
//var emptyArray: [Any] = [Any]()
//var emptyArray: [Any] = Array<Any>() //위와 동일한 표현들
print(emptyArray.isEmpty) //true
print(names.count) //4
print(names[2]) //chulsoo
names[2] = "jenny"
print(names[2]) //jenny
//print(names[4]) //error: Execution was interrupted, reason: EXC_BREAKPOINT (code=1, subcode=0x18ec081b8). 인덱스 오류
names.append("elsa")
names.append(contentsOf: ["john", "max"])
print(names)
names.insert("happy", at: 2) //["yagom", "chulsoo", "jenny", "yagom", "elsa", "john", "max"]
print(names) //["yagom", "chulsoo", "happy", "jenny", "yagom", "elsa", "john", "max"]
print(names.firstIndex(of: "yagom")) //Optional(0)
print(names.firstIndex(of: "christal")) //nil
print(names.first) //Optional("yagom")
print(names.last) //Optional("max")
let firstItem: String = names.removeFirst()
//let firstItem: String = names.removeLast()
print(firstItem) //yagom
let indexZeroItem: String = names.remove(at: 0)
print(indexZeroItem) //chulsoo
print(names[1 ... 3]) //["jenny", "yagom", "elsa"]
키는 중복될 수 없다
typealias StringIntDictionary = [String: Int]
//var numberForName: Dictionary<String, Int> = Dictionary<String, Int>()
//var numberForName: [String, Int] = [String, Int]()
//var numberForName: StringIntDictionary = StringIntDictionary()
//var numberForName: [String: Int] = [:] //위와 동일한 표현들
var numberForName: [String: Int] = ["yagom": 100, "chulsoo": 200, "jenny": 300]
print(numberForName.isEmpty) // false
print(numberForName.count) // 3
print(numberForName["chulsoo"]) //Optional(200)
print(numberForName["minji"]) //nil
numberForName["chulsoo"] = 150
print(numberForName["chulsoo"]) //Optional(150)
numberForName["max"] = 999
print(numberForName["max"]) //Optional(999)
print(numberForName.removeValue(forKey: "yagom")) //Optional(100)
print(numberForName.removeValue(forKey: "yagom")) //nil
print(numberForName["yagom", default: 0]) //0
Array<Int>
를 [Int]
처럼 줄일 수 없다var numbers = [100, 200, 300]
print(type(of: numbers)) //Array<Int> 형태가 []이라 Set가 아니라 Array타입으로 타입추론한다
//var names: Set<String> = Set<String>()
//var names: Set<String> = [] 위와 동일
var names: Set<String> = ["yagom", "chulsoo", "younghee", "yagom"]
print(names) //["chulsoo", "yagom", "younghee"] 순서가 그냥 아무렇게나 되네???
print(names.count) //3
names.insert("jenny")
print(names.count) //4
print(names.remove("chulsoo")) //Optional("chulsoo")
print(names.remove("john")) //nil
print(names.sorted()) //["jenny", "yagom", "younghee"]
옵셔널Optional은 열거형Enum으로 구현되어 있다!
enum School {
case primary
case elementary
case middle
case high
case college
case university
case graduate
}
var highestEducationLevel: School = School.university
//var highestEducationLevel: School = .university (위와 동일)
highestEducationLevel = .graduate //값 변경하기
print(highestEducationLevel) //graduate
rawValue 프로퍼티 사용하기
enum WeekDays: Character {
case mon = "월", tue = "화", wed = "수", thu = "목", fri = "금", sat = "토", sun = "일"
}
let today: WeekDays = WeekDays.fri
print("오늘은 \(today.rawValue)요일입니다.")
enum School: CaseIterable {
case primary
case elementary
case middle
case high
case college
case university
case graduate
}
let allCases: [School] = School.allCases
print(allCases) //[School.primary, School.elementary, School.middle, School.high, School.college, School.university, School.graduate]
열거형 항목의 연관 값이 열거형 자신의 값일 때
이진 탐색 트리 등 순환 알고리즘 구현 시 유용하다
indirect enum ArithmeticExpression {
case number(Int)
case addition(ArithmeticExpression, ArithmeticExpression)
case multiplication(ArithmeticExpression, ArithmeticExpression)
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let final = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
//순환 함수
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case .number(let value):
return value
case .addition(let left, let right):
return evaluate(left) + evaluate(right)
case .multiplication(let left, let right):
return evaluate(left) * evaluate(right)
}
}
let result: Int = evaluate(final)
print("(5 + 4 ) * 2 = \(result)") //(5 + 4 ) * 2 = 18
Class, Struct
class는 참조타입
struct는 값타입
값타입과 참조타입은 뒤에서 라이프타임 ARC와 함께 공부해보자👊