티스토리 뷰


열거형

(Enumerations)




1) 이론적 정의

 


1. 하나의 주제로 연관된 데이터들이 멤버로 구성되어 있는 자료형 객체       (정의 참고 : 꼼꼼한 재은씨의 Swift - 문법편)


2. 연관된 값의 그룹(타입)에 대해 공통 타입을 정의한 뒤, 타입을 안전하게 함으로서 해당 값들을 사용 가능





2) 문법적 정의



enum name {

    definition

}



 * Reference. 열거형 값 네이밍 방법.


  * PascalCase 사용 = 첫글자를 문자로

  * 각 case는 camelCase 사용 = 글자를 문자로




3) Examples




* Example 1-1. 기본 정의 방법 + 네이밍 방법 적용


enum SomeEnumeration {

    // case definition

}




* Example 1-2. case 네이밍 방법 적용


enum Starcraft {

    case protoss

    case zerg

    case terran

    case random

}


* 한 줄에 모두 표현해줄 수도 있다 !! 그러나 이렇게 사용할 경우에는 가독성을 고려하자 ! 



  enum Starcraft {

     case protoss, zerg, terran, random

  }




* 열거형을 변수로 선언하고 값을 할당하는 방법들.


var choiceYourStart1 = Starcraft.protoss

choiceYourStart1 = .terran                                         <-- Starcraft. 은 왜 생략되었을까? 앞에서 Starcraft. 이 들어간 것을 컴파일러가 기억하고 생략할 수 있게 해줌!!


var choiceYourStart2: Starcraft = .terran

 * 열거형에서는 모든 case의 그룹이 되는 열거형의 name을 타입으로 선언할 수 있다. 

   그래서 위와 마찬가지로 앞에서 타입이 선언되었기 때문에 .terran 의 앞을 생략할 수 있다.






* Example 2. 열거형 값 매칭하기(Matching Enumeration Values)



 Switch 문을 이용해서 열거형 내 일치하는 Case를 찾을 수 있다.


var choiceYourStart = Starcraft.zerg


switch choiceYourStart {

case .protoss:

    print("Powerful")

case .terran:

    print("Sociable")

case .zerg:

    print("Much")                                             <-- 일치하는 case

case .random:

    print("Good luck")

}


var nameSCVOfTerran = Starcraft.terran


