⏰ 지금까지 진행 한 과정 다시보기
2024.04.30 - [◽️ Programming/T I L] - 책 검색 앱 만들기 (1)
2024.05.01 - [◽️ Programming/T I L] - 책 검색 앱 만들기 (2)
2024.05.03 - [◽️ Programming/T I L] - 책 검색 앱 만들기 (3)
2024.05.07 - [◽️ Programming/T I L] - 책 검색 앱 만들기 (4)
2024.05.08 - [◽️ Programming/T I L] - 책 검색 앱 만들기 (5)
코어데이터 추가 기능 구현
코어데이터 저장 순서 date 설정 하여 정렬하기
코어데이터가 저장되어 마이페이지에 저장된 코어데이터가 보일때 순서가 정렬되지 않고 마구잡이로 들어오는 문제가 있었다.
그 문제를 해결하기 위해 저장한 시간대를 같이 코어데이터에 저장해 이 시간대를 기준으로 정렬을 하면 될 것 같아 그렇게 한번 구현해 보았다 🙂
extension BookCoreData {
@nonobjc public class func fetchRequest() -> NSFetchRequest<BookCoreData> {
return NSFetchRequest<BookCoreData>(entityName: "BookCoreData")
}
@NSManaged public var title: String?
@NSManaged public var authors: String?
@NSManaged public var price: Int64
@NSManaged public var date: Date
}
extension BookCoreData : Identifiable {
}
코어데이터 entity에 사진과 코드와 같이 새로운 데이터를 넣을 수 있도록 추가한다
let newProduct = NSManagedObject(entity: entity, insertInto: context)
let authorsString = booklist.authors.joined(separator: ", ")
newProduct.setValue(authorsString, forKey: "authors")
newProduct.setValue(booklist.title, forKey: "title")
newProduct.setValue(booklist.price, forKey: "price")
newProduct.setValue(Date(), forKey: "date")
그리고 코어데이터를 저장하는 메서드에 해당 내용을 추가하면 저장되는 시간도 같이 코어데이터에 저장이 완료 된다!
func getBookListFromCoreData() -> [BookCoreData] {
var bookList: [BookCoreData] = []
if let context = context {
let request = NSFetchRequest<BookCoreData>(entityName: self.coreDataName)
let dateOrder = NSSortDescriptor(key: "date", ascending: true)
request.sortDescriptors = [dateOrder]
do {
bookList = try context.fetch(request)
} catch {
print("데이터를 가져오는데 실패했습니다:", error)
}
}
return bookList
}
그리고 코어데이터를 가져와 마이페이지에 데이터를 GET 할 때 date를 기준으로 정렬하는 코드를 넣어주면 책을 저장하는 순서대로 마이페이지에서 저장된 책을 볼 수 있다.
코어 데이터 내 이미 있는 책 정보 확인하여 중복 저장 방지하기
코어 데이터 내 이미 저장되어 있는 책이라면 동일한 책은 저장되지 않도록 하는 기능을 구현했다. 해당 내용은 코드로 한번 살펴보자!
guard let context = context else {
print("context를 가져올 수 없습니다.")
completion(false)
return
}
let request = NSFetchRequest<NSFetchRequestResult>(entityName: coreDataName)
request.predicate = NSPredicate(format: "title == %@", booklist.title)
do {
let count = try context.count(for: request)
guard count == 0 else {
print("이미 저장된 책입니다.")
completion(false)
return
}
} catch {
print("중복 체크 실패:", error)
completion(false)
return
}
코어 데이터를 저장하는 메서드 내 context 안에 동일한 title을 가지고 있다면 이미 저장된 책이라는 안내와 컨텐츠 저장이 되지 않도록 구현했다 🙂
func saveBookToCoreData(completion: @escaping (Bool) -> Void) {
guard let bookData = bookData else {
print("bookData가 없습니다.")
return
}
CoreDataManager.shared.saveBookListData(bookData) { isSaved in
if isSaved {
print("코어데이터에 저장되었습니다.")
completion(true)
} else {
print("이미 저장된 책입니다.")
completion(false)
}
}
}
DetailViewController에 해당 내용을 선언해주면 구현이 완료된다 🙂
무한 스크롤 구현
NetworkingManager 세팅하기
이제 검색한 책을 스크롤 할 때 마다 끝에 도착하면 다음 페이지의 데이터를 가져와 끊임없이 스크롤이 될 수 있도록 구현할 예정이다 🙂
먼저 코어데이터 매니저에 page 값을 파라미터로 넣을 수 있도록 세팅한다.
class NetworkingManager {
static let shared = NetworkingManager()
private init() {}
var isEnd = false
let pageSize = 40
var page = 1
func fetchBookData(withQuery query: String, page: Int, completion: @escaping (Result<bookdata, error="">) -> Void) {
let url = "<https://dapi.kakao.com/v3/search/book>"
let headers: HTTPHeaders = ["Authorization": "인증키"]
let parameters: [String: Any] = ["query": query, "size": pageSize, "page": page]
AF.request(url, parameters: parameters, headers: headers).responseData { [weak self] response in
guard let self = self else { return }
switch response.result {
case .success(let data):
do {
let decodedData = try JSONDecoder().decode(BookData.self, from: data)
let nextPageExists = decodedData.meta.isEnd
self.isEnd = !nextPageExists
completion(.success(decodedData))
} catch {
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
}
}
</bookdata,>
그 이후 책 목록이 나오는 컬렉션 뷰 내 데이터를 불러 오는 메서드를 수정하면된다.
var currentPage = 1
var isEnd = false
func fetchBookData(withQuery query: String, page: Int) {
networkingManager.fetchBookData(withQuery: query, page: currentPage) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let bookData):
if self.currentPage == 1 {
self.bookData = bookData
} else {
self.bookData?.documents += bookData.documents
}
self.currentPage += 1
self.isEnd = bookData.meta.isEnd
DispatchQueue.main.async {
self.collectionView.reloadData()
}
case .failure(let error):
print("Failed to fetch book data: \\(error)")
}
}
}
현재 페이지를 나타내는 수를 넣어 page 내 파라미터에 들어갈 수 있도록 설정하고 currentPage가 1일때 데이터를 받아온 뒤 page가 1을 넘어가면 다음 페이지의 데이터를 추가해서 나올 수 있도록 설정했다.
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if !isEnd && indexPath.item == (collectionView.numberOfItems(inSection: indexPath.section) - 1) {
fetchNextPage()
}
}
func fetchNextPage() {
guard let query = searchBar.text else { return }
fetchBookData(withQuery: query, page: currentPage)
}
그 다음 collectionView willDisplay를 활용해 스크롤이 마지막에 닿을 시 fetchNextPage가 실행되도록 설정하고 fetchNextPage에는 서치바의 텍스트가 들어가 있을때 해당 하는 텍스트의 책 데이터를 가져오도록 설정하면
마지막 스크롤이 닿을때 해당 메서드가 실행되고 무한 스크롤이 작동되어 다음페이지로 넘어가지 않고 하나의 스크롤로 모든 정보를 확인할 수 있다. 🙂
이제 MVVM 적용만 남아있으니 MVVM에 대해서 공부하고 한번 적용하는 과정을 거쳐보자!!
'◽️ Programming > T I L' 카테고리의 다른 글
[Project 일지] 단어장 앱 만들기 (2) (4) | 2024.05.14 |
---|---|
[Project 일지] 단어장 앱 만들기 (1) (0) | 2024.05.13 |
책 검색 앱 만들기 (5) (0) | 2024.05.08 |
책 검색 앱 만들기 (4) (3) | 2024.05.07 |
책 검색 앱 만들기 (3) (0) | 2024.05.03 |