궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
SWIFT/Grammar

Swift : 기초문법 [열거형 - Enum]

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

본 게시글은 yagom님의 Swift 프로그래밍 3판을 참고하여 작성되었습니다.

 

 

Enum

열거형은 연관된 항목들을 묶어서 표현할 수 있는 타입입니다. 열거형은 배열이나 딕셔너리 같은 타입과는 다르게 프로그래머가 정의해준 항목 값 외에는 추가/수정이 불가능합니다. 그렇기 때문에 딱 정해진 값만 열거형 값에 속할 수 있습니다.

 

즉, 일반적으로 Enum이라고 하는 열거형은 관련 값 그룹을 사용하기 쉽게 정의하는 방법이라고 할 수 있습니다.

 

열거형은 다음 같은 경우에 요긴하게 사용할 수 있습니다.

  • 제한된 선택지를 주고 싶을 때
  • 정해진 값 외에는 입력받고 싶지 않을 때
  • 예상된 입력 값이 한정되어 있을 때

열거형으로 묶을 수 있는 항목들은 주변에서 쉽게 찾아볼 수 있습니다.

  • 지역 : 강원도, 경기도, 전라도, 제주도, 충청도
  • 애플 : 아이폰, 아이패드, 맥북, 맥미니, 에어 팟
  • 삼성 : 갤럭시, 버즈, 삼성 노트북, 갤럭시탭
  • 학생 : 초등학생, 중학생, 고등학생, 대학생

자 이렇게 열거형을 통해 연관된 항목들의 그룹을 정의할 수 있다는 것을 알았죠? Swift의 열거형은 항목별로 값을 가질 수도, 가지지 않을 수도 있습니다. Swift의 열거형은 각 항목이 그 자체로 고유의 값이 될 수 있는 것이죠. 그렇기 때문에 실수로 버그가 일어날 가능성을 원천 봉쇄할 수 있습니다.

 

물론 열거형 각 항목이 원시 값(raw Value)이라는 형태로(정수, 실수, 문자, 타입 등) 실제 값을 가질 수도 있습니다. 또는 연관 값(Associated Values)을 사용하여 다른 언어에서 공용체라고 불리는 값의 묶음도 구현할 수 있습니다.

 

이 열거형은 Switch구문과 만났을 때 아주 아주 멋있게 활용할 수 있습니다. Switch구문을 조금 이따가 알아보도록 하죠!

TIP
 
 

열거형과 옵셔널
Swift의 주요 기능 중 하나인 옵셔널은 enum으로 구현되어 있습니다.

기본 열거형

Swift의 열거형은 enum이라는 키워드로 선언할 수 있습니다.

 

열거형에 대해 간단히 예를 들어보면, 어떠한 작업의 성공 또는 실패를 나타내는 코드를 작성하려는 경우, 이를 문자열로 나타낼 수 있습니다.

let result = "failure"

하지만  실수로 result가 아닌 다른 이름을 사용하면 쓸데없는 코드들이 많이 지고 오류가 생기기 쉽습니다.

let result2 = "failed" 
let result3 = "fail"

위 세 가지는 result는 모두 다른 문자열이므로 서로 다른 코드입니다. 그래서 Enum을 사용하여 수정되지 못하게 result값을 정해줄 수 있습니다.

enum Result {
    case success
    case failure
}

이제 Result를 사용할 때는 두 값(success, failure)중 하나를 선택해야 합니다.

let result4 = Result.failure

이렇게 하면 다른 문자열을 실수로 사용하는 것을 방지할 수 있습니다.

enum Apple {
    case iPhone
    case iPad
    case AirPods
    case Mac
    case TrackPad
    case MagicKeyBoard
}

Apple이라는 이름을 갖은 열거형에는 아이폰, 아이패드, 에어팟, 맥, 트랙패드, 매직키보드 라는 항목이 있고, 각 항목에는 그 자체가 고유의 값이며, 항목이 여러 가지라서 나열하기 어려우면 한 줄로 표현할 수 있습니다.

enum Apple {
    case iPhone, iPad, AirPods, Mac, TrackPad, MagicKeyBoard
}
enum Apple {
    case iPhone, iPad, AirPods, Mac, TrackPad, MagicKeyBoard
}

// 열거형 변수의 생성 및 값 변경
var MyAppleItems: Apple = .iPhone
var MyAppleItems2 = Apple.iPhone
var MyAppleitems3: Apple = Apple.iPhone

print(type(of: MyAppleItems2)) // Apple

// 같은 타입인 Apple 내부의 항목으로만 MyAppleItems의 값을 변경해줄 수 있다.
MyAppleItems = .AirPods
print(MyAppleItems) // AirPods

Enum을 사용하기 좋은 예시