switch nameSCVOfTerran {

case .terran:

    print("SCV")                                             <-- 일치하는 case

default:

    print("not SCV")


* 위에서 선언했던 열거형 enum Starcraft의 모든 case가 선언되면 default 값을 생략할 수 있으나, 

  그렇지 않은 경우에는 default 값을 선언해야 한다. 원하는 케이스만 찾고 나머지는 필요 없을 때 위의 스위치문처럼 활용.






* Example 3. 연관 값(Associated  Values)



사용하는 시점에서 멤버에 보조 값을 설정할 수 있는 방법도 있다. 이렇게 설정된 값을 연관 값(Associated Values)이라 한다. 아래는 예시이다.

( 정의 참고 : 꼼꼼한 재은씨의 Swift - 문법편 )


enum Barcode {

    case upc(IntIntIntInt)

    case qrCode(String)

}


var productBarcode = Barcode.upc(8457)                      <-- 변수 productBarcode 생성하고 Barcode의 upc 케이스 값을 사용하는 시점에 할당

productBarcode = .qrCode("ABC")                                       <-- .qrCode(String)의  String 에 문자열 ABC 를 사용하는 시점에 값을 설정했다.

type(of: productBarcode)                                                      <--  Q.qrCode("ABC")의 타입은 뭐지??     A연관된 값의 '그룹(Barcode)'이 타입이 된다.


print(productBarcode




 그렇다면, 변수가 아니라 let 을 사용하는 Case 라면?


 열거형을 이용해 바로 상수에 할당하는 방법.



* Ref. var productBarcode = .qrCode("ABC") 상태.


switch productBarcode {

case .upc(let numberSystem, let manufacturer, let product, let check): // 각 Int 값을 let + 이름으로 정의

    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)."// QQQQQQQQQQ 그냥 원래 값으로는 안되나? 왜 이렇게 쓰지? QQQQQQQQQQ

case .qrCode(let productCode): // 일치하는 case

    print("QR code: \(productCode).")

}


productBarcode                  <--  qrCode("ABC")의 값을 갖는다.



 각각 let을 써주기가 번거로울 때는 앞에 써주면 된다 !


switch productBarcode {

case let .upc(numberSystem, manufacturer, product, check):

    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")

case let .qrCode(productCode):

    print("QR code: \(productCode).")

}





* Example 4-1. 원시 값(Raw Value)



  - 할당 가능한 타입 : Strings, Characters, or any of the Integer or Floating-point number types

  - raw value 는 해당 Enumeration 내에서 반드시 고유한 값이어야 한다. 예시를 보면서 이해해 보자.



// Example 1.


앞에서 배웠던 열거형을 활용하는 방법이다. 


enum ASCIIControlCharacter {

    case tab

    case lineFeed

    case carriageReturn

}


ASCIIControlCharacter.tab

ASCIIControlCharacter.lineFeed

ASCIIControlCharacter.carriageReturn



// Example 2.


 방금과는 다르게, 열거형의 이름 옆에 타입을 선언하는 차이가 생겼고, 각 case에도 Character 타입에 맞게 값이 들어가 있다.


enum ASCIIControlCharacter1: Character {

    case tab = "\t"

    case lineFeed = "\n"

    case carriageReturn = "\r"          \n 은 행바꿈, \t 는 '탭'을 의미한다.

}


ASCIIControlCharacter1.tab

ASCIIControlCharacter1.tab.rawValue            <-- 결과 :  "    ( 위에서 언급했듯, \t는 탭을 의미한다. lineFeed.rawValue는 줄 바꿈이 되겠죠? )

ASCIIControlCharacter1.lineFeed

ASCIIControlCharacter1.lineFeed.rawValue


 아래의 결과를 확인해보자.


입력)

print("111\n행바꿈\t탭")


결과)

111

행바꿈




 // Example 3.


 rawValue를 지정해주지 않은 상태에서는 Int 타입의 열거형의 경우 자동으로 0부터 1씩 증가하는  값이 할당된다.


enum Weekday: Int {

    case sunday, monday, tuesday, wednesday, thursday, friday, saturday

}


Weekday.wednesday

Weekday.wednesday.rawValue          <--  'wednesday'의 경우 4번째 case 이니까 0,1,2,3 그러니까 3이 rawValue가 되겠다.


String의 경우에는 어떠할까?


enum WeekdayName: String {

    case sunday, monday = "Mon", tuesday, wednesday, thursday, friday, saturday            1) 아까와는 다르게 monday에만 값을 지정했다.

}


WeekdayName.monday                                    2) 여기는 case 에 해당하는 monday 가 출력되고

WeekdayName.monday.rawValue                    3) 여기는 monday 에 지정한 rawValue 값인 Mon 이 출력된다!



Q. 그럼 sunday의 rawValue 값은 무엇인가요? 


A. 아래를 봅시다!





* Example 4-2. 암시적으로 할당된 원시 값(Implicitly Assigned Raw Value)



 제목만 보면 이해가 잘 안될 수 있다. 예시를 보면서 익혀보자.


enum WeekdayAgain: Int {


    case sunday, monday = 100, tuesday = 101, wednesday, thursday, friday, saturday


     1) monday, tuesday에만 값이 할당된 상태이다. 그럼 궁금해질 수 있다. sunday에는 99가 아닐까?

     2) 충분히 가능한 추론이지만 첫번째 case는 0부터 시작한다는 것을 잊지 말자.

     3) wednesday는 그럼 1이 증가하는 102인가요??? 

     4) 그렇다. wednesday는 102이 할당된다.

}


5) 그렇다면, 아래의 결과를 추론해보고 Xcode 에서 결과를 확인해보자 !


WeekdayAgain.sunday

WeekdayAgain.sunday.rawValue


WeekdayAgain.wednesday

WeekdayAgain.wednesday.rawValue



 이번엔 Int 가 아닌 String의 예시다.


