ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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)
    }
    
    // 각 케이스별로 상이한 특징이 있고, 그것을 저장 / 활용할 필요가 있을 때
    // 개별케이스마다 저장할 형식을 따로 정의(자료형에 제한이 없음 / 튜플의 형태)
    // 하나의 케이스에 서로다른 연관값을 저장할 수 있음 ===> 선언시점이 아니라, 새로운 열거형 값을 생성할때 저장
    

     

    • 원시값과 연관값의 차이
    1. 자료형 선언 방식: 선언하는 위치가 다름
    2. 선언 형식: 원시값: 2가지중 1가지 선택 / 연관값: 튜플의 형태로 형식 제한 없음
    3. 값의 저장 시점: 원시값: 선언시점 / 연관값: 새로운 열거형 값을 생성할 때
    4. 서로 배타적: 하나의 열거형에서 원시값과 연관값을 함께 사용하는 것은 불가능함

     

    • 옵셔널 타입에 대한 정확한 이해

    옵셔널 타입의 내부는 열거형, 열거형의 연관값으로 값이 저장

    //옵셔널 타입의 내부 구현
    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
Designed by Tistory.