[SeSAC] August 2, 2023

✔︎ 오늘의 정리

  • guard case let / if case let
  • reloadRows
  • awakeForNib
  • modal + fullScreen으로 화면 전환 시 dismiss 방법
  • ViewController 내부에서 부분적으로 CollectionView / TableView 구현하기

 


guard case let / if case let

열거형에서 switch문 대신 사용할 수 있다. 

 

 

enum Media {
  case book(title: String, author: String, year: Int)
  case movie(title: String, director: String, year: Int)
  case website(urlString: String)
}

let book = Media.book(title: "The Fault in Our Stars", author: "John Green", year: 2012)

 

 

 

- if case let

 

if case let Media.book(title, _, _) = book {
    print("This is a book named \(title)")
}

// This is a book named The Fault in Our Stars

위 코드는 아래 switch문을 대체한 거라고 볼 수 있다.

 

 

switch book {
  case let Media.book(title, _, _):
    print("This is a book named \(title)")
  default: ()
}

 

그럼 왜 그렇게 쓰는데? 하고 묻는다면...

하나의 조건만 체크할 건데, 굳이 switch문을 써 줄 필요가 없어서 그렇다고 봐도 될 것 같다.

if case let~ 보다 코드가 번거로워지기도 하니까.

 

 

 

 

- guard case let

let movie = Media.movie(title: "Carol", director: "Todd Haynes", year: 2015)

func hello(element: Media) {
    guard case let Media.movie(title, _, _) = element else {
        print("not exist")
        return
    }
    print("The movie named \(title) is exist")
}

hello(element: book)
// not exist
hello(element: movie)
// The movie named Carol is exist

guard case let의 경우에는 이후 지정한 변수를 특정 범위 내에서 사용할 수 있기 때문에 사용한다.

다른 예시를 보면 주로 데이터 통신을 할 때 자주 사용하는 모양이다.

 

관련 블로그 링크 글을 아래로 달아놓겠다.

 

 

 

https://alisoftware.github.io/swift/pattern-matching/2016/05/16/pattern-matching-4/

 

Pattern Matching, Part 4: if case, guard case, for case

Making your Swift code more fun 🎉, magical ✨ and crunchier 👌

alisoftware.github.io

 

 

 

 

 

reloadRows(at:with:)

etc-image-0

tableView나 CollectionView에서 사용할 수 있는 메서드로, reloadData()와 비슷하다. 

하지만, 굳이 reloadRows()를 쓰는 이유가 있다면 아무래도 매번 화면 전체를 전환하는 reloadData()보다 매개변수에서 선택한 셀의 data만 reload를 해 주면 불필요하게 앱이 많이 동작하는 걸 막을 수 있다.

 

 

 

https://developer.apple.com/documentation/uikit/uitableview/1614935-reloadrows

 

reloadRows(at:with:) | Apple Developer Documentation

Reloads the specified rows using the provided animation effect.

developer.apple.com

 

 

 

 

 

 

 

awakeFromNib

어제 삽질하면서 알아낸 친구... 를 오늘 다시 했다. 

어제 정리를 했나? 명확히 기억이 안 나는데 -,- 이 친구 때문에 어제 타입 메서드와 인스턴스 메서드를 정리하게 된 것만 기억이 난다.

아무튼.

 

TableViewController나 CollectionViewController에서 Cell을 재활용할 때 모두 적용해 주어야 하는 설정을 한 번에 적용하기에 좋다.

awakeFromNib은 Collection / TableView로 각 그림들이 로드될 때 실행되기 때문에 그렇다.

모든 인스턴스가 초기화가 모두 된 이후에 awakeFromNib을 실행하므로, Frame이나 Layer, Font 같은 어딘가에 일괄적으로 적용해 주어야 하는 설정을 넣어 주면 편하다. ^_^

 

원래는 각 cell이 만들어질 때 font 설정을 넣었는데 멘토님께 조언을 듣고서 awakeFromNib으로 바꿔 넣어주었다.

 

다만, 주의해야 할 점이 있다면 그냥 Xcode에서 불러와지는대로 불러오면 class method로 불러와지니 class를 빼주자 ,, ,, ^_^

 

 

 

 

 

 

 

modal + fullScreen으로 화면 전환 시 dismiss 방법

