비교 연산자
- 비교한 값을 true 와 false 로 반환한다
- a ==b
a와 b는 같다- a != b
a와 b는 같지 않다
논리 연산자
- 비교한 값을 true 와 false 로 반환한다
- 논리 부정 NOT
!a - 논리 부정 연산자는 true를 false로, false를 true로 변환한다- 논리 곱 AND
a && b - 논리 곱 연산자는 두 값 ( a, b ) 모두 true일 때 true 값을 반환한다. 첫 번째 값이 false라면,두 번째 값을 판단하지 않고 즉시 false로 반환한다- 논리 합 OR
a || b - 논리 합 연산자는 둘 중 하나가 true 면 true 를 반환한다. 첫 번째 값이 true라면, 두 번째 값을 판단하지 않고 true 를 반환한다
삼항 연산자
- a ? b : c = question ? answer1 : answer2
question의 답이 true 이면 answer1을, false 면 answer2 값을 사용한다. if-else 문을 간략하게 표현한 것
옵셔널의 필요성
코딩을 하다보면 빈 값이 발생할 수 있다. 빈 값은 컴퓨터에게는 '있어야할 것이 없다'는 의미이기 때문에 에러를 발생시키고 어플리케이션을 종료시키기도 한다. 그렇기 때문에 모든 변수에 wrapping을 씌어놓으면 값이 있을 때와 없을 때 모두 안전하게 컴퓨터가 값을 읽을 수 있다
- 값이 없을 수 있는 상황에서 옵셔널(Optional)을 사용한다
- 옵셔널은 물음표 ? 로 나타낸다 //타입 어노테이션
- 두가지 가능성을 나타낸다
값이 있고 옵셔널로 래핑(wrapping)해놓은 값을 언래핑(unwrapping)하여 해당 값에 액세스 할 수 있다
값이 전혀 없다- 옵셔널 타입끼리는 연산이 불가능하다
nil
- 변수에 nil을 할당함으로서 값이 없는 상태의 옵셔널 프로퍼티를 만들 수 있다
var myName: String? = "eunsung" myName = nil
옵셔널 바인딩
- 옵셔널 값이 빈 값인지 존재하는지 검사 후, 존재하는 경우 그 값을 다른 변수에 대입시켜 바인딩하는 것을 의미한다
- 빈 값을 체크하고 옵셔널 값을 언래핑하는 것은 강제로 언래핑하는 것보다 훨씬 안전하다
- if let / if var, guard let / guard var 을 써서 옵셔널 값을 추출해 새로운 변수에 바인딩 한다
- if let VS guard let 차이점
if let 은 if문의 코드 구현부 내에서만 상수 사용이 가능하다 ( 지역 변수 )
guard let 은 guard 문을 통과한 상수를 guard문 밖에서 사용이 가능하다 ( 전역 변수 )if let (상수 이름) = (옵셔널 값) { // 구현 코드 }
let ticketCounts: Int? = 5 if let ticket - ticketCounts { print (ticket) }
let x : Int? = 10 let y : Int? = nil func opbinding() { guard let x = x else { return } print (x) guard let y = y else { return } // y는 nil 이므로 return이 실행 print (y) // 위에서 return 실행되었기 때문에 이 코드 라인은 실행 되지 않는다 } opbinding() // 출력값 : 10
옵셔널 강제 언래핑
- ! 을 써서 강제로 옵셔널을 추출한다 ( 변수 앞에 !을 붙이는 것은 not -> 완전히 다른 의미 )
- 강제 언래핑은 잘 못 사용할 경우 프로그램이 비정상적으로 종료되기 때문에 반드시 nil이 아닌 경우에만 사용할 것
let number = Int("42")! // String 값을 Int 로 변환하는 함수는 returng 값으로 옵셔널 값을 반환한다 print(number) // 출력값 : 42 let address: String? = nil print(address!) // 에러 메시지: Unexperctedly found nil while unwrappiung an Optional value
- 옵셔널 변수의 값이 nil일 때를 위해 기본값 설정하기 ( nil-coalescing )
?? 을 사용하여 기본값을 사용할 수 있다. ?? 을 사용하여 기본값을 부여한 변수는 옵셔널 타입이 아니다var optNumber: Int? = 3 let number = optNumber ?? 5 print (number) // 출력값 : 3 //number는 Int? 타입이 아니라 Int 타입
optNumber = nil let number2 = optNumber ?? 5 print (number2) // 출력값 : 5 , nil이기 때문에 뒤에 있는 값이 도출된다
옵셔널 체이닝
- 옵셔널을 연쇄적으로 사용하는 것
- . 을 통해 내부 프토퍼티나 메서드에 연속적으로 접근할 때 옵셔널 값이 있으면 옵셔널 체이닝으로 접근할 수 있다
struct Person { var name: String var address: Address } struct Address { var city: String var street: String var detail: String } let ko: person? = Person(name: "Ko", address: Address(city: "Seoul", street: "Jung-gok", detail: "Korean")) print(sam.address.city) // 에러: Chain the optional using '?' to access member 'address' only for non-'nil' base values print(sam?.address.city) // Seoul 출력
Queue
- First-In-First-Out (FIFO)
- 먼저 들어온 값을 먼저 보내는 구조
// <T> : 제네릭, 하나의 타입에 국한되지 않고 타입에 유연하게 코드를 작성할 수 있는 기능 struct Queue<T> { private var queue: [T] = [] public var count: Int { return queue.count } public var isEmpty: Bool { return queue.isEmpty } public mutating func enqueue(_ element T) { queue.append(element) } public mutating func dequeue() -> T? { return isEmpty ? nil : queue.removeFirst() } } var queue = Queue<Int>() queue.enqueue(10) queue.enqueue(20) queue.dequeue() // 10이 나간다
Stack
- Last-In-First-Out (LIFO)
- 먼저 들어온 값을 가장 마지막에 내보내는 구조
struct Stack<T> { private var stack: [T] = [] public var count: Int { return stack.count } public var isEmpty: Bool { return stack.isEmpty } public mutating func push(_ element T) { stack.append(element) } public mutating func pop() -> T? { return isEmpty ? nil : stack.popLast() } } var stack = Stack<Int>() stack.push(10) stack.push(20) stack.pop() // 20이 나간다
3일 동안의 공백으로 인해 진도를 따라잡으려니 하루종일 정신이 없는 것 같다. 요번 주까지 좀만 더 힘내보자