출시 기간 : 2024.03.07 - 03.27 (약 3주)
Release version : v1.0.6 (지속 업데이트 중 🚀)
기획/디자인/개발 1인 개발
프로젝트 환경 - iPhone 전용(iOS 15.0+), 라이트 모드 고정
때맞춰 당신의 건강을 챙겨주는 빠릿빠릿한 약복용 비서 - 삐릿(Pill It)
-
의약품 정보 검색
-
식품의약안전처(의약품 제품 허가정보, 의약품 낱알식별 정보) API 연동 : 국내에서 신고 및 허가된 의약품(전문/일반)에 대한 정보 검색
-
의약품 상세 검색 기반의 복용약 등록 : 품목명, 업체명, 주성분, 분류명 등에 따른 자신의 복용약을 정확하게 등록
-
의약품 상세정보 제공 : 보험(보험/비보험 여부), 성분함량, 효능효과, 용법용량, DUR 등 해당 의약품에 대한 상세정보 제공
-
-
복용약 등록 및 알림
-
복용약 사진 설정 : 식품의약처, 카메라촬영/앨범, 네이버 이미지 검색 기반의 복용약 사진 설정
-
복용약 그룹 설정 : 사용자의 의약품 용도에 따른 N개 이상의 복용약에 대한 그룹 설정
-
복용약 그룹 알림 설정 : 사용자의 복용약 주기(매일, 특정요일, 일/주/월 간격)에 따른 세부 시간 설정
-
복용약 그룹 알림 : 사용자가 지정한 시간에 등록된 복용약 그룹에 대한 알림
-
-
프레임워크
UIKit
-
아키텍쳐
MVVM
-
오픈 소스(Cocoapods)
Realm / RxSwift / Alamofire / Kingfisher / UserNotifications
SearchTextField / Toast-Swift / NVActivityIndicatorView / SwipeableTabBarController / WHTabbar / Parchment / Tabman
-
버전 관리
Git(Git-Flow 적용) / Github
MVVM
-
View 및 Business 로직을 분리하기 위한 MVVM 아키텍처를 도입
-
Input-Output 패턴의 Protocol을 채택함으로써 User Interaction과 View Data 핸들링
protocol ViewModelType { var disposeBag : DisposeBag { get } associatedtype Input associatedtype Output func transform(input : Input) -> Output } protocol CombineViewModelType : AnyObject, ObservableObject { associatedtype Input associatedtype Output var cancellables : Set<AnyCancellable> {get set} var input : Input {get set} var output : Output {get set} func transform() }
Realm
Reactive Programming
-
비동기 Event의 관리를 위한 Custom Observable과 RxSwift를 이용한 Reactive Programming 구현
-
Generic 기반의 Observable 구현
final class Observable<T> {
private var closure : ((T) -> Void)?
var value : T {
didSet {
closure?(value)
}
}
init(_ text: T) {
self.value = text
}
func bind(_ closure : @escaping (T) -> Void) {
closure(value)
self.closure = closure
}
}
Alamorfie
-
URLRequestConvertible
을 활용한Router 패턴
기반의GET/POST/DEL/PUT
메소드를 활용한RESTful API Network
와의 통신 구현 -
Error Handling을 위한 Result Type 적용
SearchTextField
- User Interaction 기반의 userStoppedTypingHandler, itemSelectionHandler 구현을 통한 TextField의 Autocomplete 적용
SwipeableTabBarController, WHTabbar, Parchment, Tabman
- 다수의 UITabBarController 연관 Open Source를 활용한 사용자 친화적 UI 구성
-
문제 상황
"iOS 디바이스는 알림을 최신 64개 알림으로 제한"한다. 개발 과정에서 해당 사항을 고려하지 않고, 복용약 알림을 등록할 때 생성되는 모든 Date를 iOS 디바이스에 등록하게 되어 알림이 정상적으로 발생하지 않는 문제 발생
-> 복용약 알림등록에서 알림 주기를 등록시간 06:00시 기준으로 "매일(365일) - 07:00, 12:00, 19:00"로 설정하는 경우, 365 * 3 = 1095개의 알림이 생성됨.
-
해결 방법
-
Local Notification
을 관리하는RefreshManager 생성 (Singleton Pattern)
-
sceneDidBecomeActive
(앱이 Terminated 된 후 다시 실행되었을 때)PillAlarmDate Table로부터
D-1,D+0,D+1 Date
에 해당하는 알림 목록 Fetch하고Local Notification
을 등록하는 함수(RefreshManager.shared.resetNotificationAction) 실행 -> 앱이 Active 될때마다 실행되므로,
UserDefault를 활용하여 D+0에서 최초 1번 실행
한 경우에는 이후 부터 실행되지 않음 -> 앱이 sceneDidDisconnect 된 경우 알림이 제대로 동작하지 않으므로, 사용자가 다시 앱을 실행할 수 있도록 Local Notification으로 유도
-
sceneDidEnterBackground
(앱이 Background로 전환되었을 때)Background -> Foreground 상태로 전환시, 최신 Local Notification을 등록할 수 있도록 Timer 사용
-
-
문제 상황
DiffableDataSource에서는 Diff을 위해 삭제된 객체를 들고있어야 하는데, Realm은 데이터가 삭제되는 순간 해당 데이터에 접근할 수 없으므로 "Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'" 에러가 발생한다.
-
해결 방법
- Realm Table에서 임의의 Attribute인 Bool 타입의 isDeleted 생성 후 해당 Record의 Delete가 발생할 때, Realm Table에서 실제로 삭제되는 것이 아니고 isDeleted에
true
부여 - 또한, Realm Table에서 실제 삭제가 되는 것이 아니므로, 앱이
sceneDidDisconnect
또는sceneDidEnterBackground
상태로 변경될 때 Delete 되도록 함
- Realm Table에서 임의의 Attribute인 Bool 타입의 isDeleted 생성 후 해당 Record의 Delete가 발생할 때, Realm Table에서 실제로 삭제되는 것이 아니고 isDeleted에