하 분명 했떤 것 같은데 기억이 안 나서 한참을 찾았다

진작 정리해 놓을걸~~~!!!!!!

 

일단 dismiss 방법은 두 가지로 나뉜다.

 

1. navigationController를 imbed하여 navigationBarItem을 추가해 주는 경우

 

    // 코드로 화면 옮기기
    @IBAction func searchButtonTapped(_ sender: UIBarButtonItem) {
        
        // 스토리보드 파일 내 뷰 컨트롤러 찾기
        guard let vc = storyboard?.instantiateViewController(identifier: "SearchViewController") as? SearchViewController else {
            return
        }
        
        // 네비게이션 컨트롤러 imbed
        let nav = UINavigationController(rootViewController: vc)
        
        nav.modalPresentationStyle = .fullScreen
        present(nav, animated: true)
    }

바뀌기 전 ViewController의 화면이다.

 

이후, SearchViewController의 코드를 보면...

 

class SearchViewController: UIViewController {

    @IBOutlet weak var detailLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        designInitalSetting()
        addLeftBarItem()
    }
    
    func designInitalSetting() {
        title = "검색"
        detailLabel.text = "상세 검색"
        detailLabel.textAlignment = .center
        detailLabel.font = .boldSystemFont(ofSize: 30)
    }
    
    // 뒤로가기 버튼 추가
    func addLeftBarItem() {
        let xMark = UIImage(systemName: "xmark")
        navigationItem.leftBarButtonItem = UIBarButtonItem(image: xMark, style: .plain, target: self, action: #selector(closeButtonTapped))
        navigationItem.leftBarButtonItem?.tintColor = .black
    }
    
    // 버튼 누르면 하는 동작 구현
    @objc
    func closeButtonTapped() {
        dismiss(animated: true)
    }

}

이런 식으로 되어 있다.

 

 

 

2. 바뀐 화면에서 버튼을 만들어 준 뒤에 평소에는 숨겨 놓고 특정 view에서 호출될 때만 보이게 하기

 

먼저, 바뀐 이후의 뷰 (상세 페이지 뷰)에서 구현된 버튼을 보자.

class DetailViewController: UIViewController {
   
    @IBOutlet weak var closeButton: UIButton!
    @IBOutlet weak var posterImageView: UIImageView!
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var detailLabel: UILabel!
    @IBOutlet weak var plotLabel: UILabel!
    
    @IBOutlet weak var likedButton: UIButton!
   
    @IBOutlet weak var cardView: UIView!
    
    var movie: Movie?
    var hidden: Bool = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        closeButtonChecked()
        designInitalSetting()
        
    }
    
    // close button 눌렀을 때 하는 동작
    @IBAction func closeButtonTapped(_ sender: UIButton) {
        dismiss(animated: true)
    }
    
    // 버튼이 보이면 눌릴 수 있도록 하고, 안 보이면 눌리지 않도록 함
    func closeButtonChecked() {
        closeButton.isHidden = hidden
        if closeButton.isHidden {
            closeButton.isEnabled = false
        } else {
            closeButton.isEnabled = true
        }
    }
    
    ... ...
}

 

이런 식으로 되어 있다!

 

이후, 바뀌기 전의 뷰 컨트롤러를 보면...

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let vc = storyboard?.instantiateViewController(identifier: "DetailViewController") as? DetailViewController else { return }
        
        vc.movie = list[indexPath.row]
        // close button을 보이게 해 줌
        vc.hidden = false
        vc.modalTransitionStyle = .coverVertical
        vc.modalPresentationStyle = .fullScreen
        
        present(vc, animated: true)
    }

 

요런 식으로 되어 있다.

 

 

 

첫 번째 화면과 두 번째 화면 구현의 차이는 다음과 같다.

 

etc-image-1etc-image-2
왼쪽이 1번, 오른쪽이 2번이다.

 

 

 

 

 

 

 

ScrollBar 없애기

etc-image-3

한참 찾았다.

인터페이스 빌드 상에서 조기 Indicators에서 체크를 해제해 주면 된다.

 

etc-image-4
비포 / 애프터

깔꼼해진다.

다만, 스크롤바를 없애면 화면 위쪽에 사진 갯수만큼 동그라미를 만들어 주어 스크롤이 가능하다는 걸 알려줘야 할 것 같음.

이 부분은 나중에...

 

 

 

 

