Skip to content

bar-d/OP.GGCloneCoding

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 

Repository files navigation

OP.GG CloneCoding README.md

프로젝트 저장소

프로젝트 기간: 2022-10-16 ~ 2022-12-07
팀원: 바드, 수꿍
그라운드롤: GroundRule - Wiki

📑 목차

개발자 소개

바드 수꿍

프로젝트 소개

  • LeagueOfLegends 사용자 전적 검색 어플리케이션 OP.GG 클론 코딩
  • 메인 뷰 및 설정 뷰 구현

개발환경

Target Version

API

Riot Developer API

Architecture

MVVM

  • Model
    • 프로젝트 레벨 비즈니스 로직 처리
  • View
    • 디스플레이 표시
    • ViewModel로의 event 전달
  • ViewModel
    • 프레젠테이션 로직 처리

Clean Architecture

  • 검색하고자 하는 소환사 이름을 ViewModel로 전달
  • ViewModel에서 해당 소환사 이름을 바탕으로 네트워킹 메서드 호출
  • ViewModel의 호출로 인한 UseCase의 네트워킹 메서드 호출
  • UseCase의 호출로 인한 Repository의 네트워킹 메서드 호출
  • Repository의 호출로 인한 APIService 내 실제 네트워킹 작업 실행
  • APIService 네트워킹 결과물을 Repository -> UseCase -> ViewModel로 전달
  • 네트워킹한 데이터를 바탕으로 View를 다시 그리기

키노트 pdf

폴더 구조

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

구현화면

메인뷰

라이트모드 다크모드

설정뷰

라이트모드 다크모드

네트워킹

소환사등록

주요기능설명

Networking

  • 소환사 이름을 바탕으로 기본 소환사 정보(RiotSummonerAPIRequest) 불러오기
  • 기본 소환사 정보 네트워킹 성공시, 소환사 랭크(RiotSummonerRankAPIRequest), 소환사 경기 목록(RiotSummonerMatchListAPIRequest) 불러오기
  • 소환사 경기 목록 네트워킹 성공시, 소환사 최근 10 경기(RiotSummonerMatchAPIRequest) 불러오기
  • 위의 네트워킹 모두 성공시, 현재 게임 버전(DataDragonVersionAPIRequest) 불러오기
  • 현재 게임 버전 네트워킹 성공시, 소환사 프로필 아이콘(DataDragonProfileIconAPIRequest), 사용 챔피언 아이콘(DataDragonChampionIconAPIRequest) 불러오기

🚀TroubleShooting

네트워크 : cache 구현

문제상황

  • RiotAPIService의 소환사의 기본 정보에서부터 DataDragonAssetChampionIcon에 이르기까지 네트워킹 작업을 모두 구현한 이후 이를 실행하던 가운데, 서버로부터 불러오는 데이터의 양이 많아지다보니, 모든 데이터를 네트워킹할 때까지 사용자가 대기하는 시간이 길어지는 문제점을 발견
  • UX 측면에서 매우 불편하다 판단하여 네트워킹 시간을 최소화하는 방법을 궁구할 필요를 느낌

해결방법

  • 네트워킹 비용을 최소화하기 위하여 cache를 사용하기로 결정

    • 현재, 소환사 검색은 보통 일면식이 없는 소환사보다는 본인을 포함하여 자주 접한 소환사를 검색하는 경향 예상
    • 이는 이전에도 검색한 정보를 또 다시 검색할 수 있다는 의미
    • 이를 네트워킹이 아닌 기존 캐시에 접근한다면 자원을 훨씬 절약함과 동시에 UX 만족도를 높일 수 있다 판단
    • 특히, 나의 소환사의 경우에는 보통 자신의 게임 아이디를 설정해놓기 때문에 무엇보다도 캐싱이 필요한 부분
  • 캐싱 방법으로 CoreData 방식 수용

    • 이번 어플리케이션에서 다루고자하는 정보는 일회성보다는 다회성의 성격을 더 띄기 때문에 메모리 캐시보다는 디스크 캐시가 더욱 필요한 영역이라고 판단
    • UserDefaultsCoreData를 각각의 기준을 바탕으로 판단
      • 현재 네트워킹해서 가져오는 데이터는 작은 데이터인가, 큰 데이터인가
      • 전역적으로 접근해야할 필요가 있는가
      • 속도가 중요한 작업인가
      • 동기화 처리 이슈의 중요도는 어느 정도인가 (Thread safeness)
      • ImageArchiving 하는 것이 옳은 선택인가
      • 오버헤드가 발생하는가 (사용 기능에 비해 무거운 저장소를 사용하는가)
      • 관계형 데이터세트가 필요한가
      • 데이터 필터링이 필요한가
    • SummonerInformation, SummonerRank, SummonerMatchList 등의 네트워킹 데이터를 CoreData의 Entity로 별도 관리
  • CoreData 적용을 통한 네트워킹 구조 변경

    기존 네트워킹 구조
    • 한번 소환사 검색을 한 이후라면, 소환사가 게임을 하지 않는한 정보는 변하지 않음을 발견
    • 즉, 소환사 경기목록을 중심으로 변화가 있는지 살펴보고, 변화가 없다면 이전의 네트워킹 데이터를 사용
    • 아이콘 이미지 또한 게임 버전이 바뀌지 않는 이상 변하지 않음
    CoreData 적용 네트워킹 구조
    • 네트워킹은 전적갱신을 할 때, 혹은 해당 데이터가 존재하지 않을 때, 나아가, 소환사 최근 경기 목록이 캐시 데이터와 차이가 있으면 네트워킹을 하는 방식으로 개선
    • 추후 적용 예정