enum WeekdayNameAgain: String {

    case sunday, monday = "mon", tuesday = "tue", wednesday, thursday, friday, saturday


    1) String 의 경우에는 지정되지 않은 각 case 들은 case 의 이름 자체가 rawValue가 된다. 

    2) monday의 경우 mon 이 되겠지만, sunday의 경우 rawValue는 sunday가 된다... 쉽죠???

}


3) 아래의 결과를 추론해보고 Xcode 에서 결과를 확인해보자 !


WeekdayNameAgain.sunday

WeekdayNameAgain.sunday.rawValue


WeekdayNameAgain.wednesday

WeekdayNameAgain.wednesday.rawValue





* Example 4-3. 원시 값으로부터의 초기화(Initializing from a Raw Value)



 원시 값을 이용해 초기화하는 것이 가능하다. 



// Example 1.


enum PlanetIntRaw: Int {

    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune 


    Q. 음.. 궁금한게 생겼어요. mercury가 1이면 그 다음부터 1씩 증가할텐데, 그렇게 되면 earth가 3이 되잖아요. 근데 earth에 값을 안주고 mars에 값을 3 주면

         어떻게 되나요???

    Amars에 3을 넣으면 반드시 고유한 값이어야 한다는 규칙에 어긋나서 'Raw Value for enum case is not uninque' 에러가 난다.


}


// 두 가지 받는 방법

PlanetIntRaw(rawValue: 2)        <-- 원시 값을 이용한 초기화

PlanetIntRaw.venus                  <-- case의 이름을 이용한 초기화 



// Example 2.


let possiblePlanet = PlanetIntRaw(rawValue: 7)   <-- (= uranus)

let positionToFind = 11


if let somePlanet = PlanetIntRaw(rawValue: positionToFind) { // positionToFind 에 무엇이 들어가느냐에 따라서 달라짐.

    switch somePlanet {

    case .earth:

        print("Mostly harmless")

    default:

        print("Not a safe place for humans")

    }


else {

    print("There isn't a planet at position \(positionToFind)")          <-- enum PlanetIntRaw 에는 원시 값이 11이 되는 case는 가지고 있지 않다. 그래서 바로 여기로.

}





* Example 5. 열거형과 메소드


열거형은 클래스 혹은 구조체처럼 내부에 메소드를 정의할 수 있다. 



enum Device: String {

    case iPhone, iPad, tv, watch

    

    func printType() {

        switch self {

        case .iPad, .iPhone, .tv:

            print("device :"self)

        case .watch:

            print("apple Watch")

        }

    }



 1) 열거형 내에 선언된 메소드를 사용해보자..


 2) 값을 할당할 변수를 선언한다.

 var myDevice: Device = .iPhone

 

 3) myDevice에 지금 .iPhone 이라는 값이 담겼는데, 여기서 메소드에 넣어보자.

 myDevice.printType()


 4) Switch 문을 거쳐서, .iPhone에 해당하는 부분이 출력된다. 

 device : iPhone



* Example 6. 열거형의 중첩



 열거형도 중첩하여 사용이 가능하다.


enum Wearable {


    enum Weight : Int {

        case light = 1

        case heavy = 2

    }


    enum Armor: Int {

        case lignt = 2

        case heavy = 4

    }


    case helmet(weight : Weight, armor : Armor)

    

    func attributes() -> (weight: Int, armor: Int) {

        switch self {

        case .helmet(let w, let a):

            return (weight: w.rawValue * 2, armor: a.rawValue * 4)

        }

    }

}


let woodenHelmet = Wearable.helmet(weight: .light, armor: .heavy)                <-- .light = 1 이고 .heavy = 4

woodenHelmet.attributes()            <-- 값이 .helmet 일 경우, weight 의 원시 값을 2만큼 곱해주고 armor의 원시 값을 4만큼 곱해주는  Switch문을 사용하는 메소드.






지금까지 열거형에 대해서 알아보았습니다. 틀린 부분이 있으면 댓글로 지적해주시면 감사드리겠습니다.


Made by Inswag's Swift in FastCampus 7th iOS Development School






댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함