ViewController 내부에서 부분적으로 CollectionView / TableView 구현하기

etc-image-5

이렇게 구현하고 싶었다.

위에 배너를 Scretch Header로 구현하고 싶어서 tableViewController로 구현한 건데 결국 못했따 ㅠ,ㅠ

왜케 어려운 거임

코드로는 다들 어케 짜는 거임

나는 왜안대는거임

왜이해를못하는거임??

아무튼... 그래도 비슷하게 만드는 데는 성공해따.

 

 

etc-image-6

 

근데 중간에 삽질을 좀 했어서 일반 뷰 컨트롤러에 테이블뷰나 콜렉트뷰를 어떻게 구현하는지 그 과정을 적어보고자 한다.

 

먼저, 뷰 컨트롤러에 테이블뷰나 콜렉트뷰를 구현하려면 뷰 컨트롤러 위에 올린 테이블뷰나 콜렉트뷰를 아웃렛에 연결해야 한다.

테이블뷰 / 콜렉트뷰가 하나만 들어갈 수 있었던 기존의 CollectionViewController / TableViewController와 달리 ViewController에는 테이블뷰나 콜렉트뷰가 여러 개 들어갈 수 있기 때문에 각자 아웃렛에 연결해 주어야 한다.

 

이후, 뷰 컨트롤러에 특정 프로토콜을 선언해야 한다.

기존의 TableView에는 UITableViewDelegate, UITAbleViewDataSource 프로토콜이, CollectionView에는

UICollectionViewDataSource, UICollectionViewDelegate 프로토콜이 내장되어 있기 때문에 선언할 필요가 없었지만, 뷰 컨트롤러에는 해당 프로토콜이 선언되어 있지 않기 때문에 뷰 컨트롤러에 프로토콜을 선언해 주어야 한다.

이후, TableView / CollectionView에 필요한 핵심 기능을 구현할 함수를 호출할 수 있다.

etc-image-7

나는 TableViewController에 CollectionView를 사용하기 위해서 UICollectionViewDataSource, UICollectionViewDelegate를 선언해 주었다. 또한, 첫 번째로 말한 것처럼 사용할 콜렉트뷰를 아웃렛에 연결해 주었다. ^_^

 

 

다음으로, 콜렉트뷰 / 테이블뷰의 각각의 아웃렛과 프로토콜을 연결해 주어야 한다.

etc-image-8

이걸 안 해서 한참을 헤맸다.

해당 뷰와 프로토콜을 연결해 주고, 이후 Nib을 통하여 셀과 해당 콜렉션뷰를 연결해 주었다.

처음에 nib을 만들어줄 때, nibName에는 연결할 Cell의 이름을, 이후 등록할 때 forCellReuseIdentifier에는 Cell의 identifier를 써 주면 된다.

 

 

근데 잠깐!!!! Cell은 뭔데?

 

프로젝트에 파일을 추가할 때 UITableViewCell / UICollectionViewCell 을 subClass로 선택하여 만든 뒤에 Also create XIB file을 같이 눌러서 만들어주면 좋다.

그럼 해당 셀의 swift파일과 xib파일이 만들어진다!

만들어진 스토리보드 파일에서는 cell의 레이아웃 작업을 해 주면 되고, .swift 파일에는 작업한 라벨이나 버튼을 연결해 주어 이후 데이터를 연결할 수 있도록 한다.

 

이때!!!!!!

Cell identifier를 잘 설정해 주는 걸 잊지 말아야 한다.

 

이번에 정리햇으니 담에는 헤매지말자.

 

이후에는 원래 하던 것처럼 CollectionView / NavigationView를 구현하면 된다.

 

함수 이름이 각각의 뷰 이름인

1. numberOf... // 보일 셀의 갯수 설정

2. cellOf // 셀의 디자인 설정

 

이 method를 찾아서 구현해 주면 된당.

굿굿굿굿굿

 

 

 

 

 

 

'TIL' 카테고리의 다른 글

[SeSAC] August 6, 2023  (0) 2023.08.07
[SeSAC] August 3, 2023  (2) 2023.08.04
[SeSAC] August 1, 2023  (0) 2023.08.01
[SeSAC] July 31, 2023  (0) 2023.08.01
[SeSAC] July 27, 2023  (0) 2023.07.28