Crashed: org.alamofire.session.rootQueue
0 Haram 0x11aa64 UserManager.reissuanceAccessToken() + 4366690916 (<compiler-generated>:4366690916)
1 Haram 0x100e88 specialized Interceptor.retry(_:for:dueTo:completion:) + 28 (Interceptor.swift:28)
//... 생략
Interceptor의 retry함수에서 비정상 종료가 7명 정도가 있어 코드자체의 문제가 있다고 판단함
401 상태코드로 인한 토큰 재발급시에 재발급 이후에 retry를 하게되는데 무한정으로 retry를 시도하고있다 판단
if request.retryCount < self.retryLimit {
UserManager.shared.reissuanceAccessToken()
.subscribe(onSuccess: { _ in
// 재발급을 성공했다면 기존에 발생했던 요청 재시도
completion(.retry)
}
Crashed: com.apple.main-thread
0 Haram 0x7a534 LoginViewModel.loginMember(userID:password:) + 12 (NetworkManager.swift:12)
1 Haram 0x44768 LoginViewController.didTappedLoginButton() + 224 (LoginViewController.swift:224)
//... 생략
authRepository.loginMember(
request: .init(
userID: userID,
password: password,
uuid: UserManager.shared.uuid!,
//... 생략
if !UserManager.shared.hasUUID {
UserManager.shared.set(uuid: UUID().uuidString)
}
성서알리미 로그인 시 하나의 계정을 여러 디바이스에서 로그인하는 것을 방지하기위해 UUID를 이용하여 이를 구분하고자 함
AppDelegate에서 UUID를 생성해주었기에 강제언래핑을 통해 값을 가져와도 된다 판단했지만 딱 보이기에 앱이 비정상 종료가 될만한 코드가 저 부분이라 위처럼 UUID를 가지고있지않을 시 생성해주는 코드를 삽입
// HomeViewModel
private let newsModelRelay = BehaviorRelay<[HomeNewsCollectionViewCellModel]>(value: [])
private let bannerModelRelay = BehaviorRelay<[HomebannerCollectionViewCellModel]>(value: [])
private let shortcutModelRelay = BehaviorRelay<[HomeShortcutCollectionViewCellModel]>(value: [])
owner.newsModelRelay.accept(news)
owner.bannerModelRelay.accept(banners)
owner.noticeModelRelay.accept(notices)
// HomeViewController
Driver.combineLatest(
viewModel.newsModel,
viewModel.bannerModel,
viewModel.noticeModel,
viewModel.isAvailableSimpleChapelModal
)
홈 데이터를 가지는 타입을 BehaviorRelay를 사용하여 초기값을 가지고있는 상황에서 HomeViewController에 combineLatest를 통해 홈 화면에 데이터바인딩시키고있는 로직
위와 같은 이유로 인해 홈 정보 API를 한번 호출함에도 데이터바인딩을 3번돌려 reload하는 코드이기때문에 불필요한 리소스낭비된다고 판단
홈에 채플정보에 대한 UI를 특정시간(오전 10시 ~ 오후 1시)만 띄워주기위해 viewWillAppear함수에 구현해주었기때문에 위 코드는 해당 시간에 굳이 변경하지않아도 될 홈 정보를 reload해주는 불필요한 코드
/// HomeViewModel
private let newsModelRelay = PublishRelay<[HomeNewsCollectionViewCellModel]>()
private let bannerModelRelay = PublishRelay<[HomebannerCollectionViewCellModel]>()
private let shortcutModelRelay = PublishRelay<[HomeShortcutCollectionViewCellModel]>()
/// HomeViewController
Driver.zip(
viewModel.newsModel,
viewModel.bannerModel,
viewModel.noticeModel
)
BehaviorRelay -> PublishRelay로 바꿔줌으로써 초기값을 가지고있지않기때문에 섹션 1개만 변경해도 전체가 reload되는 문제점 해결
홈 정보 API를 호출할때 공지, 바로가기, 뉴스레터 총 3개의 섹션에 대한 데이터를 한번에 받기때문에 combineLatest -> zip으로 변경(사실 combineLatest로 둬도 무관하지만 zip연산자가 의도를 분명하게 함)
// HomeViewController
viewModel.isAvailableSimpleChapelModal
.drive(with: self) { owner, modalModel in
//... 생략
[성서알리미]앱에서는 402(refreshToken만료) 499(다른 디바이스에서 한 계정 접속)할때에 로그인 화면으로 돌아가 로그아웃하는 기능이 존재
너무 자주 로그인화면으로 이동한다는 사용자의 피드백을 따라 로그를 찍어본 결과 402, 499코드가 떨어져 이미 로그인화면에 이동했음에도 retry가 호출되는 문제점 발견
// Interceptor
else if statusCode == 402 || statusCode == 499 {
// 상태코드 402은 refreshToken 만료, 499는 다른 uuid를 이용해 로그인 시 기존 로그인이 취소되었음을 알림
UserManager.shared.clearAllInformations()
DispatchQueue.main.async {
let vc = LoginViewController()
(UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first?.rootViewController = vc
if statusCode == 499 {
AlertManager.showAlert(title: "로그아웃 알림", message: "다른 기기에서 로그인되었습니다", viewController: vc, confirmHandler: nil)
}
}
completion(.doNotRetryWithError(error))
}
전부 처리하였다고 생각했는데 402, 499 상태코드가 떨어졌을 시 completion을 이용해 retry를 이제 하지않겠다는 콜백을 던져줬어야했는데 추가하지못해 해당 문제 발생
이전 Swift Concurrency에서 콜백함수의 문제점 중 에러에 대한 처리를 하지않아도 컴파일러는 이를 모르기에 개발자의 의도에 따라 달렸다고 공부했는데 이번 경험을 통해 한번 더 인지하게 됨
기존 v1.0.1버전 사용자에 대해 비정상종료 대상자비율이 v1.0.2버전 사용자에 대비해 줄어든 모습