Netflix Clone으로 알아보는 Code Base #01

Flamozzi·2023년 3월 15일
0
post-thumbnail

팔로잉 강의

iOS Development Course - Use Swift 5 and UIKit to Build a Netflix Clone

강의 선택 이유

  • 최신 Swift 5를 사용하고 있음
  • Code Base를 채택하고 있음
  • 친숙한 App인 Netflix의 Clone을 만들기에, 앱 구성에 이해가 빠를 것으로 예상됨

유의 사항

  • 본 포스트 작성자는 지금까지 SwiftUI를 사용하여 앱 개발을 해 왔으며, UIKit을 사용한 앱 개발 경험이 없다. 따라서 오류가 존재할 수 있다. (댓글로 알려주시면 수정하겠습니다 🙂)
  • 단순 강의 타이핑을 따라 치는 것이 아닌, Netflix Clone을 만들어 가는 과정에서 Code Base의 원리와 각 구현 요소의 이유에 대해 집중한다.
  • 본 포스트에서는 원본 강의 상의 모든 코드를 다루지 않는다. 따라서 포스트 상단에 링크한 원본 강의를 수강하며 본 포스트를 참고한다면 도움이 될 것으로 예상된다.
  • 'Netflix Clone 개발 일지' 시리즈는 포스트 작성자가 Code Base 기반의 앱 개발 접근 법에 대해서 빠르게 학습하기 위해 작성하는 시리즈이다. 따라서 포스트 작성자의 학습 편향이 다소 존재할 수 있다.
  • 원본 강의를 통해 학습한 내용들은 추후에 별도의 포스트로 자세하게 다룰 가능성이 있다.
  • 많은 블로그와 자료들을 참고하여 본 포스트를 작성하며, 참고한 모든 링크는 하단 References에 추가된다. 따라서 보다 정확한 지식은 원본 포스트를 참고하는 것을 권장한다.

본 포스트에서 다루는 강의상 챕터

  • Introduction and App Demo
  • Creating new Xcode Project
  • Creating MainTabBarViewController
  • Setting HomeViewController TableView
  • Setting home TableViewCell and it's CollectionView

왜 Storyboard가 아닌 Code Base인가?

Storyboard는 결과물을 예측하기 쉬우며, 소스코드를 일일이 파악하지 않아도 UI를 확인할 수 있다는 장점이 있다. 하지만 협업에서 충돌 문제가 발생할 가능성이 크며, 앱이 커질수록 가독성이 떨어져 코드 리뷰가 어렵다는 단점이 존재한다.

Code Base로 작업할 시, 협업에서의 충돌 문제로부터 Storyboard에 비해 자유로운 편이며, 재사용성 또한 높다. Storyboard에 비해 숙련되기까지 어렵다는 단점이 존재하지만, 작업 전체에 통제감을 줄 수 있기 때문에 현업에서는 Code Base로 작업을 하는 경우가 많다.

개인적으로도 SwiftUI에 익숙하기 때문에 코드를 베이스로 하는 작업이 매력적으로 느껴졌다.

UITableView의 DataSource, Delegate

//  HomeViewControllr.swift

import UIKit

class HomeViewController: UIViewController {
    
    // 클로저 패턴
    private let homeFeedTable: UITableView = {
        let table = UITableView(frame: .zero, style: .grouped)
        table.register(CollectionViewTableViewCell.self, forCellReuseIdentifier: CollectionViewTableViewCell.identifier)
        return table
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        // 스토리 보드 없이 레이아웃을 구성할 때, 뷰 위에 다른 뷰를 추가하는 경우 addSubview()를 사용한다.
        view.addSubview(homeFeedTable)
        
        homeFeedTable.delegate = self
        homeFeedTable.dataSource = self
        
        homeFeedTable.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: 450))
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        homeFeedTable.frame = view.bounds
    }
}

extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 20
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let cell = tableView.dequeueReusableCell(withIdentifier: CollectionViewTableViewCell.identifier, for: indexPath) as? CollectionViewTableViewCell else {
            return UITableViewCell()
        }
        
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 200
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 40
    }
}

DataSource: 데이터를 받아 이를 뷰에 그려주는 역할 → 무엇을 어떻게 보여줄 것인가?
Delegate: 동작을 제시 → 사용자가 보이는 것들 중 무언가에 대한 액션을 취한다면 그에 대한 동작 수행

UITableViewDataSource

  • DataSource는 TableView를 생성하고 수정하는 데 필요한 정보를 테이블 뷰 객체에 제공한다.
  • DataSource는 데이터 모델의 delegate로, TableView의 시각적 모양에 대한 최소한의 정보를 제공한다.
  • UITableView 객체에 섹션과 행의 수를 알려주며, 행 삽입, 삭제 및 재정렬 기능을 선택적으로 구현할 수 있다.

UITableViewDelegate

  • Delegate는 TableView의 시각적인 부분 수정, 행의 선택 관리, 엑세서리 뷰 지원, 개별 행 편집을 도와준다.
  • Delegate 메소드를 활용하면 TableView의 세세한 부분을 조정할 수 있다.

간단하게 DataSource는 "보여주는" 것들을 담당하며, Delegate는 어떤 행동에 대한 "동작"을 제시한다. DataSource가 데이터를 받아 뷰를 그려주는 역할이라면(뭘 어떻게 보여줄래?), Delegate는 사용자가 보이는 부분 중 어떤 것을 클릭하거나 어떤 행동을 했을 때, 그 행동에 대한 동작을 수행하게 된다.(이 row를 클릭하면 뭘 할래?)