1. 방향 (동쪽, 서쪽, 남쪽, 북쪽 등)

2. 오류 유형

3. 영화 장르

3. 요일(일주일에 7일만 있으므로)

Enum을 사용하기 안 좋은 예시

1. 내가 방문한 도시 목록 (이것은 배열로 작성하는 것이 좋습니다)

2. 이메일 주소(String으로 작성하는 것이 좋습니다)

3. 학생들의 평균 점수(Double로 작성하는것이 좋습니다)

Enum associated values ( 연관 값)

Enum의 가장 강력한 기능 중 하나는 하나 이상의 관련 값, 즉 Enum case를 더 자세히 설명해주는 추가 정보를 저장할 수 있는 기능입니다.

 

열거형 내의 항목(case)이 자신과 연관된 값을 가질 수 있는 것이죠. 연관 값은 각 항목 옆에 소괄호로 묶어 표현할 수 있습니다. 다른 항목이 연관 값을 같는다고 모든 항목이 연관 값을 가질 필요는 없습니다.

 

이렇게 하면 열거 형에 추가 정보를 첨부하여 더 세부적인 데이터를 나타낼 수 있습니다. 예를 들어 다양한 종류의 활동을 저장하는 열거 형을 정의할 수 있습니다.

enum Activity {
    case swimming 
    case running
    case talking
    case singing
}

만약 누군가가 말을 하고 있지만 그들이 무슨 말을 하는지 알지 못하거나, 누군가가 달리고 있다는 것을 알고 있지만 그들이 어디로 달려가고 있는지는 알지 못합니다. 이럴 때 열거 형 관련 값을 사용하여 세부 정보를 추가할 수 있습니다.

enum Activity {
    case swimming 
    case running(destination: String)
    case talking(topic: String)
    case singing(volume: Int)
}

누군가가 축구에 대해 이야기하고 있다면 아래와 같이 코드를 작성할 수 있습니다.

let talking = Activity.talking(topic: "football")

다음 Weather과 같은 세 가지 케이스가 있는 열거형을 만들 수 있습니다.

enum Weather {
    case sunny
    case windy(speed: Int)
    case rainy(chance: Int, amount: Int)
}

이 열거형은 날씨가 화창하거나 바람이 불거나 비가 올 수 있음을 의미합니다. 바람이 불 때 바람의 속도를 정수로 저장하도록 요청합니다. 시간당 10km이든 20, 30 등이든 상관없습니다. 이렇게 세부적으로 열거형에 정보를 추가하게 되면 아래와 같이 복잡한 코드를 작성하지 않아도 됩니다.

//올바르지 않은 예시
enum Weather {
    case sunny
    case lightBreeze
    case aBitWindy
    case quiteBlusteryNow
    case nowThatsAStrongWind
    case thisIsSeriousNow
    case itsAHurricane
}

예시

enum MainDish {
    case pasta(taste: String)
    case pizza(dough: String, topping: String)
    case chicken(sauce: Bool)
    case rice
}

var dinner: MainDish = MainDish.chicken(sauce: false)
dinner = .pasta(taste: "크림")
dinner = .pizza(dough: "씬", topping: "새우")
dinner = MainDish.rice

만약 식당 재료가 한정적이라 파스타의 맛과 피자의 도우, 토핑 등을 특정 메뉴로 한정 지으려면 아래와 같이 열거형으로 바꾸면 됩니다.

enum PastaTaste {
    case cream, tomato
}

enum PizzaDough {
    case cheeseCrust, thin, original
}

enum PizzaTopping {
    case pepperoni, cheese, bacon
}

enum MainDish {
    case pasta(pasta: PastaTaste)
    case pizza(dough: PizzaDough, topping: PizzaTopping)
    case chicken(sauce: Bool)
    case rice
}

var dinner: MainDish = MainDish.chicken(sauce: true)
dinner = MainDish.pizza(dough: .original, topping: .pepperoni)

어때요? 열거형 안에 열거형을 넣어서 좀더 쉽게 메뉴를 고를 수 있게 되었습니다.

예시

enum Building { 
     case skyscraper(floors: Int) 
}
enum Sport { 
     case running(distance: Int) 
}
enum Instruments { 
     case piano(isElectric: Bool) 
}

잘못된 예시

enum SocialMedia 
     case twitter(username: Int)

Enum raw values (원시 값)

때로는 값을 열거형에 할당하여 의미를 가질 수 있어야 합니다. 이렇게 하면 동적으로 생성하고 여러 가지 방법으로도 사용할 수 있습니다.

예를 들어 Planet에 각 case에 대한 정수 값(Int)을 저장하는 열거형을 만들 수 있습니다.

enum Planet: Int {
    case mercury
    case venus
    case earth
    case mars
}

