deprecated/꼼꼼한 재은씨 시리즈

App Thinning & Slicing ( 앱 씨닝과 슬라이싱) + 튜토리얼 코드 리뷰

lgvv 2021. 3. 28. 20:31

@2x @3x 등 앱에 모두 넣어두면 파일 크기가 커져 디바이스에 부담이 갈 수도 있다.

 

앱 씨닝이란 개념은 ios9부터 앱의 용량을 줄이기 위한 목적으로 만들어 졌다.

장점 : 사용자의 디바이스에 최적화 된 앱을 제공할 수 있고, 설치 및 업데이트 속도가 빠를 뿐 아니라 훨씬 적은 공간을 차지하는 결과를 가져오게 된다.

 

현재 공개된 앱 씨닝 관련 기술은

1. 비트코드 (bit code)

2. 온 디맨드 리소스 (on demand resource)

3. 슬라이싱 ( slicing)

 

슬라이싱 - 하나의 앱을 각각의 ios 기기에 최적화된 형태로 설차히여 여러 버전을 쪼개어 제공하는 것을 의미

개발자가 해야하는 것은 이미지를 사용하는 방식을 변경하는 것 뿐

이미지를 에셋 카탈로그에 등록해 놓고 사용하는 방식으로만 변경

에셋 카탈로그를 사용하여 이미지를 등록하고 관리하는 방법에 대해 알아보자

이렇게 설정하고

 

유틸 가서 만든 후에 사용하기 

 

근데 이건 굳이 내가 코드를 올리기 보다 완성본을 직접 참고하자.

 

++ 스토리 보드 분리 후 튜토리얼 코드도 여기다가 작성하겠음

 

참고로 튜토리얼 만드는거 완벽하게 학습했다기엔 많이 부족한듯.

데이터 저장과 함께 공부하다 보니까 진짜 헷갈리고 어렵게 느껴진다 ㅠㅠ

 

 

유틸 파일 따로 만들어서 익스텐션 후 튜토리얼 사용

 

이렇게 하는 이유는 스토리 보드를 분리하였기 때문에 튜토리얼 스토리 보드를 따로 참조하고 통합적으로 다른 곳에서 사용하기 위함

익스텐션이라는 것을 잊지말기. 또한 익스텐션으로 했기 때문에 객체 굳이 또 만들 필요 없는 장점

 

아래 코드를 천천히 보면 이해가 간다.

그리 어려운 로직은 아니니 걱정 노노하고 봐라

//
//  TutorialMasterVC.swift
//  MyMemory
//
//  Created by Hamlit Jason on 2021/03/28.
//

import UIKit

class TutorialMasterVC: UIViewController, UIPageViewControllerDataSource{
    
    var pageVC : UIPageViewController!
    
    // 콘텐츠 뷰 컨트롤러에 들어갈 타이틀과 이미지
    var contentTitles = ["Step1","Step2","Step3","Step4"]
    var contentImages = ["Page0","Page1","Page2","Page3"]
    
