Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 파사드패턴
- 어댑터패턴
- 옵저버패턴
- 싱글턴패턴
- 상태패턴
- 디자인패턴
- unowned
- DispatchQueue
- SWIFT
- Xcode
- 스트래터지패턴
- 프록시패턴
- 데코레이터패턴
- cocoapods
- 템플릿메서드
- 스테이트패턴
- ViewController
- 커맨드패턴
- Scenedelegate
- 팩토리메서드패턴
- 추상팩토리패턴
- Mobile
- Lifecycle
- WKWebView
- RxSwift
- 컴파운드패턴
- ios
- 전략패턴
- 컴포지트패턴
- 이터레이터패턴
Archives
- Today
- Total
ios dev kangwook.
Swift) Enumeration 본문
Enum이란
컴퓨터 프로그래밍에서 열거형은 요소, 멤버라 불리는 명멷뇌 값의 집합을 위루는 자료형.
열거자 이름들은 일반적으로 해당 언어의 상수 역할을 하는 식별자.
쉽게 말하면 상수 역할의 값들을 보기 쉽게 나열해 놓은 것
Raw Values(원시 값)
enum의 case는 모두 독립적인 값이지만 내부에 또 다른 값을 저장할 수 있음 → raw value
enum Name : RawValueType {
case caseName = value
}
- 원시 값 타입으로 올 수 있는 것은 String, Character, Number Type
- 선언 지점에 저장한 원시 값은 나중에 바꿀 수 없음
- 원시 값을 저장하는 부분은 생략도 가능, 각각의 자료형마다 규칙이 존재
enum CompassPoint: Int {
case north
case south
case east
case west
}
CompassPoint.north.rawValue // 0
CompassPoint.south.rawValue // 1
CompassPoint.east.rawValue // 2
CompassPoint.west.rawValue // 3
- 또한 원시값을 통한 case매칭으로 enum을 생성할 수 있음
CompassPoint(rawValue: 0) // north
// 동일한 rawValue를 가진 north가 생성
CompassPoint(rawValue: 200) // nil
// 없는 경우에는 nil을 리턴
String Type
enum Weekday: String {
case sunday
case monday
case tuesday
case wednesday
case thursday
case friday
case saturday
}
Weekday.sunday.rawValue // "sunday"
- String으로 선언할 경우 원시 값 할당을 생략하면 case이름과 동일한 문자열이 원시값으로 저장
- 직접 할당할 수도 있음
Character Type
enum ASCII: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
- Character 같은 경우 원시 값을 직접 할당해주지 않으면 컴파일 에러 발생
Associated Values(연관 값)
원시값의 한계
- 모든 케이스가 동일한 형식을 사용해야 함
- 케이스당 값을 하나밖에 저장할 수 없음
- 원시값 문자열에 숫자가 포함되어 있을 경우 숫자만 사용하려면 따로 추출해야하는 번거로움이 있음
enum Name {
case caseName(Type)
case caseName(Type, Type, ...)
}
- 원시 값의 경우 열거형 이름 뒤에 선언하지만, 연관 값은 케이스 이름 뒤에 선언
- 튜플을 사용하여 하나의 케이스에 서로 다른 연관 값들을 저장할 수 있음
enum AppleDevice: String {
case iPhone = "X, 256GB"
case iMac = "27, Pro, 300만원"
case macBook = "Air, 1kg, 150만원"
}
enum AppleDevice {
case iPhone(model: String, storage: Int) // named tuple
case iMac(size: Int, model: String, price: Int)
case macBook(String, Int, Int) // unnamed tuple
}
var gift = AppleDevice.iPhone(model: "X", storage: 256)
switch gift {
case .iPhone(model: "X", storage: 256):
print("iPhone X and 256GB")
case .iPhone(model: "X", _):
// 와일드 카드 패턴
print("iPhone X")
case .iPhone:
// 연관 값 생략 가능
print("iPhone")
case .iPhone(let model, let storage):
// 블록 내부에서 연관값을 사용할 땐 상수로 바인딩
// 값을 변경할 때는 var 로 변경 가능
print("iPhone \(model) and \(storage)GB")
case let .iMac(size, model, price):
// 모든 연관 값을 동일한 형태로 바인딩한다면
// let 키워드를 열거형 케이스 앞에 표기하는 것도 가능
print("iMac \(size), \(model), \(price)")
}
// 새로운 케이스를 할당할 경우 모두 새로운 값으로 교체
gift = .macBook("Air", 1, 150)
if case let .macBook(model, weight, price) = gift {
print("macBook \(model), \(weight)kg, \(price)")
}
Enum with Protocol
protocol MenuProtocol {
var menuName: String { get }
mutating func nextMenu() -> Self
}
- 프로퍼티는 enum에서 연산 프로퍼티만 사용할 수 있기 때문에 { get } 만 존재
enum FastFoodMenu: MenuProtocol {
case chicken
case pizza
case hamburger
var menuName: String {
switch self {
case .chicken:
return "치킨"
case .pizza:
return "피자"
case .hamburger:
return "햄버거"
}
}
func nextMenu() -> FastFoodMenu {
switch self {
case .chicken:
return .pizza
case .pizza:
return .hamburger
case .hamburger
return .chicken
}
}
}
enum NoodleMenu: MenuProtocol {
case ramen
case pasta
case udon
var menuName: String {
switch self {
case .ramen:
return "라멘"
case .pasta:
return "파스타"
case .udon:
return "우동"
}
}
func nextMenu() -> NoodleMenu {
switch self {
case .ramen:
return .pasta
case .pasta:
return .udon
case .udon
return .ramen
}
}
}
enum BeverageMenu: MenuProtocol {
case coke
case sprite
case water
var menuName: String {
switch self {
case .coke:
return "콜라"
case .sprite:
return "사이다"
case .water:
return "물"
}
}
func nextMenu() -> BeverageMenu {
switch self {
case .coke:
return .sprite
case .sprite:
return .water
case .water:
return .coke
}
}
}
var vendingMachine = BeverageMenu.coke
print(vendingMachine.menuName) // "콜라"
vendingMachine = vendingMachine.nextMenu()
print(vendingMachine.menuName) // "사이다"
vendingMachine = vendingMachine.nextMenu()
print(vendingMachine.menuName) // "물"
extension을 사용해서 케이스와 메서드, 프로퍼티를 분리하여 가독성을 높일 수 있음
enum FastFoodMenu: MenuProtocol {
case chicken
case pizza
case hamburger
}
extension FastFoodMenu: MenuProtocol {
var menuName: String {
switch self {
case .chicken:
return "치킨"
case .pizza:
return "피자"
case .hamburger:
return "햄버거"
}
}
func nextMenu() -> FastFoodMenu {
switch self {
case .chicken:
return .pizza
case .pizza:
return .hamburger
case .hamburger
return .chicken
}
}
}
Protocol자체를 extension과 함께 사용함으로써 가독성을 더욱 높일 수 있음
protocol MenuProtocol {
var menuName: String { get }
func nextMenu() -> Self
}
extension MenuProtocol {
var menuName: String {
return String(describing: self)
}
}
Generic Enumeration(제네릭 열거형)
제네릭으로 구현한 열거형의 대표적인 예는 Optional
Apple Documentation : Optional
Apple Developer Documentation
developer.apple.com
enum Optional<Wrapped> {
case none // 값이 없을 경우
case some(Wrapped) // 값이 있을 경우
}
let someValue = Optional<String>.some("some")
let nilValue = Optional<String>.none
print(someValue) // Optional("some")
print(nilValue) // nil
Recursive / Indirect Enumeration(재귀적/간접적 열거형)
재귀 / 간접 타입을 사용하면 열거형의 각 항목의 연관 값으로 열거형 타입을 지정 가능
자기 자신을 참조하는 열거형은 무한한 크기를 가질 수 있기 때문에 해당 타입이 재귀 / 간접 타입이라는 것을 명시해주어야 함
indirect enum LinkedListItem<T> {
case end(value: T)
case node(value: T, next: LinkedListItem)
}
enum LinkedListItem<T> {
case end(value: T)
indirect case node(value: T, next: LinkedListItem)
}
let cNode = LinkedListItem.end(value: "c")
let bNode = LinkedListItem.node(value: "b", next: cNode)
let aNode = LinkedListItem.node(value: "a", next: aNode)
var current = aNode
linkedListLoop: while true {
switch current {
case let .end(value):
print(value)
break linkedListLoop
case let .node(value, next):
print(value)
current = next
}
}
/**
a
b
c
**/
Custom Constructor(커스텀 생성자)
API를 통해 String, Int값을 받아온 후 열거형으로 변환하여 사용하려고 할 때 사용
구조체나 클래스의 생성자를 만드는 방법과 동일 → init
enum ErrorCode {
case Code400
case Code404
case Code500
case CodeNil
init(errorCode: Int) {
switch errorCode {
case 400:
self = .Code400
case 404:
self = .Code404
case 500:
self = .Code500
default:
self = .CodeNil
}
}
var errorMessage: String {
switch self {
case .Code400:
return "서버 요청 실패"
case .Code404:
return "페이지가 존재하지 않음"
case .Code500:
return "서버 응답 없음"
case .CodeNil:
return "알 수 없는 에러"
}
}
}
let errorCode = ErrorCode.init(errorCode: 404)
print(errorCode.errorMessage)
/** 페이지가 존재하지 않음 **/
let errorCode2 = ErrorCode.init(errorCode: 700)
print(errorCode2.errorMessage)
/** 알 수 없는 에러 **/
- 참조되어 있는 블로그들과 애플 공식 문서를 통해 공부했습니다.
참조
'Swift' 카테고리의 다른 글
nil, Nil, NSNull, Null에 대한 고찰 (0) | 2024.01.05 |
---|---|
Swift) KVC(Key-Value Coding) (0) | 2022.10.11 |
Swift) Initialization (0) | 2022.10.02 |
Swift) Property (0) | 2022.09.25 |
Swift) Semaphore (0) | 2022.09.25 |
Comments