결과

네트워킹 캐싱

SettingView : StickyHeaderView 구현

문제상황

처음 해당 설정 뷰의 타이틀 뷰가 LargeTitle 처럼 나타나고, 아래로 스크롤을 하면 스크롤의 높이에 맞춰 LargeTitle이 위로 사라지고 네비게이션 바 타이틀 위치에 알파값이 조정되면서 타이틀이 나옴

처음 생각은 UINavigationBarLargeTitle을 통해 해줄 수 있을거라 생각
하지만 처음 생각과는 다르게 뜻대로 되지 않아서 Custom Navigation Bar를 구현 결정

Custom Navigation Bar를 구현한다 했지만, 어떤식으로 구현해야 할지 전혀 감을 못잡음

여러 방법으로 구글링을 시도하고, 기존 핸드폰에 깔려있는 어플들을 보면서 비슷한 사례를 찾다가 StickyHeader라는 키워드를 발견하고 현재 뷰에 적합한 사례를 찾음

참고 블로그: https://velog.io/@annapo/iOS-Sticky-Header-구현하기

해결방법

UI 구성 구현된 UI
  • 설정 뷰의 전체적인 UI구성은 위 그림과 같음 StickyHeaderView를 해당 UI를 구현해주기 위해서는 HeaderView, StickyHeaderView, ScrollView가 필요(tableViewtabBar는 구현된 상태)

  • HeaderView

    먼저 titleLabel을 가지고 있는 HeaderView를 구현
    HeaderView에서 동적으로 변경해줘야 하는 것을 titleLabel의 알파값 titleLabel의 알파값을 변경해줄 수 있는 메서드를 public 메서드로 구현

  • StikcyHeaderView

    HeaderView를 구현했다면 StickyHeaderView를 구현 우리가 StickyHeaderView에게 원하는 dynamic autolayouttopConstraint -> 스크롤에 따라 그만큼의 값이 더해진 topConstraint를 구해야 함

  • TableView

    ScrollView 내부에 TableView를 가지고 있으므로 테이블 뷰는 컨텐츠 자체 사이즈로 높이를 가지고 있고 자체 스크롤을 막고 ScrollView의 스크롤로 컨텐츠를 위아래로 움직일 수 있게끔 구현해야 함 viewWillLayoutSubviews 메서드를 재정의해 테이블뷰 height을 테이블 뷰 컨텐츠 사이즈로 설정

  • ScrollView

    ScrollViewDelegate를 이용해 스크롤에 따라 dynamicAutolayout 설정ScrollView.contentOffset.yheaderViewStickyHeaderView의 높이 차이만큼을 더하여 stickyHeaderViewtopConstraint에 제약을 동적으로 설정

    다만 스크롤을 위로 할 때는 topConstraint를 0으로 제한 위로 스크롤을 할 때는 topConstraintdynamic autolayout이 필요없음 아래로 스크롤 할 때도 마찬가지로 topConstraintHeaderViewStickyHeaderView 높이 차이만큼만 움직이면 되므로 HeaderView 높이만큼 제한

    scrollViewDidScroll 메서드에서 위에서 계산한 대로 움직이게끔 구현 topConstraint의 값을 HeaderView 높이로 나누면 HeaderViewtitleLabel의 알파값도 0에서 1만큼 StickyHeaderView가 올라가는 만큼 동적으로 변경

    주의해야할 점은 StickyHeaderViewHeaderView의 차이만큼 scrollviewcontentInset을 설정해주어야 StickyHeaderView와 같이 변화가 일어남

SettingView : StickyHeaderView와 TableView간 스크롤 오작동

문제상황

  • 위로 스크롤 할 시, Sticky HeaderView가 사라짐과 동시에 scrollViewTableView 또한 사라지기 시작
문제의 UI

해결방법

  • 목표 화면은 설정과 로그인이 위로 스크롤 할 시에는 붙어서 같이 위로 이동하고, 아래로 스크롤 할 시, TableView만 스크롤이 이루어졌음

  • 이에, TableView가 바로 사라지지 못하게, TableViewinset을 설정하여, 어느정도 TableView의 내용물(cell)이 어느정도 올라간 후에야 사라지도록 설정

  • 이에 따라, 기존의 scrollViewtop constantheaderView Max Height에서 시작했는데, Min Height로 수정하고, 대신 inset(Max Height - Min Height)으로 설정하여 이를 보강

SettingView : Custom Modal ViewController 구현

문제상황

  • 언어 선택이나 기본 테마 설정 셀을 선택했을 때는 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이면 viewbackgroundColor를 알파 값을 주고 mainView.frame.origin.y를 0에서 view의 1/3만큼 애니메이션으로 올려줌

About

opgg어플을 클론코딩하는 프로젝트

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages