책 검색 앱 만들기 (3)

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

 

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

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


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

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

 

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

스크린샷 2024-05-03 오후 10.39.16.png

 

그렇기 때문에 데이터 모델링에도 이 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으로 변환한다!

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

edited_Simulator Screenshot - iPhone 15 Pro - 2024-05-03 at 17.08.52.png

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

 

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에 해당 메서드를 선언하면

 

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

Simulator Screenshot - iPhone 15 Pro - 2024-05-03 at 17.08.52.png

'◽️ 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