안녕하세요.
KataRN입니다.
오늘은 Come Hear 기획부터 출시하기까지 면접에서 질문할 법한 것들을 정리해보려고 합니다.
이번 Come Hear는 마감일이 있는 프로젝트였습니다.
그러다보니 공부를 위해 쓴다보다는 익숙했던, 성능적으로 더 우위에 있는 기술들을 사용하였습니다.
그리고 이러한 것들이 면접에서 저의 프로젝트를 보고 질문하기에 딱 좋지 않나 라는 생각이 되어 정리를 해보려고합니다.
우선 차례차례 적어보겠습니다.
1. SPM(Swift Package Manager) 사용
빌드속도를 최소로 줄이고싶었습니다.
- 코코아팟
장점 - 지원하는 라이브러리가 많다.
단점 - 의존성 추가한 라이브러리도 함께 빌드하기 때문에 빌드 타임이 오래 걸린다.
- SPM(Swift Package Manager)
장점 - Apple이 지원하는 first party, 빠르게 라이브러리 추가 가능 => 간편하다
단점 - 지원하는 라이브러리가 많지 않다.
이러한 이유로 SPM을 사용해보고 싶었고 적용하였습니다.
사소한 장점으로는 다른 맥북에 깃허브로 설치할 경우 pod 업데이트를 따로 하지 않아도 되어서 편했습니다.
2. 스토리보드 사용하지 않기
평소에 깃에서 merge할 경우 충돌이 많이 났었는데 스토리보드를 사용할 경우의 단점이라는 것을 알고 이번엔 스토리보드를 사용하지 않기로 하였습니다.
그밖에도 빌드속도를 올리고 싶었습니다.
스토리보드를 사용하지 않고 코드로만 작성하였습니다.
3. 지연 저장 속성을 이용하기
지연 저장 속성 (Lazy Stored Property) 은 인스턴스가 초기화 되는 시점이 아니라 속성에 처음 접근하는 시점에 초기화됩니다.
Swift는 비싼 코스트의 작업을 in-time 계산할 수 있게 하는 lazy variables라는 메커니즘을 제공합니다. lazy variables는 변수가 처음 요청되었을 때만 사용자가 지정한 함수를 사용하여 생성됩니다.
만약 요청되지 않는다면, 지정된 함수는 절대 불리지 않고, 이는 processing time을 절약해줍니다
4. 로딩화면에 애니메이션을 넣고 로딩하는 동안 데이터 불러오기
기존의 로딩화면은 너무 빨리 사라져서 어느정도 애니메이션을 노출하고싶었습니다.
의도적으로 시간을 지연시키는 방법은 단순하게 시간만 노출하는데 그러면 애니메이션이 끝나고 데이터를 불러와서 비효율적이었습니다.
그래서 제가 선택한 방법은 기존의 런치스크린을 지우고 Xib로 새로 생성해서 런치스크린으로 생성하였고 0.5초후에 비동기적으로 뷰가 사라지도록 만들었습니다. 그리고 자체 제공하는 UIActivityIndicatorView를 생성하여 상태에 따라 지속하거나 사라지도록 만들었습니다.
5. Compositional Layouts 사용하기
여러개의 CollectionView를 중첩하여 사용하는 방법도 좋지만 Compositional Layouts을 이용하여 넷플릭스, Wavve 등처럼 만들어보고 싶었습니다. 요즘 OTT 서비스들은 전부 이 방법을 사용하는것 같아서 트렌드를 따라해보고 싶었습니다. (애플의 설명에 의하면 빠르고 편하다고 하여 사용하였습니다.)
Compositional Layout은 빠르고 유연하고 composable하게 컬렉션뷰를 구현할 수 있는 CollectionViewLayout의 한 종류이며 iOS 13.0 이상부터 지원합니다.
- 복잡한 레이아웃을 선언형 API 로 간단하게 구축할 수 있음
- 하나의 컬렉션 뷰로 다양한 레이아웃을 구성할 수 있음
- 빠른 속도
6. Diffable DataSource를 사용하고 싶었으나 최종적으로 적용 못하였습니다.
Diffable DataSource는 Hashable 기반으로 동작하며 데이터 업데이트를 단순하고 효율적으로 관리할 수 있게 합니다. performBatchUpdates() 대신 apply()를 사용하며 iOS 13.0 부터 지원합니다.
장점
- 변경 사항이 있을 경우 애니메이션이 적용되어 UI가 자연스럽게 업데이트되므로 사용자 경험을 해치지 않음
- Centralized Truth를 사용하기 때문에 UI와 DataSource 간에 Truth가 맞지 않아 크래시나 에러가 발생하는 일이 없음
- Hashable 기반으로 O(n)의 빠른 성능을 가지고 있음
7. Hero 라이브러리를 사용하여 화면애니메이션 구현하기.
- 사실 최종적으로는 Hero없이 구현을 하고싶었으나 Hero없이 구현하기에 시간이 부족하였습니다.
8. 이미지 캐시 처리
image를 가져올 때 매번 서버와의 통신 작업을 하면 현저히 속도가 느리고 로드되는 시간이 길어졌다. 비용 문제도 ..
아무래도 사진이 많이 쓰이는 앱이다 보니 사진을 어떻게해야 빠르고 여러개를 불러올 수 있을까란 생각을 많이 해봤습니다.
기존에는 라이브러리 없이 NSCache를 사용하려고 하였으나 인디케이터 노출 및 PlaceHolder설정, 리사이징, 캐시 관리 등을 직접하기에는 시간이 부족하여 Kingfisher 라이브러리를 이용하게 되었습니다.
캐시 유지 기간, 용량 등 직접적인 관리를 신경 못썼던 점이 아쉬웠습니다.
9. SnapKit 사용하기
스토리보드를 사용하지 않으려다 보니 자연스럽게 SnapKit을 사용하였습니다.
SnapKit을 쓰니 코드가 훨씬 간결하게 적용되어 좋았습니다.
당근마켓에서는 PinLayout을 사용한다고 하여 다음 프로젝트에서는 사용해보고싶습니다.(FlexLayout도...)
10. MVC패턴 사용
사실 MVVM패턴과 RXSwift를 사용하고 싶었으나 아직 RXSwift가 익숙하지 않아서 RX를 제외하고 MVVM으로 설계를 하기로 하였었습니다.
RXSwift없이 MVVM패턴을 만들려고 하였더니 너무 시간이 지체되어 롤백하였습니다.
특히 테이블뷰의 Cell을 접고 여는 행위가 RX로 구현하기 너무 어려웠던 기억이 있습니다.(찾아보니 좋지 않다고하여 이부분에 대해서 고민을 했었습니다.)
11. 비동기작업에서 DispatchQueue(background) 사용하기
AVAudioPlayer를 실행하기 위해 오디오 세션을 세팅을 해줘야하는데 시간도 걸리고 뚝뚝 끊기는 느낌이 나서 qos(background)를 사용하여 뷰를 열면서 미리 준비하도록 만들었습니다. (다만 최종적으로 화면이 열리면서 자동재생이 되는게 좋을것 같다고하여 변경되었습니다.)
12. AVAudioPlayer, AVPlayer 두가지
처음에는 한화면에서는 AVAudioPlayer를 사용했고 다른 화면에서는 AVPlayer를 사용했었으나 최종적으로 AVAudioPlayer로 통일하였다.
이유는 AVPlayer가 스트리밍에 유리하다는 글을 참고하였고 AVAudioPlayerDelegate를 통해서 노래가 정지되면 자동으로 캐치 되도록 만들었다.
13. Extension을 활용하기
가급적 Extension을 활용하여 소스를 분리하고싶었다.
예상대로 유지보수에 유리하고 어디서든 쓸수있어서 편했다.
14. Lottie 라이브러리 사용
개발자들끼리 만들다보니 이미지 파일이 많이 부족하였고 Lottie를 이용하기로 하였다.
15. KakaoMap
네이버는 Swift 코드를 제공하나 카카오맵의 경우 Objective-C만 제공하고있다.
솔직히 네이버 쓰고싶었다... 하지만 공모전의 주최에 카카오도 포함이 되어... 어쩔 수 없이 Objective-C를 사용하였다.
16. SNS로그인 계정삭제 처리
올해 6월부터 SNS로그인 계정 삭제처리를 필수로 넣어야된다고 하였다.
나는 뷰티포인트앱에서 SNS로그인, 회원가입 로직이 있는데 앱이 종료되어 따로 작업을 하지 않았다.
하지만 필수로 적용된만큼 공부할 필요성을 느꼈다.
그리하여 연동해제처리를 직접 네이티브로 하려고 하였으나 인증키를 파일로 넣으니 키값이 보여서 뭔가 보안적으로 안될것같은 느낌이 들었다. 그래서 서버에서 처리하는것으로 변경하여 처리하였다.
- App Store 심사 지침 5.1.1(v)에 설명된 대로, 계정 생성을 지원하는 앱은 2022년 6월 30일부터 사용자가 앱 내에서 계정을 삭제할 수 있도록 허용해야 합니다. 해당 기한은 본 요구 사항을 적용하는데 추가적인 시간을 제공하기 위해 연장되었습니다.
- 앱에서 Apple로 로그인을 제공하는 경우, 계정을 삭제할 때 사용자 토큰을 취소하려면 Apple로 로그인 REST API를 사용해야 합니다.
17. 다국어 설정
다국어를 사용하면 가산점을 준다고하여 사용했다.(결과적으로 특정 다국어 API를 이용해야만 가산점을 주는것이었다. 우리가 사용한 API는 다국어 API는 맞으나 특정 다국어 API에 해당하지 않아서 가산점을 받지 못하였다.)
Localizable를 이용하여 각 나라별 언어를 설정하였다. key값으로 한국어를 쓴 느낌이다.
- 앱을 종료하지 않고 적용되도록 유도하였으나 특정화면에서 적용이 안되어서 적용후 종료시켜서 재시작하도록 유도하였다.
- 종료하는 화면도 애니메이션으로 처리할 수 있다는것을 뒤늦게 알게되었다. 다음에 적용해볼 예정이다.
18. VoiceOver를 사용하기
VoiceOver를 사용하는것이 목표였다.
- isVoiceOverRunning : 보이스오버에 접근할 경우와 아닐 경우로 분기처리하였다.
- isAccessibilityElement : 해당 요소에 접근 못하도록 설정
- accessibilityLabel : 요소를 선택할때 읽어주는 텍스트
- accessibilityTraits : 접근성 요소의 특징을 지정가능.
- UIAccessibility.post : 앱 내의 변경사항이 있을 때 Notification 을 통해 알려줄 수 있습니다.
- accessibilityElementDidBecomeFocused : 해당 접근성 요소에 초점을 설정하도록 합니다.
- accessibilityElementsHidden : 모든 접근성 요소를 숨겨 초점이 해당 요소로 이동하지 못하게 합니다.
19. VoiceOver + 다국어 설정의 문제점
Voice Over의 경우 현재 로컬에 따라 읽어주는 목소리가 바뀐다.
그런 이유로 영어로 바뀌어도 VoiceOver는 한국어 성우가 영어로 읽어준다.(발음이 영어식 발음이 아닌 한국식?발음이다.)
지역을 바꿔주고싶었으나... 지역을 바꾸는 방법을 찾지 못하였다...
20. GPS사용
CoreLocation을 이용하여 좌표를 갖고왔으며 이용하였다.
21. BGM + 목소리 합성
AVMutableComposition을 이용하여 앞뒤로 1초의 여백을 줬다.
여백을 준 이유는 재생시에 앞뒤로 점점 크게 점점 작아지게를 적용하였더니 처음 목소리가 들리지 않아 변경하였다.
22. 속도조절
재생시 rate를 조절하여 속도조절기능을 추가하였다.
23. STT를 사용하여 목소리를 텍스트로 변경함, TTS를 통해 오디오파일이 없는 경우를 대체함.
speech 프레임 워크를 이용하여 사용하였다. 기본적으로 언어를 설정할 수 있는데....
한국어의 경우 비속어를 필터링하기위해 적용하였으나 다른 언어는 어떤 언어를 필터링해야될지 선정할 수 없어서 한국어만 적용하였다.
24. 목소리 변조를 넣고싶었다.
목소리 변조의 경우 피치로 조절을 할 수 있는데 어떤식으로 조절해서 분류해야될지 갈피를 잡지 못하여서 적용하지 못했다.
25. zira, notion을 사용하였다.
26. 최근검색어 StackView UI 구현...ㅎㅎ..
27. 아쉬웠던점
- RXSwift, MVVM, Tuist, 자동화배포 구축(fastlane + GithubActions)을 못하였다...
- 시간이 부족했다... (능력부족... 반성합니다..)
Tuist
- Xcode 프로젝트의 구조를 관리하는 커멘드 라인 툴
- 비슷한 툴은 XcodeGen이 있지만, XcodeGen은 .yml파일로 관리를 하고 tuist는 swift언어로 프로젝트 관리를 하므로 tuist 사용을 추천
- 모듈화에 앞서서 Tuist로 프로젝트의 구성을 Tuist로 관리해놓으면 모듈 구조 역시도 관리하는데 편리하여, 모듈화에 Tuist 사용할것
모듈화의 이점
- 빌드 속도 향상
- 모듈화로 나누어져 있으면, 빌드 시 변경된 부분만 빌드
- 모듈간 결합도는 낮추고, 응집도를 높이는 형태
- .pbxproj에 UUID의 conflict를 줄일 수 있는 장점
Fastlane
Fastlane은 Android 및 iOS배포를 단순화하기 위한 오픈소스 플랫폼이라고 하는데요,
fastlane을 사용하면 개발 및 릴리즈 워크 플로우의 모든 측면을 "자동화" 할 수 있다고 해요!!!
테스트도 가능하다고한거같은데...
로컬에서만 쓰던것을 Github를 통해서 로컬밖에서도 쓸수있게되는것같다?
Github Action
- PR을 날릴때마다 프로젝트에 문제가 있는지 자동으로 빌드 테스트
- 테스트 및 배포 파이프라인 CI/CD 구축
- workflow 사용
- 순차적 or 병렬로 실행할 수 있는 하나 이상의 작업이 존재
GitHub Action으로 할 수 있는 것
- Push 발생되면 아래 단계들이 자동으로 실행
( 1. GitHub Action 개념, 기능 (CI/CD) 에서는 UnitTest까지 진행)- Build
- Unit Test
- Archive
- ipa 생성, Git에 Artifacts 형식으로 업로드 or 앱스토어에 ipa파일 업로드
끝!