[Swift] 열거형의 연관 값을 이용한 활용성 및 재사용성 향상 방법

Ryan (Geonhee) Son·2021년 4월 20일
0

Study Stack

목록 보기
9/34

열거 타입에 연관 값을 이용하여 활용성과 재사용성을 향상시키는 사례를 살펴보겠습니다. 에러 타입을 정의하기 위해 열거 타입을 활용하는 경우, 아래와 같이 코드를 작성할 수 있습니다.

enum ExpoAppError: Error {
  case invalidJSONFileName
  case invalidJSONFormat
  case foundNil
  case numberFormattingFailed
  case unknownError
}

extension ExpoAppError: CustomDebugStringConvertible {
  var debugDescription: String {
    switch self {
    case .invalidJSONFileName:
      return "📃 존재하지 않는 JSON 파일이에요. 파일 이름을 다시 확인해주세요!"
    case .invalidJSONFormat:
      return "📑 JSON 형식이 맞지 않아요. 데이터를 다시 확인해주세요."
    case .foundNil:
      return "😵 이 값은 nil이에요!"
    case .numberFormattingFailed:
      return "😅 숫자 형식 변환에 실패했어요! 숫자를 다시 확인해주세요."
    case .unknownError:
      return "𝙛 알 수 없는 에러가 발생했어요!"
    }
  }
}

그럼 이런 에러는 아래와 같이 반환하거나 던질(throw) 수 있습니다.

static func decode<Decoded>(
  to type: Decoded.Type,
  from jsonFileName: String
) -> Result<Decoded, ExpoAppError> where Decoded: Decodable {
  var decodedResult: Decoded
  guard let jsonData: NSDataAsset = NSDataAsset(name: jsonFileName) else {
    return .failure(ExpoAppError.invalidJSONFileName) // 에러 반환
  }
  
  do {
    decodedResult = try jsonDecoder.decode(Decoded.self, from: jsonData.data)
  } catch {
    return .failure(ExpoAppError.invalidJSONFormat) // 에러 반환
  }
  
  return .success(decodedResult)
}

이 경우, 유사한 에러이지만 발생 위치가 다를 경우 이를 특정하기 위해 새로운 에러 케이스를 작성해야 합니다. 하지만 열거 타입의 연관 값(associated value)를 활용하면 에러와 관련된 값을 에러 메시지에 포함하여 나타낼 수 있으면서도 같은 케이스를 활용할 수 있게끔 할 수 있습니다. 적용은 아래와 같이 하면 됩니다.

enum ExpoAppError: Error, Equatable {
  case invalidJSONFileName(String) // 연관값의 타입을 소괄호 내부에 명시
  case invalidJSONFormat(String)
  case foundNil(String)
  case numberFormattingFailed(Int)
  case unknownError(String)
}

extension ExpoAppError: CustomDebugStringConvertible {
  var debugDescription: String {
    switch self {
    case .invalidJSONFileName(let fileName):
      return "📃 존재하지 않는 JSON 파일이에요. 파일 이름을 다시 확인해주세요! 파일 이름: \(fileName)" // 연관 값 활용
    case .invalidJSONFormat(let fileName):
      return "📑 JSON 형식이 맞지 않아요. 데이터를 다시 확인해주세요. 파일 이름: \(fileName)"
    case .foundNil(let valueName):
      return "😵 이 값은 nil이에요! 값 이름: \(valueName)"
    case .numberFormattingFailed(let number):
      return "😅 숫자 형식 변환에 실패했어요! 숫자를 다시 확인해주세요. 입력한 숫자: \(number)"
    case .unknownError(let location):
      return "𝙛 알 수 없는 에러가 발생했어요! 발생 위치: \(location)"
    }
  }
}

static func decode<Decoded>(
  to type: Decoded.Type,
  from jsonFileName: String
) -> Result<Decoded, ExpoAppError> where Decoded: Decodable {
  var decodedResult: Decoded
  guard let jsonData: NSDataAsset = NSDataAsset(name: jsonFileName) else {
    return .failure(ExpoAppError.invalidJSONFileName(jsonFileName)) // 입력한 파일 이름과 함께 반환
  }
  
  do {
    decodedResult = try jsonDecoder.decode(Decoded.self, from: jsonData.data)
  } catch {
    return .failure(ExpoAppError.invalidJSONFormat(jsonFileName))
  }
  
  return .success(decodedResult)
}

멋지지 않나요? associated value를 활용해서 열거 타입을 더 유용하게 활용해봅시다!

profile
합리적인 해법 찾기를 좋아합니다.

0개의 댓글