책 검색 앱 만들기 (3)

오늘은 네크워크 과정을 한층 더 이해할 수 있는 날이었다.. 지금까지 자꾸 데이터 모델링을 맞게 넣었는데 받아오는 형식이 다르다고 나오니 너무 답답하고 막막했다.

 

그래서 튜터님을 찾아가니 잘못 구현된 점을 바로 캐치하시고 알려주셔서 막히다가 깨달으니 더욱 기억에 남을 수 있는 것 같았다.

그래서 오늘은 책 검색 API를 어떻게 가져오고 데이터를 연결하는지 자세하게 기록을 남기도록 하겠다.


JSON 데이터를 바탕으로 데이터 모델링 잡기

오늘 여기서 데이터 모델링 자체가 잘못되어 있어서 나머지 네트워크 연결들이 잘 되어있어도 제대로 데이터를 받아오지 못하는 것이었다..

 

먼저 카카오 API 예시를 살펴보면 내가 title을 가져와 내 컬렉션 뷰 레이블에 넣고 싶다면 동일한 데이터 모델링 명칭을 달면됐었는데 자세히 보면 title이 documents 안에 소속되어 있는 것을 알 수 있다..

 

그렇기 때문에 데이터 모델링에도 이 documents를 가져와 얘를 거쳐 title에 접근해야만 정상적인 접근이 가능하다는 것이다!!!

// MARK: - BookData
struct BookData: Codable {
    let documents: [Document]
}

// MARK: - Document
struct Document: Codable {
    let authors: [String]
    let contents, datetime, isbn: String
    let price: Int
    let publisher: String
    let salePrice: Int
    let status: String
    let thumbnail: String
    let title: String
    let translators: [String]
    let url: String

    enum CodingKeys: String, CodingKey {
        case authors, contents, datetime, isbn, price, publisher
        case salePrice = "sale_price"
        case status, thumbnail, title, translators, url
    }
}

JSON 데이터를 바탕으로 이렇게 struct를 활용해 데이터 모델링을 해주면 된다! 위에 보이는 documents가 꼭 들어가야 정상적으로 title에 접근 할 수 있는 점 꼭 기억하자!

 

Alamofire를 활용한 네트워킹

이렇게 데이터 모델링을 가져왔으면 이제 Alamofire를 활용해 네트워크를 연결해주자!

class NetworkingManager {
    
    static let shared = NetworkingManager()
    private init() {}
    
    
    func fetchBookData(withQuery query: String, completion: @escaping (Result<bookdata, error="">) -> Void) {
        let url = "<https://dapi.kakao.com/v3/search/book>"
        let headers: HTTPHeaders = ["Authorization": "KakaoAK <인증키>"]
        let parameters: [String: String] = ["query": query]
        
        AF.request(url, parameters: parameters, headers: headers).responseData { response in
            switch response.result {
            case .success(let data):
                print("Received data from network request:")
                if let jsonString = String(data: data, encoding: .utf8) {
                    print(jsonString)
                }
                
                do {
                    let decodedData = try JSONDecoder().decode(BookData.self, from: data)
                    completion(.success(decodedData))
                } catch {
                    completion(.failure(error))
                }
            case .failure(let error):
                completion(.failure(error))
            }
        }
    }
}
</bookdata,>

네트워크 매니저는 한곳에서 설정되고 여러곳에서 쓰일 수 있기 때문에 싱글톤으로 관리하면 편리하게 관리하고 사용할 수 있으니 싱글톤으로 지정해준다.

 

그리고 헤더부분에 형식에 맞게 넣은 뒤 개인 API 키를 넣으면 된다.

 

쿼리 부분을 파라미터로 받는 것은 이 쿼리에 따라 검색 결과가 바뀌기 때문에 그것을 서치바와 연결해 입력된 값을 넣어주기 위해 따로 파라미터로 관리하였다.

 

