[Swift] - case let
case let
https://stevenpcurtis.medium.com/ive-finally-mastered-case-let-in-my-swift-code-7b1737cf52c3
JSON 문자열을 다운받아서 결과를 화면에 출력하는 코드가 있다고 해보자. 이 때 사용하는 completionHandler에는 JSON 데이터를 올바르게 잘 받은 경우에 ((Users) -> Void)?
클로저를 리턴한다.
Result 타입을 리턴하는 것은 복잡도를 증가시킨다. 백엔드나 그 외에서 리턴된 에러에 대해서도 생각해봐야 한다. 이런 에러를 핸들링 하기 위해 viewModel을 사용할 수 있다. ViewModel
이 아래의 클로저를 리턴해서 사용하게 할 수 있다.
var closure: ((Result<Users, Error>) -> Void)?
구현은 아래와 같이 될 것이다.
viewModel.closure = { result in
switch result {
case let .success(users):
print(users.data.map{ "\($0.firstName)"}.joined(separator:"\n"))
case .failure(_):
break
}
}
위 코드에서 문제는 무엇이냐면 fail일 때의 case를 핸들링하고 있지만, 여기서 아무 작업도 하고 있지 않기 때문에 break를 작성한 것인데, 별로 이 코드에 도움이 되지 않는다. 이는 아래와 같이 개선될 수 있다.
viewModel.closure = { result in
if case let .success(users) = result {
print(users.data.map{ "\($0.firstName)"}.joined(separator:"\n"))
}
}
정리하자면, Result
타입으로 내려오는 결과를 switch
문으로 success / failure로 case를 나눠 구분 했지만 failure case의 코드가 의미가 없어 이를 if case let
문으로 바꾼 것 같다. 그런데 case let
문 자체에 대한 설명이 아니어서 아래에는 이에 대한 내용을 정리했다.
case let
Swift에서 case는 switch
뿐만 아니라 if
, guard
, for
, while
문과 함께 조건절을 완성하는 구문으로 활용도가 높다.
위에서 봤던 코드를 다시 보자.
if case let x = y {
...
}
위와 같은 형식을 띄고 있는데, 이 구문은 아래와 같은 코드이다.
switch y {
case let x: ...
default: ()
}
그래서 switch
문을 굉장히 단순화 시킬 수 있던 것이다. 예제를 좀 더 보자.
enum Media {
case book(title: String, author: String)
case movie(title: String, director: String)
case website(url: String)
}
let m = Media.movie(title: "movie", director: "director")
switch m {
case let Media.movie(title: title, director: _):
print("movie with \(title)")
default: ()
}
// same
if case let Media.movie(title: title, director: _) = m {
print("movie with \(title)")
}
또한 여기에 추가적인 조건을 붙일 수 있다.
if case let Media.movie(title: title, director: _) = m, title != "title" {
print("movie with \(title)")
}
if
문 뿐만 아니라 guard
문도 사용할 수 있다.
enum NWResponse {
case response(String, Int)
case error(Error)
}
func processNWResponse(_ response: NWResponse) {
guard case let .response(string1, codeNum) = response, let resp = string1 as String?, 200..<300 ~= codeNum else {
return
}
print(resp)
}
이런 식으로 guard case let
문을 사용해서 굉장히 복잡해 보이는 조건도 처리하기 쉽게 만들 수 있다.
Optional pattern
Swift에서 바인딩을 할 때는 옵셔널 값을 바인딩 하는 지를 잘 살펴봐야 한다. if case let
문에서도 바인딩하는 값이 옵셔널일 경우도 주의해야 하는데, 옵셔널 값을 받는 것을 옵셔널 패턴이라고 한다.
let optional: Int? = 12
// optional enum의 .some case에 매칭
if case .some(let x) = optional {
print(x)
}
// ?를 사용해서 optional unwrapping(optional pattern)
if case let x? = optional {
print(x)
}
if case let .some(x) = optional {
print(x)
}
참고로 위의 세 print문에서는 모두 12란 값이 출력된다.
- 참고
- https://townpharm.tistory.com/12