    @IBAction func close(_ sender: Any) {
        let ud = UserDefaults.standard
        ud.set(true,forKey: UserInfoKey.tutorial)
        ud.synchronize()
        
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }
    override func viewDidLoad(){
        
        // 페이지 뷰 컨트롤러 객체 생성하기
        self.pageVC = self.instanceTutorialVC(name:"PageVC") as? UIPageViewController //
        self.pageVC.dataSource = self // 생성된 인스턴스의 데이터소스를 셀프로 설정하여 데이터 소스 구성에 필요한 메소드가 현재의 클래스 인스턴스 자신에게 구현되어 있다는 것을 알려준다
        
        // 페이지 뷰 컨트롤러의 기본 페이지 지정
        let startContentVC = self.getContentVC(atIndex:0)!
        self.pageVC.setViewControllers([startContentVC], direction: .forward, animated : true) // 이 메소드는 페이지 뷰 컨트롤러가 실행되면 사용자의 스와이프 액션이 있기 전까지 임의의 컨텐츠 뷰를 기본값으로 출력하고 있어야 하는데, 이 기본값은 이 메소드를 통해 사용된다.
        
        // 페이지 뷰 컨트롤러의 출력 영역 지정
        self.pageVC.view.frame.origin = CGPoint(x:0, y:0)
        self.pageVC.view.frame.size.width = self.view.frame.width
        self.pageVC.view.frame.size.height = self.view.frame.height - 50 // 듀토리얼이 상단에서 50정도 덜 나와야 모달식으로 듀토리얼로 느낄거니까
        
        // 페이지 뷰 컨트롤러 마스터 뷰 컨트롤러의 자식 뷰 컨트롤러로 설정
        self.addChild(self.pageVC) // 페이지 뷰 자식 컨트롤러로 등록
        self.view.addSubview(self.pageVC.view) // 컨트롤러의 뷰를 현재의 서브 뷰로 추가한 다음
        self.pageVC.didMove(toParent: self) // 자식 뷰 컨트롤러에게 부모 뷰 컨트롤러가 바뀌었음을 알려주기
        // 3단 과정 외우기
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        /*
         현재의 컨텐츠 뷰 컨트롤러보다 앞쪽에 올 컨텐츠 뷰 컨트롤러 객체
         즉, 현재의 상태에서 앞쪽으로 스와이프 했을 때, 보여줄 컨텐츠 뷰 컨트롤러 객체
         */
        
        guard var index = (viewController as! TutorialContentsVC).pageIndex else {
            return nil
        }
        
        guard index > 0 else { // 현재의 인덱스가 맨 앞이라면 nil을 반환하고 종료
            return nil
        }
                
        index -= 1 // 현재의 인덱스에서 하나 뺌(즉, 이전페이지의 인덱스)
        return self.getContentVC(atIndex: index)
        
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        /*
         현재의 컨텐츠 뷰 컨트롤러보다 뒤쪽에 올 컨텐츠 뷰 컨트롤러 객체
         즉, 현재의 상태에서 뒤쪽으로 스와이프 했을 때, 보여줄 컨텐츠 뷰 컨트롤러 객체
         */
        
        guard var index = (viewController as! TutorialContentsVC).pageIndex else {
            return nil
        }
        
        index += 1 // 현재의 인덱스에서 하나 뺌(즉, 이전페이지의 인덱스)
        
        guard index < self.contentTitles.count else { // 인덱스는 항상 배열 데이터의 크기보다 작아야 한다.
            return nil
        }
                
        
        return self.getContentVC(atIndex: index)
    }
    
    func getContentVC(atIndex idx : Int) -> UIViewController? {
        
        guard self.contentTitles.count >= idx && self.contentTitles.count > 0 else {
            // 인덱스가 데이터 배열 크기 범위를 벗어나면 nil 반환
            return nil
        }
        /*
         instanceTutorialVC 는 Utils.swift에 익스텐션으로 추가된 메소드
         */
        
        guard let cvc = self.instanceTutorialVC(name: "ContentsVC") as? TutorialContentsVC else { // ContentsVC 라는 스토리보드 아이디를 가진 뷰 컨트롤러의 인스턴스를 생성하고 캐스팅한다.
            return nil
        }
        // 콘턴츠 뷰 컨트롤러의 내용을 구성
        cvc.titleText = self.contentTitles[idx]
        cvc.imageFile = self.contentImages[idx]
        cvc.pageIndex = idx
        return cvc
    }
    
    
    // 페이지 인디케이터를 위한 메소드 - 필수
    func presentationCount(for pageViewController: UIPageViewController) -> Int { // 출력한 페이지가 모두 몇개인지
        return self.contentTitles.count
    }
    
    // 페이지 인디케이터를 위한 메소드 - 필수
    func presentationIndex(for pageViewController: UIPageViewController) -> Int { // 최초에 출력한 컨텐츠 뷰의 인덱스 번호를 알려줌
        return 0
    }
}