확실히 URLSession을 사용할때보다 직관적이고 코드가 단축된 것을 볼 수 있다! 이래서 알라모파이어를 많이 사용하는 것 같다.

 

데이터를 받아줄 VC로 넘어와 네트워킹 매니저와 데이터 모델링을 변수에 담은 뒤

let networkingManager = NetworkingManager.shared
var bookData: BookData?

네트워킹 된 데이터를 받아주기 위해 데이터를 fetch 해줄 수 있는 메서드를 만든다.

func fetchBookData(withQuery query: String) {
    networkingManager.fetchBookData(withQuery: query) { [weak self] result in
        guard let self = self else { return }
        switch result {
        case .success(let bookData):
            self.bookData = bookData
            print(bookData)
            DispatchQueue.main.async {
                self.collectionView.reloadData()
            }
        case .failure(let error):
            print("Failed to fetch book data: \\(error)")
        }
    }
}

이 메서드를 실행 시키면 네트워킹 된 데이터를 정상적으로 콘솔에 확인할 수 있다.

fetchBookData(withQuery: "세이노")

그리고 아까 쿼리를 별도로 관리한다고 했는데 메서드를 실행시킬때 이렇게 파라미터로 값을 넣어주면 해당하는 검색 값을 컬렉션 뷰에서 확인할 수 있도록 구성했다.

 

지금은 “세이노” 라고 설정해놨지만 이 값을 서치바와 연결해 그때그때 값을 변경할 수 있도록 수정할 예정이다.

 

CollectionView 데이터 넣기

이제 네트워킹 데이터를 내가 만든 컬렉션 뷰에 넣어주자!

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
   return bookData?.documents.count ?? 0
}

셀 갯수는 전달 받을 데이터의 갯수로 설정한다 🙂

guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BookCollectionViewCell.identifier, for: indexPath) as? BookCollectionViewCell else { fatalError("에러입니다.") }
    cell.setupView()
    
    if let document = bookData?.documents[indexPath.item] {
        cell.titleLabel.text = document.title
        
        if let url = URL(string:  document.thumbnail) {
            cell.bookImageView.kf.setImage(with: url)
        }
    }
    
    return cell
}

그리고 전달받을 네트워킹 데이터의 title 값과 이미지 URL을 Kingfiher를 활용해 쉽게 String으로 변환한다!

이렇게 데이터 연결이 완료된다면 짜잔..

이렇게 데이터가 정상적으로 보인다 ㅠㅠ… 여기까지 오는데 힘들었다..

 

SearchBar 구현하기

이제 네비게이션 바를 만들어 searchBar를 만들어보자!

let firstVC = UINavigationController(rootViewController: SearchViewController())
firstVC.tabBarItem = UITabBarItem(title: "책 검색", image: UIImage(systemName: "book"), tag: 0)

이전에 탭바를 만들었던 firstVC에 UINavigationController를 선언하면 간단하게 설정이 가능하다!

 

다시 VC로 넘어와서

 let searchBar = UISearchBar()

서치바를 선언해준 뒤

func setupSearchBar() {
    navigationItem.titleView = searchBar
    searchBar.delegate = self
    searchBar.placeholder = "원하는 책을 검색해주세요."
    searchBar.sizeToFit()
}

navigationItem.titleView 를 만들어준 searchBar 로 선언해주면 된다!

이렇게 설정 해주고 viewDidLoad에 해당 메서드를 선언하면

 

이렇게 서치바가 완성이된다!

'◽️ Programming > T I L' 카테고리의 다른 글

책 검색 앱 만들기 (5)  (0) 2024.05.08
책 검색 앱 만들기 (4)  (3) 2024.05.07
책 검색 앱 만들기 (2)  (3) 2024.05.01
책 검색 앱 만들기 (1)  (3) 2024.04.30
[ProJect 일지] 영화 예매 앱 만들기 (5)  (2) 2024.04.27