에러 발생시 ⏰Alert 띄우는 뷰 익스텐션 만들기

sanghee·2021년 8월 23일
0

🚩iOS

목록 보기
11/18
post-thumbnail

목표

뷰모델에서 데이터를 작업하는 과정에서 에러가 발생할 수 있다. 그럴 경우, 뷰에 Alert를 띄워서 사용자에게 에러가 발생했다는 것을 알리려고 한다. 에러가 발생할 수 있는 모든 뷰에 해당 기능을 넣을 것이다. 재사용할 수 있도록 ViewModifier로 만들고 extension에 추가하려고 한다.

extension

익스텐션은 구조체, 클래스, 열거형, 트로토콜 타입에 새로운 기능을 추가할 수 있다. 연산 프로퍼티, 메서드 등을 추가할 수 있다.

*protocol: 프로토콜은 특정 역할을 수행하기 위한 메서드, 프로퍼티, 기타 요구사항 등의 청사진을 정의한다.

modifier(_:)

Apple Developer Documentation - modifier

Applies a modifier to a view and returns a new view.

뷰에 modifier를 적용하고 새로운 뷰를 반환한다.

ViewModifier

Apple Developer Documentation - ViewModifier

A modifier that you apply to a view or another view modifier, producing a different version of the original value.

뷰나 또다른 뷰 modifier에 적용해서 기본 값과 다른 버전을 만든다. 재사용할 modifier를 만들어 뷰에 적용할 수 있다.

커스텀 캡션 예시

struct BorderedCaption: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.caption2)
            .padding(10)
            .overlay(
                RoundedRectangle(cornerRadius: 15)
                    .stroke(lineWidth: 1)
            )
            .foregroundColor(Color.blue)
    }
}

뷰에 바로 적용할 수도 있지만, 기본적으로 modifier(_ :)를 사용해 뷰에 대한 익스텐션을 정의한다.

extension View {
    func borderedCaption() -> some View {
        modifier(BorderedCaption())
    }
}

아래와 비슷하게 캡션을 적용할 수 있다.

Image(systemName: "bus")
    .resizable()
    .frame(width:50, height:50)
Text("Downtown Bus")
    .borderedCaption()

ViewModifier 만들기

재사용할 ErrorAlertModifier를 만들었다. 그리고 isPresented와 message 텍스트를 받는다. 에러 메세지를 확인하는 용도로 버튼은 .cancel 스타일로 하나를 넣었다. isPresented는 Binding타입이어야 함에 주의하자.

struct ErrorAlertModifier: ViewModifier {
    var isPresented: Binding<Bool>
    let message: String

    func body(content: Content) -> some View {
        content.alert(isPresented: isPresented) {
            Alert(title: Text("Error"),
                  message: Text(message),
                  dismissButton: .cancel(Text("OK")))
        }
    }
}

뷰에 익스텐션 추가하기

뷰에 showErrorMessage 메서드를 추가한다. 이 함수는 showAlert과 message를 받아 자신에 ErrorAlertModifier를 추가한다.

extension View {
    func showErrorMessage(showAlert: Binding<Bool>, message: String) -> some View {
        self.modifier(ErrorAlertModifier(isPresented: showAlert, message: message))
    }
}

뷰모델

뷰모델에서 Alert를 띄울지에 대한 showErrorAlert와 에러메세지를 저장하는 errorMessage 변수들을 만든다. 에러가 발생했는지(값이 변경되었는지) 감시해야 하므로 @Published를 추가한다.

@Published var showErrorAlert = false
@Published var errorMessage = ""

그리고 에러가 발생한다면 error의 메세지를 errorMessage에 저장한다. 뷰모델 내에서 파이어베이스에서 현재 유저를 fetch하는 함수 코드 예시이다. error가 발생시에 showErrorAlert를 true로 저장하고 에러 메세지도 저장하였다.

func fetchUser() {
    guard let uid = userSession?.uid else { return }
    
    COLLECTION_USERS.document(uid).getDocument { snapshot, error in
        if let (errorMessage) = error?.localizedDescription {
				    self.showErrorAlert = true
            self.errorMessage = errorMessage
            return
        }
        
        guard let user = try? snapshot?.data(as: User.self) else { return }
        self.currentUser = user
    }
}

뷰에서 익스텐션 사용하기

뷰에서 showErrorMessage 익스텐션을 사용한다. showErrorMessage에 이전에 저장한 showErrorAlert와 errorMessage를 넣는다.

struct LoginView: View {
    @EnvironmentObject var viewModel: AuthViewModel

    var body: some View {
        NavigationView {
            ...
        }
        .showErrorMessage(showAlert: $viewModel.showErrorAlert, message: viewModel.errorMessage)
    }
}

시뮬레이터에서 확인

에러가 발생하면 해당 에러 메세지를 띄우는 것을 확인할 수 있다.

깃허브 커밋 주소

GitHub - Commit

profile
👩‍💻

0개의 댓글