mobile client/iOS

[iOS] 집안일을 관리하자, 페어러(fairer) 회고

hongjunehuke 2023. 10. 25. 19:21
728x90

개요

페어러 서비스는 디프만(Depromeet) 동아리에서 시작되어 안드로이드 앱이 출시된 상태였고 iOS 앱을 만들기 시작하는 상황이었다.
나는 페어러 팀에 합류하고 싶다며 메일을 썼고 간단한 인터뷰 이후 iOS 개발로 팀에 합류하게 되었다.
처음 팀에 들어갔을 때 30% 정도의 UI가 구현되어 있었다. 물론 서버 연결 없이 순수하게 UI만 구현되어 있었다.
하지만 팀 내에서 지키는 코드 컨벤션, PR 규칙, 폴더링 규칙, Base component 등 기본적인 골격이 존재했다. 처음 팀에 들어가서 했던 일은 기존의 코드 구조를 이해하는 일이었다. 팀원들이 짜놓은 코드를 읽으며  내가 맡은 뷰를 어떻게 구현할지 고민하며 프로젝트를 시작했다.

주요 기능
1. 집안일 그룹 생성 및 관리

집안일 그룹을 만들고 팀원을 초대할 수 있다.
집안일 그룹 이름을 바꾸거나 삭제할 수 있다.

2. 규칙을 만들고 관리

집안일 그룹원들과 공유하는 집안일 규칙을 만들고 관리할 수 있다.

3. 집안일 계획을 만들고 관리

집안일을 날짜별로 추가할 수 있고 수정, 삭제가 가능하다. 반복되는 집안일은 반복하기 설정을 추가하여 계획에 추가할 수 있다.
날짜별로 본인과 집안일 그룹원의 집안일 진행 상황을 확인할 수 있다.

개발 기간

2022/10 ~ 2023/5    1차 출시
2023/6 ~                    버전업 준비

시연 영상

https://tv.kakao.com/v/441403212


앱 스토어

https://apps.apple.com/kr/app/%ED%8E%98%EC%96%B4%EB%9F%AC-fairer/id6451104062


깃허브

https://github.com/fairer-iOS/fairer-iOS

문제 해결 및 구현 방법

1. 안드로이드 출시를 따라가는 개발 흐름

안드로이드 팀은 안드로이드 버전 앱을 이미 출시하였고 추가적인 기능을 넣은 2차 릴리지를 준비하고 있었습니다. iOS 팀은 안드로이드 1차 버전의 기능을 먼저 개발하고 이후 안드로이드 2차 버전의 기능을 넣어 2차 릴리즈를 준비하기로 했습니다.
1차 릴리즈에 있어 중요한 부분은 기능적으로 안드로이드 앱과 동일하게 구현하는 것이었습니다.
추가적으로 캘린더 UI 디자인이나 vertical 스와이프 제스처가 양방향으로 되는 등 iOS HIG에서 제시하지 않는 요소를 디자인 팀과 함께 고민하여 수정했습니다.

2. 캘린더 UI 기능 구현

메인 뷰에 집안일을 관리하는 주간 캘린더가 있습니다.
무작정 서드파티인 FSCalendar를 도입하지 않고, 디자인과 기능 요구 사항이 FSCalendar로 커스텀 가능한 영역인지를 패기지를 뜯어보며 고민했습니다.
서드파티의 도입으로 패키지 종속성이 생긴다는 문제도 분명했고, FSCalendar 도입으로 과연 개발 시간을 줄일 수 있을지 고민했습니다.
FSCalendar를 커스텀하기보다 직접 주간 캘린더를 구현하는 것이 시간적으로나 패키지 종속 측면에서 장점이 많다고 판단하고 주간 캘린더를 직접 구현했습니다.

3. 네트워크 환경 예외 처리

네트워크 환경을 관찰하고 대응하는 코드를 SceneDelegate의 확장으로 아래와 같이 구현했습니다.
NetworkMonitor 클래스를 만들고 SceneDelegate의 생명주기에 맞춰 willConnectTo 함수에서 네트워크 모니터링 함수(startMonitoringNetwork)를 호출하도록 구현했습니다.

import Foundation

import Network

final class NetworkMonitor {
    private let queue = DispatchQueue.global(qos: .background)
    private let monitor: NWPathMonitor
    
    init() {
        monitor = NWPathMonitor()
        dump(monitor)
        print("------------")
    }
    
    func startMonitoring(statusUpdateHandler: @escaping (NWPath.Status) -> Void) {
        monitor.pathUpdateHandler = { path in
            statusUpdateHandler(path.status)
        }
        monitor.start(queue: queue)
    }
    
    func stopMonitoring() {
        monitor.cancel()
    }
}
extension SceneDelegate {
    private func startMonitoringNetwork(on scene: UIScene) {
        networkMonitor.startMonitoring(statusUpdateHandler: { [weak self] connectionStatus in
            switch connectionStatus {
            case .satisfied: self?.removeNetworkErrorWindow()
            case .unsatisfied: self?.loadNetworkErrorWindow(on: scene)
            default: break
            }
        })
    }
    
    private func removeNetworkErrorWindow() {
        DispatchQueue.main.async { [weak self] in
            self?.errorWindow?.resignKey()
            self?.errorWindow?.isHidden = true
            self?.errorWindow = nil
        }
    }
    
    private func loadNetworkErrorWindow(on scene: UIScene) {
        if let windowScene = scene as? UIWindowScene {
            DispatchQueue.main.async { [weak self] in
                let window = UIWindow(windowScene: windowScene)
                window.windowLevel = .statusBar
                window.makeKeyAndVisible()
                let noNetworkView = NoNetworkView(frame: window.bounds)
                window.addSubview(noNetworkView)
                self?.errorWindow = window
            }
        }
    }
}

이때 네트워크 환경이 끊기는 상황은 잘 처리했지만, 네트워크 환경이 정상으로 돌아왔을 때 발생할 때는 정상적으로 네트워크 환경에 대응하지 못했습니다.
네트워크 환경이 정산으로 돌아올 때 발생하는 딜레이 도중에 startMonitoringNetwork 함수가 호출되며 발생하는 문제였습니다.
일정 시간 이후 모니터링을 돌리는 방식이나 3회 차례로 모니터링을 돌리는 방식을 생각하여 구현했지만, 문제는 해결되지 못했습니다.
글을 읽는 분 중에 네트워크 딜레이를 무시하고 네트워크 연결 상태를 확인할 방법을 아시는 분은 소개해 주시면 정말 감사하겠습니다.

4. 카카오 공유하기 API 사용

집안일 그룹의 초대 코드를 카카오톡으로 공유하는 기능을 구현하기 위해 카카오 공유하기 API를 사용하여 파이어베이스 동적링크를 전달하는 방식으로 구현했습니다.
카카오 개발자 문서와 파이어베이스 문서를 자주 읽으며 공식 개발 문서에 익숙해질 수 있었습니다.

5. 자세한 PR과 코드리뷰

페어러 iOS 팀에서는 이해할 수 있는 자세한 PR과 꼼꼼한 코드 리뷰를 강조했습니다.
버그의 유무만 판단하지 않고 더 좋은 방식을 함께 고민했습니다.
https://github.com/fairer-iOS/fairer-iOS/pull/128
https://github.com/fairer-iOS/fairer-iOS/pull/88







728x90