前提環境:
・Xcode:12.1
・Swift:5.3
私はコードレビュー等でしばしば以下のような実装を見かけるのですが、Swiftの良さを活かしていないなと感じます…
改善前
// APIレスポンスの値と仮定
let memberType = "1"
func foo() {
switch memberType {
case "0":
print("通常会員の処理を行う")
case "1":
print("プレミアム会員の処理を行う")
case "2":
print("お試し会員の処理を行う")
default:
break
}
}
foo() // "プレミアム会員の処理を行う"
以下が改善したコードです。
改善後
// APIレスポンスの値と仮定
let memberTypeRaw = "1"
enum MemberType: String {
case normal = "0"
case premium = "1"
case trial = "2"
}
func foo() {
guard let memberType = MemberType(rawValue: memberTypeRaw) else {
preconditionFailure("定義されていない値")
}
switch memberType {
case .normal:
print("通常会員の処理を行う")
case .premium:
print("プレミアム会員の処理を行う")
case .trial:
print("お試し会員の処理を行う")
}
}
foo() // "プレミアム会員の処理を行う"
改善後のコードには以下の利点があります。
- enumを定義することによって、APIレスポンスとして返却されうる値に対して型と名前が付与されることで、その仕様が読み取りやすくなる。
- guard節によって、MemberType型に変換した結果がnilである=仕様として想定外の値である、という実装意図が明確である。
- 将来
enum MemberType
にcaseが増えた際に、switch memberType
にてcaseを網羅していないとコンパイルエラーとして検出でき、改修漏れを防止できる。
一行でまとめると、
Swiftの「Null安全」、「型安全」、そして「コンパイラによるenumの全ケース網羅チェック」という特徴を活かしましょう、
というお話でした。