친구와 단 둘이서 공유하고 싶은 추억이 있나요?
둘다에서 친구와 함께한 추억을 기록 해 보세요
페이지가 하나씩 채워질 수록 친구와의 관계도 깊어질 거에요
S007 김민주 | S017 박세원 | S027 양승훈 | S053 정지승 |
---|---|---|---|
@doingsquirrel | @ehWld | @yabby1997 | @ralph |
둘다의 실제 동작화면 입니다.🦔
페어링 화면 |
이미지 넣기 |
텍스트 넣기 |
스티커 넣기 |
페이지 보기 |
페이지 필터 |
페이지 수정 |
폰트 변경 |
- 당신의 코드로 친구를 초대해 보세요
- 초대코드를 입력한 사람이 먼저 페이지를 작성할 수 있어요
- 새로고침 버튼을 눌러서 친구와 연결되었는지 확인할 수 있어요
- 하루의 내용을 글과 사진, 스티커로 기록해보세요
- 원하는 속지의 색깔을 골라 다이어리의 분위기를 바꿔보세요
- 좌측 상단의 버튼을 누르면 두가지 레이아웃 모드를 토글할 수 있어요
- 필터 버튼으로 원하는 페이지를 골라보세요
- 각 페이지를 수정하거나 공유할 수 있어요
- 오른쪽 하단 편집 버튼으로 페이지를 수정할 수 있어요.
- 왼쪽 하단 공유 버튼으로 페이지를 이미지로 저장하거나 다른사람과 공유할 수 있어요
- 다이어리 작성을 완료하면 상대방에게 푸시알림이 전달돼요
- 새로고침을 통해 상대방에게 다이어리 작성을 요청할 수 있어요
- 제공되는 다양한 폰트들 중 원하는 폰트를 선택할 수 있어요
- 선택된 폰트로 앱 전반의 기본 폰트가 변경되며, 앱이 종료되어도 기본 폰트 선택이 유지돼요.
둘다에서 사용하고 있는 프로젝트 구조 입니다.
프로젝트를 진행하면서 저희가 시도한 기술적 도전을 소개합니다.
- 다이어리 페이지 캐싱을 위해 데이터베이스를 직접 관리하지 않아도 객체 인스턴스를 통해 CRUD작업을 할 수 있는
CoreData
를 사용하였습니다. - 다이어리 페이지는 디스크에 캐싱하고 이에 대한 메타 데이터를
CoreData
에 캐싱합니다. 다이어리 페이지 데이터를 사용할 때CoreData
와 서버에 기록된 마지막 편집 시간을 비교하고, 이를 통해 서버로부터 다시 다이어리 페이지 데이터를 가져와야 하는지를 판단합니다. 이는 불필요한 통신을 줄여 통신 비용을 감소시키고, 더 나은 사용자 경험을 제공합니다.
- 파이프라인을 통해 계층간 데이터 전달과 비동기 이벤트 처리를 가능하도록 하는
Combine
framework를 사용하였습니다. 애플에서 직접 제공하는 First Party Framework인 만큼 가장 신뢰할 수 있으며,NotificationCenter
와Timer
등 기존의 Swift 비동기 코드와도 통합하기 유리하다는 장점에 따라 이를 선택하였습니다. UIControl
과UIGestureRecognizer
의 이벤트를 위한 커스텀 Publisher와 Subscription 정의해 유저로부터 발생하는 비동기 이벤트에 대해서도Combine
을 활용할 수 있도록 했습니다. 이를 통해 프로젝트 전반의 비동기 이벤트 처리에 있어 통일성과 코드 가독성을 향상시킬 수 있었습니다.
- 비즈니스 로직과 변경이 자주 발생하는 외부의 레이어를 명확하게 분리하여 결합도를 낮추고
ViewController
간의 의존성을 낮추기 위해서 Clean Architecture 기반의 MVVM-C 패턴을 선택했습니다. ViewModel
이Coordinator
의 인터페이스를 통해 Scene을 전환시킬 수 있도록 하고, 각 Scene에 대한 의존성을Coordinator
가 직접 주입하도록 했습니다. 이를 통해ViewController
가 유저 입출력만을 담당하여 단일 책임 원칙을 지킬 수 있도록 했습니다. 이를 통해 각 객체 간의 결합도를 낮추고, 독자적으로 테스트가 가능한 구조로 설계하여 유지보수성을 높일 수 있었습니다.
- iOS 13 버전 이후로 다크 모드 지원하도록 HIG에서 권장하고 있기 때문에, 둘다에서도 완벽한 다크모드를 지원하고자 했습니다.
- 모든 다이어리에 표시될 객체의 각도와 크기 조절을 가능하도록 해, 다이어리를 꾸미는 사용자의 자유도를 높이고자 했습니다. 이를 위해 사용자의 제스처를 인식하여 CGRect, scale, angle 값을 객체에 저장하고, 이를 실제 View에 보여주기 위한 변환 과정에서
CGAffineTransform
을 활용했습니다.
-
시각적인 효과를 더해주기 위해
UIDynamicAnimator
를 활용했습니다 -
중력 효과를 주기 위해서
UIGravityBehavior
를 사용했습니다. -
실제 기기가 받는 중력으로 애니메이션을 구현하기 위해
CoreMotion
을 함께 사용했습니다. -
스티커간 충돌 효과를 주기 위해
UICollisionBehavior
를 사용했습니다. -
스티커에 탄성 효과를 주기 위해
UIDynamicItemBehavior
를 활용했습니다.