Conversation
Feature/mission result view#6
- 공통 레이블 설정 값으로 재 수정 작업 진행
🌟feat: 자유항행 - View 제작: 상단 타이머 화면 구현
- 변경된 공통 레이블 설정값으로 변경 작업 진행
[FEAT] 자유항행 - View 제작: 하단 레코드 화면 구현 #9
🐛fix: AlarmListViewCell 메서드 주석처리, ViewController 연결
[FEAT] 자유항행 - View 제작: 상단 및 하단 통합 VC 설계 및 구현 #10
- StopWatch Viewmodel 설계 - 버튼 눌렀을때 시간 동작 기능 구현 - 같은 버튼 눌렀을때 Pause 기능 구현 ref #23
[PR] 상세 기록 화면 컬렉션 뷰 헤더 및 상세보기 버튼 추가 (HomeTab#50)
🌟feat: 홈으로가기 버튼 삭제
Updated README to enhance project description and details.
🐞fix: 잘못된 단위로 표시되던 미션 결과 데이터 수정
✨feat: ActivatedMissionCell에 ProgressView 추가
[PR] 미션 결과 표시 형식 변경 및 버그 수정 (HomeTab#57)
✨feat: CustomMissionCell 삭제 기능 추가
♻️ refactor: 오타 수정, 오류 출력 수정
There was a problem hiding this comment.
Code Review
이번 풀리퀘스트는 우주 테마의 시간 관리 앱인 'RocketCall'의 핵심 기능인 알람, 미션(뽀모도로), 자유 항행(스톱워치) 기능을 MVVM 아키텍처와 RxSwift를 기반으로 구현하고, CoreData를 통한 데이터 영속성 및 로컬 알림 관리 로직을 추가합니다. 코드 리뷰 결과, 프로덕션 환경에서 앱 충돌을 유발할 수 있는 fatalError 사용과 특정 인덱스에 의존하는 로직 등 안정성 측면의 개선이 필요합니다. 또한, 코드의 가독성과 유지보수성을 높이기 위해 매직 넘버를 상수로 정의하고, 알림 권한 요청 및 미션 결과 처리 시의 에러 핸들링을 강화할 것을 권장하며, 오타로 인한 컴파일 오류 수정이 필요합니다.
| if let error = error as NSError? { | ||
| fatalError("Unresolved error \(error), \(error.userInfo)") | ||
| } |
| // Replace this implementation with code to handle the error appropriately. | ||
| // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. | ||
| let nserror = error as NSError | ||
| fatalError("Unresolved error \(nserror), \(nserror.userInfo)") | ||
| } |
|
|
||
| do { | ||
| // 무음모드 일때도 소리나게 하기 | ||
| try AVAudioSession.sharedInstance().setCategory(.playback, mode: . default) |
| guard let self else { fatalError("Error: self is nil") } | ||
| switch itemIdentifier { | ||
| case .activatedMission(let mission): | ||
| guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ActivatedMissionCell.id, for: indexPath) as? ActivatedMissionCell else { fatalError("ActivatedMissionCell dequeueReusableCell error") } |
There was a problem hiding this comment.
셀 캐스팅 실패로 인한 앱 충돌을 방지하기 위해, fatalError를 호출하는 대신 빈 셀을 반환하도록 수정하세요. 이는 추후 더 견고한 오류 처리 및 사용자 알림을 구현하기 위한 계획의 일환입니다.
| guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ActivatedMissionCell.id, for: indexPath) as? ActivatedMissionCell else { fatalError("ActivatedMissionCell dequeueReusableCell error") } | |
| guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ActivatedMissionCell.id, for: indexPath) as? ActivatedMissionCell else { return UICollectionViewCell() } |
References
- To prevent application crashes from cell casting failures during dequeuing, return an empty cell instead of calling fatalError, with a plan to implement more robust error handling and user notifications later.
| center.requestAuthorization(options: options) { granted, error in | ||
| } |
There was a problem hiding this comment.
| var dateComponents = DateComponents() | ||
| dateComponents.hour = alarm.hour | ||
| dateComponents.minute = alarm.minute | ||
| dateComponents.second = i * 9 |
| content.interruptionLevel = .timeSensitive // 방해 금지여도 알람 | ||
|
|
||
| // 2. 시간 설정 | ||
| let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 300, repeats: false) |
There was a problem hiding this comment.
| } | ||
|
|
||
| // 24초 딜레이 | ||
| DispatchQueue.global().asyncAfter(deadline: .now() + 27.0) { |
| private func showMissionResult(resultId: UUID) { | ||
| selectedIndex = 2 | ||
| // 네비게이션 컨트롤러 꺼냄 | ||
| guard let missionNavigationController = viewControllers?[2] as? UINavigationController else { return } |
There was a problem hiding this comment.
viewControllers 배열의 특정 인덱스(2)에 의존하여 UINavigationController를 가져오고 있습니다. 탭 바의 순서가 변경될 경우 이 코드는 예기치 않게 동작하거나 실패할 수 있습니다. 타입 기반으로 뷰 컨트롤러를 찾는 것이 더 안정적입니다.
| guard let missionNavigationController = viewControllers?[2] as? UINavigationController else { return } | |
| guard let missionNavigationController = viewControllers?.first(where: { ($0 as? UINavigationController)?.viewControllers.first is MissionViewController }) as? UINavigationController else { return } |
| let payload = try coreDataManager.fetchMissionResult(of: resultId) | ||
| missionResultView.configure(with: payload) | ||
| } catch { | ||
| // TODO: 오류 처리 로직 구현 | ||
| missionResultView.configure(with: samplePayload) |
고생많으셨습니다