[Swift]Google Books APIs 이슈트래킹

힐링힐링·2024년 4월 10일
0

SwiftUI

목록 보기
14/14
수정 전수정 후

현상

onChange와 Text를 이용해서 구글Books API를 불러와 실시간으로 동기화되는 검색기능이에요.
'행복'이라는 도서를 검색했을때 정확도가 낮았어요

원인

함수에 print로 데이터가 들어오는것을 확인하니
'행복' 이라는 단어 검색시 '행'이라는 데이터 '행복'이라는 데이터가 append로 추가되기에 뒤로 밀려났어요.

해결

append를 insert로 변경했어요.
또한 isProgress라는 파라미터를 추가해서, scrollView에서 추가 검색을 유도될때만 append로 추가했어요

코드

View

struct SearchBarView: View {
    @StateObject var viewModel: SearchBooksViewModel
    var body: some View {
        GeometryReader { geometry in
            HStack {
                TextField("검색어를 입력해주세요", text: $viewModel.text)
                    .padding(7)
                    .onChange(of: viewModel.text) { _ in
                        viewModel.searchBooks.totalItems = 0
                        viewModel.searchBooks.items.removeAll()
                        viewModel.firstToTalCount = 0
                        viewModel.isFinish = true
                        viewModel.startIndex = 0
                        
                        if viewModel.text != "" {
                            isEditing = true
                            viewModel.callBookApi(isProgress: false)
                        } else {
                            isEditing = false
                        }
                    }
            }
        }
        .frame(width: geometry.size.width)
    }
}
struct SearchResultView: View {
    @StateObject var viewModel: SearchBooksViewModel
    
    var body: some View {
        GeometryReader { geometry in
            VStack {
                ScrollView {
                    LazyVStack {
                        ForEach(viewModel.searchBooks.items) { book in
                            HStack(alignment: .top) {
                                VStack(alignment: .leading) {
                                    Text(book.volumeInfo.title ?? "제목 미상")
                                        .font(.system(size: 12, weight: .semibold))
                                        .padding(.bottom, 10)
                                }
                            }
                            .padding(.vertical, 10)
                            .padding(.horizontal)
                        }
                        
                        if !viewModel.isFinish {
                            ProgressView()
                                .onAppear {
                                    viewModel.callBookApi(isProgress: true)
                                }
                        }
                    }
                }
            }
            .frame(width: geometry.size.width, height: geometry.size.height)
        }
    }
}

ViewModel

class SearchBooksViewModel: ObservableObject {
    @Published var searchBooks: Book = Book.init(totalItems: 0, items: [])
    @Published var selectBooks: Book = Book.init(totalItems: 0, items: [])
    
    @Published var firstToTalCount: Int = 0
    @Published var isFinish: Bool = true
    @Published var startIndex: Int = 0
    @Published var text: String = ""
    
    var bookApiManger = BookAPIManger()
}

extension SearchBooksViewModel {
    //도서 api 호출
    func callBookApi(isProgress: Bool) {
        bookApiManger.getData(text: text, startIndex: startIndex) { book in
            DispatchQueue.main.async {
                if self.firstToTalCount == 0 {
                    self.firstToTalCount = book.totalItems
                    self.searchBooks.totalItems = book.totalItems
                }
                // 추가 검색 결과는 뒤로
                if isProgress{
                    self.searchBooks.items.append(contentsOf: book.items)
                }else{
                    self.searchBooks.items.insert(contentsOf: book.items, at: 0)
                }
                
                self.startIndex += 20
                
                if self.firstToTalCount <= self.startIndex || self.startIndex >= 100 {
                    self.isFinish = true
                } else if self.firstToTalCount > 20 {
                    self.isFinish = false
                }
            }
        }
    }
}

Mangager


class BookAPIManger {
    //결과값
    func getData(text: String, startIndex: Int, completion: (@escaping (Book) -> Void)){
        let urlString = "https://www.googleapis.com/books/v1/volumes?q=\(text)&startIndex=\(startIndex)&maxResults=20&printType=books"

         guard let url = URL(string: urlString) else { return }

         let session = URLSession(configuration: .default)

         let task = session.dataTask(with: url){ data, response, error in
             if let error = error {
                 print(error.localizedDescription)
                 return
             }

             guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
                 print("포스팅되지 않음")
                 return
             }

             guard let data = data else {
                 print("데이터 없음")
                 return
             }

             do {
                 let json = try JSONDecoder().decode(Book.self, from: data)
                 
                 completion(json)
             } catch let error {
                 print(error.localizedDescription)
             }
         }
         task.resume()
    }
}
profile
블로그 이전합니다 https://james-kim-tech.tistory.com/

0개의 댓글