⎮ 네트워크 예외처리는 왜 하는걸까?
지하철을 타고 가다가 깊은 터널에 진입하는 순간, 앱 화면이 멈추는 경험을 해보셨을겁니다
로딩 인디게이터가 빙글빙글 도는 상황도,
아무런 반응이 없어서 강제종료 후 다시 실행한 경험도 있을텐데요
이때 사용자에게 앱에 어떻게 표시되는게 가장 좋을까요?
다양한 의견이 있겠지만, 결국 네트워크 예외처리를 해야한다는 사실 자체는 변함이 없습니다
네트워크 요청은 언제든 실패할 수 있고, 이를 제대로 처리하지 않으면 사용자 경험이 크게 저하됩니다
사용자 경험을 위해서라도, 또 네트워크의 경제적인 요청을 위해서라도 예외처리는 해야합니다
⎮ 예외처리 꼭 해야할까? (feat. 실제 앱의 케이스)
좋은 예외처리가 있다는 것도 알겠고, 사용자 경험 저하를 방지할 수 있다는 것도 알겠는데
이 귀찮은 예외처리 꼭 해야하는걸까요?
저는 그 해답을 잘 서비스되고 있는 앱에서 찾아보려고 했습니다
앱을 실행하다가 중간에 비행기 모드를 켜거나, 와이파이를 꺼서 네트워크를 단절하면 어떻게 될까요?
각 앱마다 테스트는 총 1분 30초씩 진행했습니다
(개인이 한 테스트이므로, 부정확할 수 있음을 양해해주세요)
- 초기 실행 후 네트워크 단절 시(2025. 09. 01. 기준)
유튜브 : 2초 뒤 알럿
여기어때 : 약 20초 뒤 알럿
빗썸 : 약 5초 뒤 토스트 메시지
크림 : 알럿 미표시, 홈화면에서 대기(스켈레톤 뷰)
네이버 : 약 10초 뒤 알럿, 홈화면에서 대기(스켈레톤 뷰)
토스 : 알럿 미표시, 다른 탭 이동 시 다시 시도하기 View
배달의민족 : 약 20초 뒤 알럿, 스플래시 화면






(위의 테스트는 테스팅 시간도 짧을 뿐더러, 단일 기기로 테스트한거라 부정확할 수 있습니다)
다만 제가 이 테스트를 통해 깨달은 점은 다음과 같습니다
1분 뒤 알럿을 띄우는 기업이라고 해서 이상한 예외처리를 했다고 볼 수 없습니다
내부적으로는 1분동안 네트워크 연결이 되어 있는지 감지하고,
재시도하는 등의 로직을 처리하고 있을 수 있기 때문이죠
마찬가지로 내부 동작을 모른다는 관점에서
테스트 시간동안 어떠한 알럿을 띄우지 않았다고 해서
아무런 예외처리도 되어 있지 않은 기업이라고 볼 수도 없다는 생각을 하게 되었습니다
- 실행 중 네트워크 단절 시(2025. 10. 29. 기준)
유튜브 : 동일
여기어때 : * 홈화면에서는 미표시, 다른 탭으로 이동하면 알럿
빗썸 : * 재시도 View
크림 : * 알럿 표시
네이버 : * 상단 재시도 탭
토스 : 동일
배달의민족 : * 알럿 즉시 표시





예외처리 방식이 수정된 기업도 있고, 유지 중인 기업도 있습니다.
대부분의 서비스는 네트워크 관련 예외처리가 되어 있고
더 나은 UX를 위해 업데이트를 지속하고 있는 것으로 보입니다
네트워크가 꼭 필수적인 서비스도 있고, 필수적이지 않은 서비스도 있지만
네트워킹을 포함하고 있는 서비스는 사용자를 위해 네트워크 예외 처리를 해주는 것이 좋아보입니다
⎮ 좋은 예외처리가 있을까?
예외처리에도 좋은 예외처리라는게 있을까요?
제가 생각하는 좋은 예외처리는 다음과 같습니다
- 명확해야 한다
- 일관되어야 한다
- 복구 가능해야 한다
'명확하다'는 것은 다음과 같습니다
어떤 에러인지 구분하여 처리해야 합니다
// 1. error로 전부 처리
enum NetworkError: Error {
case error
}
// 2. 에러를 구분하여 처리
enum NetworkError: Error {
case noInternetConnection
case requestTimeout
case unauthorized
case serverError
case decodingFailed
var localizedDescription: String {
switch self {
case .noInternetConnection:
return "인터넷 연결을 확인해주세요"
case .requestTimeout:
return "요청 시간이 초과되었습니다"
case .unauthorized:
return "로그인이 필요합니다"
case .serverError:
return "서버에 문제가 발생했습니다"
case .decodingFailed:
return "데이터 처리 중 오류가 발생했습니다"
}
}
}
2번 케이스와 같이 에러를 처리하면
개발자 뿐만 아니라 사용자에게도 어떤 에러인지 명확하게 알려줌으로써 디버깅에 많은 도움이 됩니다.
'일관된다'는 것은 다음과 같습니다.
protocol ErrorHandleable: AnyObject {
func handle(error: NetworkError)
}
extension ErrorHandleable where Self: UIViewController {
func handle(error: NetworkError) {
let alert = UIAlertController(
title: "오류",
message: error.localizedDescription,
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "확인", style: .default))
present(alert, animated: true)
}
}
프로토콜로 에러를 정의하면, 프로젝트 전체에서 동일한 방식으로 에러를 핸들링할 수 있습니다
이렇게 하면 여러 VC에서 각자의 방식으로 Alert을 띄우는 것이 아니라,
통일된 사용자 경험을 제공할 수 있습니다
또한 추후 에러 처리 방식을 변경할 때도 한 곳만 수정하면 되므로 유지보수에도 유리합니다
'복구가 가능하다'는 것은 다음과 같습니다
enum NetworkError: Error {
case noInternetConnection
case serverError
case unauthorized
var isRetryable: Bool {
switch self {
case .noInternetConnection, .serverError:
return true
case .unauthorized:
return false
}
}
var recoveryAction: String? {
switch self {
case .noInternetConnection:
return "재시도"
case .serverError:
return "재시도"
case .unauthorized:
return "로그인"
}
}
}
모바일 리소스를 고려하면 재시도도 무한정할 수는 없기 때문에
상세하게 처리해줘야 하지만, 그건 다음 포스팅에서 다뤄보겠습니다
⎮ 결론
대부분의 앱은 네트워크 예외처리가 되어 있습니다
어떤 앱은 2초만에 알럿을 띄우기도하고, 어떤 앱은 재시도 View를 제공합니다
방식은 다르지만, 목표는 같습니다
"네트워크가 끊겨도 사용자가 당황하지 않도록 에러를 처리하자"
이어지는 포스팅에서는 Status Code 기반 예외처리, 서버 메시지 기반 예외처리와
에러별 후속 처리 로직에 대해 다뤄보겠습니다
'Swift > TOPIC' 카테고리의 다른 글
| Json Web Token(JWT)와 Apple Login (0) | 2025.10.24 |
|---|---|
| Swift | 네트워크 예외처리를 해보자(2) - 상태 코드 / 서버 응답 (0) | 2025.09.21 |
| Hash / Hashable / Hasher / HashTable (0) | 2025.09.09 |
| Swift | 메모리 누수(2) (Memory Graph) (0) | 2025.09.01 |
| Swift | 메모리 누수(1) (feat. Instruments Leaks) (0) | 2025.08.30 |