-
[Swift] Enumeration🍏Swift 2023. 2. 9. 17:20
안녕하세요 오늘은 평소 제가 개발하면서 많이 사용하는 열거형에 대한 부분을 공부해보려고 합니다!
제가 평소 열거형을 많이 사용하는 이유는 아래와 같습니다!
- 깔끔하고 가독성 좋은 코드를 쓰는데도 큰 도움이 됩니다!
- Raw한 값들을 열거형으로 정의하여 오타낼 일을 줄일 수 있어 안정성도 향상된다고 생각합니다!
그럼 어떻게 사용해 볼 수 있을까요?
개념부터 차근차근 알아보겠습니다!
기본 개념
- 문법
연관된 상수(케이스)들을 하나의 이름으로 묶은 자료형(타입)
//케이스가 한정된 가짓 수로 정해져 있을때 정의 //가위바위보, 동서남북과 같은 느낌 //열거형을 사용하면 코드의 가독성과 안정성이 높아짐 enum CompassPoint { case north, south, east, west } enum RockScissorsPaper{ case Rock case Scissors case Paper }💡 열거형에서는 저장속성은 추가할 수 없지만 타입속성은 추가할 수 있음
- 원시값
열거형 타입의 각 케이스에 정수 또는 문자열을 매칭시켜 타입을 생성하거나 다룰 때 조금 더 편하게 사용하려는 목적
//여러가지 형태로 원시값을 정의 가능(Hashable한 Int/String/Character/Double 가능) enum Weekday: Int{ case monday case tuesday case wednesday case thursday case friday case saturday case sunday } //원시값은 옵셔널타입 Weekday(rawValue: 0) //그러므로 옵셔널값을 안전하게 벗겨서 사용해야함 if let w = Weekday(rawValue: 0){ print(w) }- 연관값
열거형 타입의 각 케이스의 카테고리에 해당하는 구체적인 정보를 저장하기위해 사용
enum Computer { case cpu(core: Int, ghz: Double) case ram(Int, String) case hardDisk(gb: Int) } // 각 케이스별로 상이한 특징이 있고, 그것을 저장 / 활용할 필요가 있을 때 // 개별케이스마다 저장할 형식을 따로 정의(자료형에 제한이 없음 / 튜플의 형태) // 하나의 케이스에 서로다른 연관값을 저장할 수 있음 ===> 선언시점이 아니라, 새로운 열거형 값을 생성할때 저장- 원시값과 연관값의 차이
- 자료형 선언 방식: 선언하는 위치가 다름
- 선언 형식: 원시값: 2가지중 1가지 선택 / 연관값: 튜플의 형태로 형식 제한 없음
- 값의 저장 시점: 원시값: 선언시점 / 연관값: 새로운 열거형 값을 생성할 때
- 서로 배타적: 하나의 열거형에서 원시값과 연관값을 함께 사용하는 것은 불가능함
- 옵셔널 타입에 대한 정확한 이해
옵셔널 타입의 내부는 열거형, 열거형의 연관값으로 값이 저장
//옵셔널 타입의 내부 구현 enum Optional<Wrapped> { // 제네릭 문법 case some(Wrapped) case none } var num:Int? = 10 Optional.some(10) Optional.none //.none과 nil은 완전히 동일 //일반적으로 nil 사용- 열거형에 연관값이 없고 옵셔널 열거형의 경우
옵셔널 자체가 열거형으로 선언되어 있고 옵셔널 열거형으로 선언하는 경우 열거형을 감싸는 열거형의 형태가 됨
// 열거형의 선언 enum SomeEnum { case left case right } // 타입을 다시 옵셔널 열거형으로 선언 let x: SomeEnum? = nil //[SomeEnum?의 의미] 옵셔널 열거형 //값이 있는 경우 .some -> 내부에 다시 열거형 .left /.right //값이 없는 경우 .none -> nil // 원칙 // Optional.some(let value) = Optional.some(SomeEnum.left) switch x { case .some(let value): switch value { case .left: print("왼쪽으로 돌기") case .right: print("오른쪽으로 돌기") } case .none: print("계속 전진") } //편의적 기능 //.some == 값이 있는 옵셔널 //.none == 값이 없는 옵셔널 switch x { case .some(.left): print("왼쪽으로 돌기") case .some(.right): print("오른쪽으로 돌기") case .none: print("계속 전진") } //위와 같은 코드지만 편의적 기능으로 더 간소화 //switch문에서 옵셔널 열거형 타입을 사용할때 옵셔널 벗기지 않아도 내부값 접근가능 switch x { case .left: print("왼쪽으로 돌기") case .right: print("오른쪽으로 돌기") case nil: print("계속 전진") }- 열거형에 연관값이 있는 경우
열거형 case 패턴: 케이스 내부에 구체적인 정보(연관값)가 들어있고 그 구체적인 정보를 꺼내서 활용하기 위해 변수에 바인딩해서 사용하는 패턴
enum Computer { case cpu(core: Int, ghz: Double) case ram(Int, String) case hardDisk(gb: Int) } var chip = Computer.cpu(core: 4, ghz: 3.1) //switch문 //모든 케이스를 다룰때는 switch문을 사용 switch chip { case .cpu(core: 8, ghz: 3.1): print("CPU 8코어 3.1GHz입니다.") case .cpu(core: 8, ghz: 2.6): print("CPU 8코어 2.6GHz입니다.") case .cpu(core: 4, ghz: let ghz): //let ghz = 연관값 (cpu가 4코어인 경우, ghz에 저장된 연관값을 꺼내서 바인딩) print("CPU 4코어 \\(ghz)HGz입니다.") case .cpu(core: _, ghz: _): print("CPU 칩 입니다.") case .ram(32, _): print("32기가램 입니다.") case .ram(_, _): print("램 입니다.") case let .hardDisk(gb: gB): //let gB = 연관값 print("\\(gB)기가 바이트 하드디스크 입니다.") default: //대부분 default문이 필요하기도 함 print("그 외에 나머지는 관심이 없습니다. 그렇지만 칩이긴 합니다.") } //조건문 / 반복문 //특정 케이스만 다룰 때는 조건문 반복문 사용 chip = Computer.hardDisk(gb: 128) //if문에서도 스위치문에서 사용하는 case문과 같이 사용 가능 if case Computer.hardDisk(gb: let gB) = chip { print("\\(gB)기가 바이트 하드디스크임") } //for문에서도 특정 케이스만 뽑아서 활용 가능 let chiplists: [Computer] = [ .cpu(core: 4, ghz: 3.0), .cpu(core: 8, ghz: 3.5), .ram(16, "SRAM"), .ram(32, "DRAM"), .cpu(core: 8, ghz: 3.5), .hardDisk(gb: 500) } //cpu만 골라서 보여주는 for문 for case let .cpu(core: c, ghz: h) in chiplists { print("CPU칩: \\(c)코어, \\(h)헤르츠")- 옵셔널 패턴
옵셔널 타입에서 열거형 케이스 패턴을 더 간소화한 옵셔널 패턴
//열거형 내부에 연관값을 사용시 let a: Int? = 1 // 1) 열거형 케이스 패턴 (앞에서 배운) switch a { case .some(let z): //상수명에는 아무거나 들어가도 됨 print(z) case .none: // nil이라고 써도됨 print("nil") } // 2) 옵셔널 패턴 (현재 배울) switch a { case let z?: // .some을 조금 더 간소화하는 문법 print(z) case nil: // .none 이라고 써도됨 print("nil") }💡 간단히 말하면 .some을 대신하여 ?를 이용하는 패턴 (열거형 case패턴을 간소화한 문법)
- @unknown 키워드
switch문에서 열거형의 모든 케이스를 다루지 않는 경우에 스위치문에서 모든 열거형의 케이스를 다루지 않았다고 컴파일 시점에 경고를 통해 알려줌
// 3가지 케이스에서 카카오톡 로그인의 케이스를 추가 enum LoginProvider: String { case email case facebook case google case kakaotalk } let userLogin = LoginProvider.email //아래와 같은 상황이 발생하면 아래처럼 노란 경고창으로 알려줌 //그럼 개발자는 저 경고를 보고 빼먹은 케이스를 추가해주면 됨 switch userLogin { //Switch must be exhaustive case .email: print("이메일 로그인") case .facebook: print("페이스북 로그인") case .google: print("구글 로그인") case .kakaotalk print("카카오톡 로그인") @unknown default: print("그 외의 모든 경우") }혹시 잘못된 내용이 있다면 피드백 주시면 정말 감사합니다! 😊
'🍏Swift' 카테고리의 다른 글
[Swift] ARC (0) 2023.02.26 [Swift] Optional (0) 2023.02.19 [Swift] Access Control (0) 2023.02.06 [Swift] map, filter, reduce 등 고차함수 (0) 2023.02.03 [Swift] 메서드의 종류 (0) 2022.10.13