프로젝트 기간: 2022-10-16 ~ 2022-12-07
팀원: 바드, 수꿍
그라운드롤: GroundRule - Wiki
바드 | 수꿍 |
---|---|
- LeagueOfLegends 사용자 전적 검색 어플리케이션 OP.GG 클론 코딩
- 메인 뷰 및 설정 뷰 구현
Model
- 프로젝트 레벨 비즈니스 로직 처리
View
- 디스플레이 표시
- ViewModel로의 event 전달
ViewModel
- 프레젠테이션 로직 처리
- 검색하고자 하는 소환사 이름을
ViewModel
로 전달 ViewModel
에서 해당 소환사 이름을 바탕으로 네트워킹 메서드 호출ViewModel
의 호출로 인한UseCase
의 네트워킹 메서드 호출UseCase
의 호출로 인한Repository
의 네트워킹 메서드 호출Repository
의 호출로 인한APIService
내 실제 네트워킹 작업 실행APIService
네트워킹 결과물을Repository
->UseCase
->ViewModel
로 전달- 네트워킹한 데이터를 바탕으로
View
를 다시 그리기
Detail
└── OP.GGCloneCoding
└── OP.GGCloneCoding
├── Application
├── Builder
├── Data
│ ├── Network
│ │ └── DataMapping
│ └── Repositories
├── Domain
│ ├── Entities
│ ├── Interface
│ │ └── Repositories
│ └── UseCases
├── Extension
├── Infrastructure
│ └── Network
│ ├── Common
│ └── RiotAPI
├── PreviewHelpers
├── Protocol
├── Resource
│ ├── Assets.xcassets
│ ├── LaunchScreen.storyboard
│ ├── Info.plist
│ └── LoadingIndicator.json
└── Scene
├── Common
│ ├── Section
│ ├── View
│ └── ViewModel
├── Main
│ ├── SectionView
│ │ ├── ChampionTier
│ │ │ └── PositionTabBar
│ │ ├── ChampiosAndSkinOnSale
│ │ ├── FavoriteChampion
│ │ ├── FavoriteSummoner
│ │ │ └── SummonerSearch
│ │ ├── MoreInformation
│ │ ├── MySummoner
│ │ │ ├── SelectedSummoner
│ │ │ │ ├── View
│ │ │ │ └── ViewModel
│ │ │ ├── SummonerRegister
│ │ │ │ ├── View
│ │ │ │ └── ViewModel
│ │ │ └── UnselectedSummoner
│ │ │ └── View
│ │ ├── OtherGames
│ │ ├── PatchNote
│ │ └── TodayTMI
│ ├── SummonderDetail
│ │ ├── AdditionalInformation
│ │ ├── SummonerInformationTableView
│ │ ├── SummonerInformationTableViewCell
│ │ │ └── LeftView
│ │ ├── TierView
│ │ ├── TopView
│ │ └── ViewModel
│ └── View
└── Settings
├── SectionCell
└── View
├── LanguageSelection
└── ThemeSelection
라이트모드 | 다크모드 |
---|---|
라이트모드 | 다크모드 |
---|---|
소환사등록 |
---|
- 소환사 이름을 바탕으로 기본 소환사 정보(
RiotSummonerAPIRequest
) 불러오기 - 기본 소환사 정보 네트워킹 성공시, 소환사 랭크(
RiotSummonerRankAPIRequest
), 소환사 경기 목록(RiotSummonerMatchListAPIRequest
) 불러오기 - 소환사 경기 목록 네트워킹 성공시, 소환사 최근 10 경기(
RiotSummonerMatchAPIRequest
) 불러오기 - 위의 네트워킹 모두 성공시, 현재 게임 버전(
DataDragonVersionAPIRequest
) 불러오기 - 현재 게임 버전 네트워킹 성공시, 소환사 프로필 아이콘(
DataDragonProfileIconAPIRequest
), 사용 챔피언 아이콘(DataDragonChampionIconAPIRequest
) 불러오기
RiotAPIService
의 소환사의 기본 정보에서부터DataDragonAsset
의ChampionIcon
에 이르기까지 네트워킹 작업을 모두 구현한 이후 이를 실행하던 가운데, 서버로부터 불러오는 데이터의 양이 많아지다보니, 모든 데이터를 네트워킹할 때까지 사용자가 대기하는 시간이 길어지는 문제점을 발견- UX 측면에서 매우 불편하다 판단하여 네트워킹 시간을 최소화하는 방법을 궁구할 필요를 느낌
-
네트워킹 비용을 최소화하기 위하여
cache
를 사용하기로 결정- 현재, 소환사 검색은 보통 일면식이 없는 소환사보다는 본인을 포함하여 자주 접한 소환사를 검색하는 경향 예상
- 이는 이전에도 검색한 정보를 또 다시 검색할 수 있다는 의미
- 이를 네트워킹이 아닌 기존 캐시에 접근한다면 자원을 훨씬 절약함과 동시에 UX 만족도를 높일 수 있다 판단
- 특히, 나의 소환사의 경우에는 보통 자신의 게임 아이디를 설정해놓기 때문에 무엇보다도 캐싱이 필요한 부분
-
캐싱 방법으로
CoreData
방식 수용- 이번 어플리케이션에서 다루고자하는 정보는 일회성보다는 다회성의 성격을 더 띄기 때문에 메모리 캐시보다는 디스크 캐시가 더욱 필요한 영역이라고 판단
UserDefaults
와CoreData
를 각각의 기준을 바탕으로 판단- 현재 네트워킹해서 가져오는 데이터는 작은 데이터인가, 큰 데이터인가
- 전역적으로 접근해야할 필요가 있는가
- 속도가 중요한 작업인가
- 동기화 처리 이슈의 중요도는 어느 정도인가 (
Thread safeness
) Image
를Archiving
하는 것이 옳은 선택인가- 오버헤드가 발생하는가 (사용 기능에 비해 무거운 저장소를 사용하는가)
- 관계형 데이터세트가 필요한가
- 데이터 필터링이 필요한가
SummonerInformation
,SummonerRank
,SummonerMatchList
등의 네트워킹 데이터를 CoreData의 Entity로 별도 관리
-
CoreData 적용을 통한 네트워킹 구조 변경
기존 네트워킹 구조 - 한번 소환사 검색을 한 이후라면, 소환사가 게임을 하지 않는한 정보는 변하지 않음을 발견
- 즉, 소환사 경기목록을 중심으로 변화가 있는지 살펴보고, 변화가 없다면 이전의 네트워킹 데이터를 사용
- 아이콘 이미지 또한 게임 버전이 바뀌지 않는 이상 변하지 않음
CoreData 적용 네트워킹 구조 - 네트워킹은 전적갱신을 할 때, 혹은 해당 데이터가 존재하지 않을 때, 나아가, 소환사 최근 경기 목록이 캐시 데이터와 차이가 있으면 네트워킹을 하는 방식으로 개선
- 추후 적용 예정
네트워킹 | 캐싱 |
---|---|
처음 해당 설정 뷰의 타이틀 뷰가 LargeTitle
처럼 나타나고,
아래로 스크롤을 하면 스크롤의 높이에 맞춰 LargeTitle
이 위로 사라지고
네비게이션 바 타이틀 위치에 알파값이 조정되면서 타이틀이 나옴
처음 생각은 UINavigationBar
의 LargeTitle
을 통해 해줄 수 있을거라 생각
하지만 처음 생각과는 다르게 뜻대로 되지 않아서 Custom Navigation Bar
를 구현 결정
Custom Navigation Bar
를 구현한다 했지만, 어떤식으로 구현해야 할지 전혀 감을 못잡음
여러 방법으로 구글링을 시도하고, 기존 핸드폰에 깔려있는 어플들을 보면서 비슷한 사례를 찾다가
StickyHeader
라는 키워드를 발견하고 현재 뷰에 적합한 사례를 찾음
참고 블로그: https://velog.io/@annapo/iOS-Sticky-Header-구현하기
UI 구성 | 구현된 UI |
---|---|
-
설정 뷰의 전체적인 UI구성은 위 그림과 같음
StickyHeaderView
를 해당 UI를 구현해주기 위해서는HeaderView
,StickyHeaderView
,ScrollView가
필요(tableView
및tabBar
는 구현된 상태) -
먼저
titleLabel
을 가지고 있는HeaderView
를 구현
HeaderView
에서 동적으로 변경해줘야 하는 것을titleLabel
의 알파값titleLabel
의 알파값을 변경해줄 수 있는 메서드를public
메서드로 구현 -
HeaderView
를 구현했다면StickyHeaderView
를 구현 우리가StickyHeaderView
에게 원하는dynamic autolayout
은topConstraint
-> 스크롤에 따라 그만큼의 값이 더해진topConstraint
를 구해야 함 -
ScrollView
내부에TableView
를 가지고 있으므로 테이블 뷰는 컨텐츠 자체 사이즈로 높이를 가지고 있고 자체 스크롤을 막고ScrollView
의 스크롤로 컨텐츠를 위아래로 움직일 수 있게끔 구현해야 함viewWillLayoutSubviews
메서드를 재정의해 테이블뷰height
을 테이블 뷰 컨텐츠 사이즈로 설정 -
ScrollViewDelegate
를 이용해 스크롤에 따라dynamicAutolayout
설정ScrollView.contentOffset.y
에headerView
와StickyHeaderView
의 높이 차이만큼을 더하여stickyHeaderView
의topConstraint
에 제약을 동적으로 설정다만 스크롤을 위로 할 때는
topConstraint
를 0으로 제한 위로 스크롤을 할 때는topConstraint
의dynamic autolayout
이 필요없음 아래로 스크롤 할 때도 마찬가지로topConstraint
는HeaderView
와StickyHeaderView
높이 차이만큼만 움직이면 되므로HeaderView
높이만큼 제한scrollViewDidScroll
메서드에서 위에서 계산한 대로 움직이게끔 구현topConstraint
의 값을HeaderView
높이로 나누면HeaderView
의titleLabel
의 알파값도 0에서 1만큼StickyHeaderView
가 올라가는 만큼 동적으로 변경주의해야할 점은
StickyHeaderView
와HeaderView
의 차이만큼scrollview
의contentInset
을 설정해주어야StickyHeaderView
와 같이 변화가 일어남
- 위로 스크롤 할 시,
Sticky HeaderView
가 사라짐과 동시에scrollView
내TableView
또한 사라지기 시작
문제의 UI |
---|
-
목표 화면은 설정과 로그인이 위로 스크롤 할 시에는 붙어서 같이 위로 이동하고, 아래로 스크롤 할 시,
TableView
만 스크롤이 이루어졌음 -
이에,
TableView
가 바로 사라지지 못하게,TableView
에inset
을 설정하여, 어느정도TableView
의 내용물(cell)이 어느정도 올라간 후에야 사라지도록 설정 -
이에 따라, 기존의
scrollView
는top constant
가headerView Max Height
에서 시작했는데,Min Height
로 수정하고, 대신inset
을(Max Height - Min Height)
으로 설정하여 이를 보강
- 언어 선택이나 기본 테마 설정 셀을 선택했을 때는
modal view
를 띄어줘야 하는데, 기존의 Apple에서 제공하는 방식이 아닌 전체 뷰의 1/3 정도로 띄우고 싶어서custom modal view
를 만들어줌
UI 구성 | 구현된 UI |
---|---|
-
UIViewControllerTransitioningDelegate
,UIViewControllerAnimatedTransitioning
을 활용해custom modal view
를 구현 -
UIViewControllerTransitioningDelegate
: viewController간의 전환을 관리해주는 프로토콜
// present될 때 실행될 애니메이션 메서드
animationController(forPresented:, presenting:, source:) -> UIViewControllerAnimatedTransitioning?
// dismiss될 때 실행될 애니메이션 메서드
animationController(forDismissed:) -> UIViewControllerAnimatedTransitioning?
UIViewControllerAnimatedTransitioning
:customViewController
전환을 해 줄 때 필요한 애니메이션 메서드들이 구현되어 있는 프로토콜
// 애니메이션 지속 시간 메서드
transitionDuration(using:) -> TimeInterval
// 전환 애니메이션 구현부 메서드
animateTransition(using:)
- 모달 뷰로 나타낼 줄 뷰 컨트롤러를 구현
전역변수로
isPresenting
이라는Bool
타입 변수 선언isPresenting
의 값에 따라 애니메이션을 구현isPresenting
의 값이true
이면view
의backgroundColor
를 알파 값을 주고mainView.frame.origin.y
를 0에서view
의 1/3만큼 애니메이션으로 올려줌