수정 전 | 수정 후 |
---|---|
onChange와 Text를 이용해서 구글Books API를 불러와 실시간으로 동기화되는 검색기능이에요.
'행복'이라는 도서를 검색했을때 정확도가 낮았어요
함수에 print로 데이터가 들어오는것을 확인하니
'행복' 이라는 단어 검색시 '행'이라는 데이터 '행복'이라는 데이터가 append로 추가되기에 뒤로 밀려났어요.
append를 insert로 변경했어요.
또한 isProgress라는 파라미터를 추가해서, scrollView에서 추가 검색을 유도될때만 append로 추가했어요
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)
}
}
}
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
}
}
}
}
}
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()
}
}