내일배움캠프 iOS

UIKit) TIL # 54 앱개발 심화주차 개인과제 - Lv 4,마무리 및 트러블 슈팅

yjuni22 2025. 1. 6. 09:55

깃허브

https://github.com/bryjna07/BookSearchApp

 

과제 안내 및 기획

https://yjuni22.tistory.com/71

 

구현 TIL

Lv 1 ~ 2

https://yjuni22.tistory.com/72

Lv 2

https://yjuni22.tistory.com/73

Lv 3

https://yjuni22.tistory.com/74


트러블 슈팅

문제 : 검색기능이 제대로 되지 않음
- 서치 버튼 클릭 시 Nan error 와 함께 검색기능이 실행되지 않음

 

 

해결과정:

 

해당 에러 서칭

https://stackoverflow.com/questions/67757790/how-to-handle-nan-not-a-number-in-swift-correctly

 

How to handle NaN (Not a number) in Swift correctly?

I have a function that calculates the width of the cells for me based on a CollectionView. This layout is dynamic. In the simulator I repeated the case that the width / height of the CollectionView...

stackoverflow.com

 

어떤 에러인지는 모르겠으나 일단 검색기능이 되지 않기에 관련 구현 코드들을 다시 천천히 살펴보았다.
위의 stackoverflow 에서 보니 API 로 받아오는 데이터를 count 로 셀을 그려주고 있는데

 

UICollectionViewDataSource

   func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if section == 0 {
            return 0
        } else {
            return bookArrays.count
        }
    }

 

이 부분에서 count 에서 (Nan, or not-a-number) 의 에러가 발생하는 건가? 싶어서 확인중

모델의 데이터를 옵셔널로 하지 않은 것이 확인되어 이게 문제인가? 하고 바꾸었다.

 

하지만 알고보니 시뮬레이터에서 마우스로 돋보기를 클릭했을 때 발생하는 오류였다.

 

결과:

 

에러에 관련된 내용은 아니지만

API 모델을 받아오는 경우 없는 데이터도 있을 수 있기 때문에
옵셔널로 처리해 주는 것이 좋다는 것을 리마인드할 수 있었다.


 

트러블 슈팅 #2, Lv 4

문제

 최근검색 섹션을 처음에 보이지 않도록 하는 방법에 대한 고민

 

뷰와 뷰컨트롤러가 분리되어 있는 구조에서, SearchTapView(뷰)에서 recentBookArrays(뷰컨트롤러의 데이터)에 접근하기 어려운 상황 발생

최근검색 섹션을 구현하기 전

 private func createCompositionalLayout() -> UICollectionViewCompositionalLayout {
        return UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in
            
            switch sectionIndex {
                
            case 0:
                return nil
                
            case 1:
                return self.createSearchListSection()
                
            default:
                return nil
            }
        }

 

이미 최근 검색 섹션을 생성하기 전에 대략적인 구조를 구현해두었기 때문에
이를 활용하고 싶었다.

 


해결과정:

 

뷰와 뷰컨트롤러 사이의 데이터를 주고받기 위해 클로저를 활용
SearchTapView에 "최근 검색 데이터의 개수"를 반환하는 클로저(recentBooksCountHandler)를 추가하여 문제 해결

 

 

SearchTapView

final class SearchTapView: UIView {
    
    // 최근 본 책 숫자 넘겨받는 클로저
    var recentBooksCountHandler: (() -> Int)?

 

 

SearchTapViewController

class SearchTapViewController: UIViewController {


   override func viewDidLoad() {
        super.viewDidLoad()
        
        // 최근검색 섹션이 없을 때 관련
        searchTapView.recentBooksCountHandler = { [weak self] in
            return self?.recentBookArrays.count ?? 0
        }

 

 

 

 

SearchTapView 의 레이아웃 메서드

private func createCompositionalLayout() -> UICollectionViewCompositionalLayout {
        return UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in
            
            switch sectionIndex {
                
            case 0:
                // 최근 본 책 0이면 nil 반환
                if let count = self.recentBooksCountHandler?(), count == 0 {
                    return nil
                }
                return self.createRecentBooksSection()
                
            case 1:
                return self.createSearchListSection()
                
            default:
                return nil
            }
        }

 

 

결과:

 

최근 검색 데이터(recentBookArrays)가 없을 때, count가 0 일때
즉 처음 진입 시 "최근 검색" 섹션이 나타나지 않게 되었다.
이런 부분이 MVC의 단점이지 않을까 .. ? 

 


 

Lv 4 최근검색 섹션 구현

RecentBooksCell 을 새로 생성하여 

 

cellForItemAt 에 섹션 0 일때 해당 셀의 모양으로 나오도록 구현하였다.

 

 // 섹션별 셀 데이터
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if indexPath.section == 0 {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RecentBooksCell.id, for: indexPath) as! RecentBooksCell
            
            cell.titleLabel.text = recentBookArrays[indexPath.row].title
            
            // 셀 색상 배열 정의
            let colors: [UIColor] = [
                .systemRed, .systemOrange, .systemYellow, .systemGreen,
                .systemBlue, .systemMint, .systemPink , .systemPurple,
                .systemBrown, .systemGray2
            ]
            
            let colorIndex = indexPath.row % colors.count
            cell.imageView.backgroundColor = colors[colorIndex]
            
            return cell
        } else {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SearchListCell.id, for: indexPath) as! SearchListCell
            
            cell.bookNameLabel.text = bookArrays[indexPath.row].title
            cell.authorNameLabel.text = bookArrays[indexPath.row].authors?.first
            cell.bookPriceLabel.text = "\(bookArrays[indexPath.row].price ?? 0)원"
            
            cell.layer.borderWidth = 2
            return cell
        }
    }

 

색깔을 넣고 싶어서 색상 배열을 만들고 인덱스에 따라 색상이 적용되도록 하였다.

 

 

didSet을 활용해 셀 클릭 시 최근 본 책이 생기도록 구현하였다.

 

  var recentBookArrays: [Document] = []
    
    var recentBooks: Document? {
        didSet {
            configureWithRecentBooks()
        }
    }

   // didSelectItemAt 누르면 recentBooks 에서 didSet 실행
    private func configureWithRecentBooks() {
        guard let book = self.recentBooks else { return }
        self.recentBookArrays.insert(book, at: 0)
        if self.recentBookArrays.count > 10 {
            self.recentBookArrays.removeLast()
        }
        self.searchTapView.searchCollectionView.reloadData()
    }

 

배열의 맨 앞으로 들어가도록 insert, at: 0 을 활용하고
10개가 넘어가면 마지막 것을 지우도록 했다.