챗봇을 개발하면서 예외, 오류 처리 등 이용자 경험에 필수적으로 포함되어야 하는 부분에 대해 구현하기 위해 일단 발생할 수 있는 상황을 정리해 에러 핸들링을 나열하고 이 핸들링을 통해 특정 상황에 맞는 Toast 메세지를 날려주는 로직을 구현하려고 한다!
먼저 최대한 기능별 모듈화를 통해 프로젝트를 쪼개 구현하고 있기 때문에 에러 핸들러 패키지를 만들어서 사용하는 방식을 사용해보자!
이 글에서는 대표적인 사례로 인터넷 연결이 끊겼을때 상황을 가정해 로직 구현을 해보려고 한다.
public enum NetworkError: Error {
case networkError(code: Int, underlying: Error?)
case noInternetConnection
case yesInternetConnection
case timeout
case invalidResponse
case unknown(underlying: Error?)
public var localizedDescription: String {
switch self {
case .networkError(let code, _):
return "네트워크 오류가 발생했습니다. 오류 코드: \\(code)"
case .noInternetConnection:
return "인터넷 연결이 없습니다."
case .yesInternetConnection:
return "인터넷 연결되었습니다."
case .timeout:
return "네트워크 요청 시간이 초과되었습니다."
case .invalidResponse:
return "잘못된 응답을 받았습니다."
case .unknown:
return "알 수 없는 네트워크 오류가 발생했습니다."
}
}
}
각 상황 별로 네트워크 연결 관련 상황을 바탕으로 enum을 통해 해당 내용을 리스트업한 다음 해당 내용을 가져가 토스트 메세지에 localizedDescription을 각 상황에 맞게 넣어줄 수 있도록 하려고 한다.
그 다음 토스트 메세지를 호출하는 로직을 프로토콜을 활용해 추상화 한다.
public protocol ToastNotifying {
@MainActor func showToast(message: String)
}
MainActor를 활용해 UI 업데이트와 관련 된 해당 로직이 안정적으로 메인 스레드에서 실행됨을 보장할 수 있도록 했다.
public func showToast(message: String) {
withAnimation(.spring(response: 0.3)) {
toastMessage = message
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) { [weak self] in
withAnimation(.easeOut(duration: 0.2)) {
self?.toastMessage = nil
}
}
}
그 다음 Toast메세지가 등장한 다음 2.5 초 뒤 사라질 수 있도록 해당 로직을 넣어주면 토스트 메세지에 대한 로직 구현이 쉽게 완료된다.
검색해보니 앱을 사용하면서 네트워크가 연결되어있는지 여부를 추적할 수 있는 방법은 NWPathMonitor를 활용해 연결 상태 변화를 감지하는 방법이 있는 것 같아 이 방법으로 한번 적용해보려고 한다.
공식문서를 확인해보니 NWPathMonitor 내 pathUpdateHandler를 활용하면 현재 단말기의 네트워크 상태 값을 전달 받을 수 있다고 한다!
이를 바탕으로 상태에 맞게 메세지를 전달해보자
private let monitor: NWPathMonitor
private let queue = DispatchQueue(label: "NetworkMonitorQueue")
@Published public var isConnected: Bool = true
private init() {
monitor = NWPathMonitor()
monitor.pathUpdateHandler = { [weak self] path in
let newStatus = (path.status == .satisfied)
Task { @MainActor [weak self] in
guard let self = self else { return }
if self.isConnected != newStatus {
self.isConnected = newStatus
if newStatus {
await ErrorHandler.shared.toastNotifier.showToast(message: NetworkError.yesInternetConnection.localizedDescription)
} else {
await ErrorHandler.shared.toastNotifier.showToast(message: NetworkError.noInternetConnection.localizedDescription)
}
}
}
}
}
public func startMonitoring() {
monitor.start(queue: queue)
}
public func stopMonitoring() {
monitor.cancel()
}
별도의 Queue를 활용해 네트워크 모니터링 업무를 수행하도록 맞춰주게 되면 현재 상태를 전달받으면서 각 상황에 맞는 메세지를 넣어주면 이렇게 각각 상황에 맞는 메세지를 넣을 수 있게 된다.
이 내용을 바탕으로 앱단으로 넘어가 앱 델리게이트 내
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Task { @MainActor in
NetworkMonitor.shared.startMonitoring()
}
return true
}
}
네트워크 모니터링을 시작할 수 있도록 전역으로 선언해주면 이제 앱에서 네트워크 상태를 감지하고 해당 값을 통해 토스트 메세지가 정상적으로 뜰 수 있게 된다. ( 원하는 뷰에 선언만 해주면 됨 )
토스트 메세지를 통해 해당 앱의 오류 상태를 이용자에게 전달할 수 있게 됐지만 일단 할 수 있도록만 구현해보았고 조금 더 효율적으로 구현할 수 있는 방법에 대해서 확인해보고 적용해 내용을 추가해야겠다!
'◽️ Programming > iOS' 카테고리의 다른 글
Static Dispatch, Dynamic Dispatch (2/2) (0) | 2025.03.04 |
---|---|
Static Dispatch & Dynamic Dispatch (1/2) (0) | 2025.02.28 |
Sendable에 대해서 알아보자 (0) | 2025.02.24 |
Swift Concurrency에서 Task는 어떤 역할을 담당하나 (0) | 2025.02.20 |
Objective-C를 Swift에 가져와 사용하기 (0) | 2025.02.12 |