[Swift] Enum

개자이너·2022년 2월 1일
0

내맘대로 Swift

목록 보기
2/6

Struct를 활용해서 채팅 메세지를 만든다고 가정해보겠습니다.
채팅메세지에는 아래와 같은 형식을 가지고 있습니다.

  1. 일반적인 텍스트 메세지
  2. 채팅 참가 메세지
  3. 채팅 탈퇴 메세지

위와 같은 메세지 형태를 Struct로 표현했을 경우와 Enum으로 표현했을 경우에는 어떤 차이점이 있는지 확인해보겠습니다.

1. Struct

struct Message {
    let userId: Int
    let contents: String?
    let data: Date
    
    let hasJoined: Bool
    let hasLeft: Bool
}

let joinMessage = Message(userId: 1, contents: nil, date: Date(), hasJoined: true, hasLeft: false)
let textMessage = Message(userId: 1, contents: "Hello World", date: Date(), hasJoined: false, hasLeft: false))
let leftMessage = Message(userId: 1, contents: nil, date: Date(), hasJoined: true, hasLeft: true))

Struct를 활용하면 잘못된 상태의 객체가 만들어질 수 있습니다.

let wrongMessage = Message(userId: 1, contents: "Hi", hasJoined: true, hasLeft: true)

이처럼 의도하지 않은 잘못된 상태의 객체가 만들어질 수 없도록 효율적인 방법이 없을까요?

2. Enum

  1. Enum은 '상호 배타적'인 관계를 표현할 수 있습니다.
  2. 연관 값(Tuple)을 이용하면, 데이터도 포함할 수 있습니다.
enum Message {
    case text(userId: Int, contents: String, date: Date)
    case join(userId: Int, date: Date)
    case leave(userId: Int, date: Date)
}

let joinMessage: Message = Message.join(userId: 1, contents: "hello", date: Date())

let textMessage = Message.text(userId: 1, contents: "hello", date: Date())

let leaveMessage: Message = .leave(userId: 1, date: Date())

enum을 활용한 switch-case문을 활용할 경우에는 default와 같이 모든 case에 대해서 처리하는 것 보다는, 모든 경우를 처리하는 형태로 만들어 놓는 것이 좋습니다.

func logMessage(message: Message) {
    switch message {
    	case .text(userId: let userId, contents: let contents, date: let date):
        break

        case .join(userId: let userId, date: let date):
        break

        case .leave(userId: let userId, date: let date):
        break
    }
}

default로 모든 경우를 처리할 경우에 enum에 새로운 값이 추가되었을 경우에 컴파일러가 오류 없이 처리하기 때문에, 개발자가 의도치 않은 작동을 막아주는 역할을 기대할 수 없기 때문입니다.

switch-case

Enum을 사용하다 보면 if-else보다는 switch-case를 자주 사용하게 됩니다. 때문에 다양한 표현 방법을 알고 있는 것이 큰 도움이 될 때가 있습니다.

switch message {
    case let .text(userId, contents, date):
    break
    
    case let .join(userId, date):
    break
    
    case let .leave(userId, date):
    break
}

단일 항목 처리

if case .text(userId: let userId, contents: let contents, date: let date) = textMessage {
    ...
}

if case .join(let userId, let contents) = joinMessage {
    ...
}

if case let .leave(userId, date) = leaveMessage {
    ...
}

Type Check

enum DataType {
    case date(Date)
    case string(String)
    case int(Int)
    case double(Double)
    
    // 새로운 항목이 추가되면, 컴파일러가 오류를 통해 처리해야 하는 부분을 알려줍니다.
    case intRange(Range<Int>)
    // 1...10: CloseRange
    // 0..<10: Range
    
    case dateRange(Range<Date>)
}

let startDate = Date()
let endDate = Date().addingTimeInterval(10)

let arr: [DataType] = [
    .date(Date()),
    .string("Hello"),
    .int(42),
    .double(3.14),
    .intRange(1 ..< 10),
    .dateRange(startDate ..< endDate)
]

for element in arr {
    switch element {
    case let .date(date):
	print(date)
    case let .string(string):
	print(string)
    case let .int(int):
    	print(int)
    case let .double(double):
    	print(double)
    case let .intRnage(range):
    	for e in range {
            print(e)
        }
    case let .dateRange(range):
        print(range)
    }
}
profile
개발과 디자인을 다 하려는 욕심 그득한 노예

0개의 댓글