iOS 개발일지
게임도브 - 출시 회고 본문
순식간에 지나간 3주간의 출시 프로젝트
- API 통신
개발 초기에 API에 정말 많은 시간을 들였다.
쿼리는 왜 이렇게 많은지, API 통신에서의 매개변수 종류도 몰랐던 나에겐 꽤 아찔했던 경험이었다.
이 외에도 통신 실패 시 대응과 hud의 dismiss 시점, 검색 결과가 없을 시 대응, 페이지네이션 등 고려할 점이 많았다.
- DB 설계
API 통신을 통해 데이터를 보여주는 것이 주된 기능인 어플이기 때문에 DB 설계는 크게 어렵지는 않았다.
Realm Model은 총 두 가지로, Storage와 MainSettings이다.
Storage는 저장 버튼을 누를 경우 저장되는 게임에 대한 정보를 담고 있으며, 중복 저장을 허용하지 않기 때문에 pk는 game의 id값이다.
Repository에 id를 매개변수로 받고, Bool 타입을 반환하는 함수 canStore를 만들어 중복체크 후 저장하도록 구현했다.
이번 프로젝트로 Realm에 대해 아주 조금이지만 더 이해하게 된 것 같다.
MainSettings는 메인플랫폼 설정 등에 사용되는 모델로, 설정은 하나만 지원하기 때문에 pk는 고정값 "setting"으로 설정했다.
추후에 더 많은 사용자 설정을 추가하게 된다면 마이그레이션이 필수인 모델이다... 벌써 무섭다.
- 오픈소스와 싸워보기
해당 프로젝트에서 사용한 오픈소스는 총 7개이며, 이 중 처음 사용해본 오픈소스는 DeviceKit, SideMenu 이다.
DeviceKit은 이름처럼 매우 직관적인 기능으로, 사용자의 디바이스 정보를 캐치할 수 있다.
해당 오픈소스를 사용해서 문의하기의 MessageBody에서 사용자의 디바이스를 자동으로 받을 수 있도록 설정했다.
SideMenu는 탭바의 탭 갯수를 줄이기 위해 사용해본 라이브러리로, 사이드에서 숑 하고 나오는 메뉴를 만들 수 있다.
사용하는 방법을 몰라 조금 헤맸지만, 알고 보면 그렇게 어렵지도 않다!
@objc func sideMenuTapped() {
let menu = SideMenuNavigationController(rootViewController: SideMenuViewController())
menu.leftSide = true
menu.isNavigationBarHidden = true
menu.presentationStyle = .viewSlideOut
menu.pushStyle = .popWhenPossible
present(menu, animated: true, completion: nil)
}
가장 중요한 것은 버튼을 클릭했을 때 보여질 사이드메뉴의 VC를 만드는 것으로, VC를 반만 사용한다고 생각하고 레이아웃을 구성하면 된다.
- 리젝 경험
많은 사람이 경험해보지는 못할 것 같은 리젝을 한번 경험했다.
애플이 깐깐하게 생각할법한, 당연하다면 당연한 그런 이유였다.
Specifically, your app includes Android references in the Android section.
바로 게임의 플랫폼에 안드로이드가 포함되어 있는 것...
바로 안드로이드에 관련된 코드를 수정한 후 재심사를 넣으니 주말 아침이었는데도 불구하고 단 20분만에 승인되어 출시할 수 있었다.
애플의 폐쇄성에 대해서는 이미 들은 바 있었지만 실제로 이렇게 겪어보니 어이없으면서도 재미있어서, 좋은 경험이었다고 생각한다.
- 자동 스크롤 타이머 이슈
타이머를 활용해 3초마다 배너 컬렉션뷰가 자동으로 스크롤되게끔 구현했다.
그리고 사용자가 직접 스크롤할 경우엔 nowPage를 다시 설정하고, 타이머를 멈춘 후 재실행한다.
var timer: Timer?
var nowPage = 0 {
didSet {
mainView.pagingIndexLabel.text = "\(nowPage + 1) / \(scList.count + 1)"
}
}
private func bannerTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] Timer in
self?.bannerMove()
print(#function)
}
}
private func bannerMove() {
if nowPage == scList.count {
mainView.bannerCollectionView.scrollToItem(at: NSIndexPath(item: 0, section: 0) as IndexPath, at: .right, animated: false)
nowPage = 0
return
}
nowPage += 1
mainView.bannerCollectionView.scrollToItem(at: NSIndexPath(item: nowPage, section: 0) as IndexPath, at: .right, animated: true)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
guard scrollView == mainView.bannerCollectionView else { return }
nowPage = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width)
timer?.invalidate()
bannerTimer()
}
그런데 만일을 위해 print를 찍어봤더니, deinit이 되었음에도 불구하고 타이머가 계속 돌아가고 있었다...
알고보니, 타이머는 클래스 내에서만 동작하는 것이 아니기 때문에 (ex. 백그라운드 실행) 클래스가 deinit 되고도 종료되지 않을 수 있다.
따라서 아래와 같이 deinit 될 때 invalidate 시켜주는 코드가 따로 필요하게 된다.
deinit만 믿고 해당 VC 내에서의 모든 작업이 종료되었다고 생각하면 안될 것 같다.
- 아쉬운 부분
MVVM으로 구현하고 싶었지만 능력이 부족했다ㅠㅠ...
MVVM에 대해서 더 자세히 다룰 예정이라고 하니, 나중에라도 MVVM으로 바꾸고 싶다.
그리고 MVC로 구현하더라도 조금 더 깔끔한 코드를 작성할 수 있었을텐데, 출시에 급급해서 비효율적인 코드가 군데군데 있는 것도 아쉬운 부분이다.
그리고 디자이너는 아니지만 조금 더 보기 편하고 그럴듯한 디자인을 할 수는 없었을까... 하는 마음도 있다.
하지만 다시 봐도 어디서부터 고쳐야 예쁜 UI가 될지는 잘 모르겠다.
'App' 카테고리의 다른 글
게임도브 - 개인정보 처리방침 (0) | 2022.09.27 |
---|