Frame과 Bounds의 차이

Fram과 Bounds 모두 UIView의 instance property이다. Frame과 Bounds 모두 타입은 CGRect 이다. 따라서 frame과 bounds는 사각형으로 그려지기 때문에 origin(x 좌표, y 좌표)과 size(width, height)를 가진다.

frame: frame은 SuperView(상위뷰)의 좌표시스템안에서 View의 위치와 크기를 나타낸다.

bounds: View의 위치와 크기를 자신만의 좌표시스템안에서 나타낸다.

그렇다면 언제 무엇을 사용하는가?

frame은 View의 위치나 크기를 설정할 때 사용한다.
bounds는 View 내부에 그림을 그릴 때, trnasformation 후 View의 크기를 알고 싶을 때, 하위 View를 정렬하는 것과 같이 내부적으로 변경하는 경우에 사용한다.

frame은 단순히 UIView와 동일한 위치나 크기가 아니라 view가 회전되었을 때도 감쌀 수 있는 사각형을 의미한다.
bounds를 옮기면 마치 subview가 움직이는 것 처럼 보이는데 이 현상은 superview의 frame은 변하지 않고 그대로 있되, subview들을 그리는 좌표계의 기준이 기준이 달라졌기 때문이다.
frame의 위치를 변경하면 뷰가 이동하지만, bounds의 경우 뷰포트가 이동한다. 50pt 만큼 x 좌표를 증가시키면 실제로는 50pt 만큼 왼쪽으로 이동한 것 처럼 보인다.

대표적으로 스크롤 뷰를 사용할 때 bounds가 사용된다. 스크롤 뷰는 스크롤 될 때마다 스크롤 뷰의 bounds를 업데이트 한다. 만약 왼쪽으로 스와이프해서 스크롤하면 bounds의 x 좌표가 증가한다.

ViewController Life Cycle

UIViewController는 UIKit으로 구성된 앱의 뷰 계층관계를 관리하고 뷰를 그리는 로직을 담고 있다. (앱 화면의 콘테츠를 표시하는 로직과 담당하는 객체이다.)

앱에는 하나 이상의 ViewController가 존재하며, 각가의 ViewController는 생명주기를 가지고 있다. 생명주기는 각가의 ViewController가 화면에 나타나거나 사라지는 것을 의미한다.

그림의 흐름에서 Appearing은 화면에 뷰가 나타나는 중을 나타내며, Appeared는 뷰가 화면에 나타나는게 완료된 상태, Disappearing은 뷰가 화면에서 사라지는 중, Disappeared는 뷰가 화면에서 사라진 상태를 의미한다.

각각의 상태로 변경될 때 그림에 표시된 method가 iOS 시스템에 의해 자동으로 호출된다.
순환적으로 발생하기 때문에 화면 전환에 따라 발생해야 하는 로직을 적절한 곳에서 실행시켜야 한다.

viewDidLoad()

  • 그림에서는 보이지 않지만 ViewController를 생성했을 때 자동으로 생성되어 있는 method 이며, 해당 뷰가 메모리에 로드되었을 때 호출되는 method 이다.
  • ViewController class가 생성될 때 가장 먼저 실행되며, 특별한 경우가 아니라면 딱 한 번 실행되기 때문에 초기화 할 때 사용 할 수 있다.

viewWillAppear(_:)

  • 뷰가 생성되기 직전에 실행 되기 때문에 뷰가 나타나기 전에 실행해야 하는 작업들을 여기서 할 수 있다. 예를 들면, 화면이 보여지지 않는 동안 변경된 데이터 업데이트 등이 이에 해당한다.
  • ViewController가 화면에 나타날 때마다 반복 실행 된다.

viewDidAppear(_:)

  • ViewController에게 해당 뷰가 뷰의 계층 구조에 추가되었음을 알리는 method 이며, 뷰가 화면에 나타났음을 의미한다.
  • 뷰가 생성되고 난 뒤에 실행 되기 때문에, 뷰가 화면에 나타난 즉시 발생해야 하는 작업을 여기에 작성하면 된다. 데이터를 받아서 화면에 뿌려주거나 애니메이션 등의 작업을 하는 로직을 위치시킬 수 있다.

viewWillDisappear(_:)

  • ViewController에게 해당 뷰가 뷰의 계층 구조에서 제거되려 함을 알리는 method 이다.
  • 뷰가 사라지기 직전에 실행 되며, 뷰가 생성된 뒤 발생한 변화를 이전 상태로 되돌리기 좋은 시점이다.
  • 최종적으로 데이터를 저장하는 작업을 해당 메서드에 정의한다.

viewDidDisappear(_:)

  • ViewController의 뷰가 뷰 계층에서 사라진 뒤에 호출되는 method 이다.
  • 뷰가 사라지고 난 뒤에 실행 되며, 뷰가 사라지는 것과 관련된 작업이 위치한다.

진행 상황

Neflix를 사용해본 사람이라면, 바로 Home 화면의 그것이 떠오를 것이다.
클론 코딩은 장단점이 참 명확하기에 장점만을 잘 취할 수 있도록 더욱 UIkit 및 Code Base의 앱 개발 지식에 대한 정리를 잘 해두어야겠다. 잘 활용한다면 충분히 좋은 학습 방법이라고 생각한다.
다음 포스트에서는 Table의 HeaderView를 디테일하게 작업하는 것에서부터 생기는 궁금증들을 이어서 정리 할 계획이다.


References

profile
개발도 하고, 글도 적고

0개의 댓글