Swift에서 위 코드의 earth는 2번째입니다. 0부터 숫자를 카운트하기 때문이죠. 만약 earth를 가져오고 싶다면 아래와 같이 작성합니다.

let earth = Planet(rawValue: 2)

하지만 원하는 경우 하나 이상의 case에 특정값을 할당하면 Swift가  자동으로 나머지를 생성합니다. 아래와 같이 mercury에 정수 값 '1'을 할당해준다면 위에서부터 아래로 자동으로 숫자를 넣어주게 됩니다. 그렇기 때문에 이제 earth는 세 번째 행성이 됩니다.

enum Planet: Int {
    case mercury = 1
    case venus
    case earth
    case mars
}

예시

enum AnimationCurve: Int {
    case easeInOut
    case easeIn
    case easeOut
    case linear
}

위의 코드를 아래처럼 한 줄로 정의할 수 있습니다.

enum AnimationCurve: Int {
    case easeInOut, easeIn, easeOut, linear
}

그리고 이것들은 Raw value 유형을 일치 키시는데 아주 좋습니다.

print(AnimationCurve.easeInOut.rawValue) // 0
print(AnimationCurve.easeIn.rawValue) // 1
print(AnimationCurve.easeOut.rawValue) // 2
print(AnimationCurve.linear.rawValue) // 3

원시 값이 있는 열거형

  1. case에 값을 제공할 수 있다.
  2. Int raw value는 자동으로 0부터 계산된다.
  3. raw value는 전적으로 선택 사항이기 때문에 필수적이지 않다.
  4. raw value에 정수와 같은 다른 것을 사용할 수 있다.
  5. raw value를 사용하면 열거형 값을 동적으로 만들 수 있다.

항목 순회

열거형에 포함된 모든 케이스를 알아야 할 때는 열거형의 이름 뒤에 콜론 ( : )을 작성하고 CaseIterable 프로토콜은 채택하면 됩니다. 그러면 열거형이 allCases라는 이름의 타입 프로퍼티를 통해 모든 케이스의 컬렉션을 생성해줍니다.

enum Apple: CaseIterable {
    case iPhone
    case iPad
    case AirPods
    case Mac
    case TrackPad
    case MagicKeyBoard
}

let allCases: [Apple] = Apple.allCases
print(allCases)

원시 값을 갖는 열거형이면 원시값 타입 다음에 쉼표( , )를 쓰고 CaseIterable을 채택해주면 됩니다.

enum Apple: String, CaseIterable {
    case iPhone
    case iPad
    case AirPods
    case Mac
    case TrackPad
    case MagicKeyBoard
}

let allCases: [Apple] = Apple.allCases
print(allCases)

비교 가능한 열거형

Comparable 프로토콜을 준수하는 연관 값만 갖거나 연관 값이 없는 열거형은 Comparable 프로토콜을 채택하게 되면 각 케이스를 비교할 수 있습니다. 

 

앞에 위치한 case 가 더 작은 값이 됩니다.

enum Condition: Comparable {
    case terrable
    case bad
    case good
    case great
}

var MyCondition: Condition = Condition.great
var yourConditon: Condition = Condition.bad


if MyCondition >= yourConditon {
    print("오늘응 내가 너의 상태보다 좋네..?")
} else {
    print("오늘은 네가 나의 상태보다 좋구나..!")
}


MyCondition = .bad
yourConditon = .good

if MyCondition >= yourConditon {
    print("오늘응 내가 너의 상태보다 좋네..?")
} else {
    print("오늘은 네가 나의 상태보다 좋구나..!")
}

어때요? 어떤 식으로 비교가 되는지 알 수 있겠죠? Conditon에서 terrable이 최상단이기 때문에 제일 작은 값이 된 것입니다.

enum Apple: Comparable {
case iPhone(series: String)
case iPad(series: String)
case AirPods
case Mac
}

var apple: [Apple] = []
apple.append(Apple.iPhone(series: "아이폰 11 pro"))
apple.append(Apple.iPhone(series: "아이폰 12 pro"))
apple.append(Apple.iPad(series: "아이패드 pro 5세대 12.9"))
apple.append(Apple.Mac)
apple.append(Apple.AirPods)


let MyDevices: [Apple] = apple.sorted()
print(MyDevices)
/*
 
[ Apple.iPhone(series: "아이폰 11 pro"), Apple.iPhone(series: "아이폰 12 pro"),
 Apple.iPad(series: "아이패드 pro 5세대 12.9"), Apple.AirPods, Apple.Mac ]

 */

마찬가지로 순서에 맞게 출력이 되는 것을 확인할 수 있습니다.

 

 

읽어주셔서 감사합니다🤟

 

 


잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.