WishList 만들기 (완) - 코어데이터 삭제 , 리프레쉬 기능 구현

2024.04.10 - [◽️ Programming/T I L] - WishList 만들기 (1) - (URLSession 데이터 연결 완료)

2024.04.12 - [◽️ Programming/T I L] - WishList 만들기 (2) - (CoreData 연결)

 

오늘은 주말에 wishlist 만들기를 끝내고 싶어 코어데이터를 테이블 뷰에 나오도록 구현하고 데이터 삭제, 그리고 리프레쉬 하는 기능까지 넣어 과제를 완료 했다.

 

오늘 진행한 기능 구현을 블로그에 정리해보자


저장된 코어데이터 불러와 테이블 뷰에 표현하기

 

먼저 저장된 코어 데이터를 가져올 수 있도록 이전에 구현해 놨던 코어데이터 요청하는 메서드를 다시 한번 보자

func getWishListFromCoreData() -> [Product] {
    var wishList: [Product] = []
    
    if let context = context {
        let request = NSFetchRequest<NSManagedObject>(entityName: self.coreDataName)
        let idOrder = NSSortDescriptor(key: "id", ascending: false)
        request.sortDescriptors = [idOrder]
        
        do {
            if let fetchWishList = try context.fetch(request) as? [Product] {
                wishList = fetchWishList
            }
        } catch {
            print("가져오기 실패")
        }
    }
    
    return wishList
}

저장된 코어데이터를 요청해 해당 데이터를 가져올 수 있는 함수를 구현했다.

이 함수를 가져올 수 있도록 뷰 테이블 뷰가 있는 뷰컨트롤러에 코어데이터 타입을 가진 변수를 설정하자

var wishList: [Product] = []

이렇게 코어데이터 저장된 것을 가질 수 있도록 설정하고 그 이후 저장된 데이터를 가져와 저장하는 함수를 구현한다.

func fetchWishListData() {
    wishList = CoreDataManager.shared.getWishListFromCoreData()
    wishListTableView.reloadData()
}

여기서 .getWishListFromCoreData는 CoreDataManager에서 구현해둔 메서드를 가져온 것이다.

그 이후 테이블 뷰 셀 데이터소스를 활용해 위시리스트가 있는 셀의 레이블 들과 연결 할 수 있도록 구현한다.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "WishListCell", for: indexPath) as! WishListTableViewCell
    let product = wishList[indexPath.row]
    cell.cellPrice.text = "\\(product.price)$"
    cell.cellId.text = "\\(product.id)"
    cell.cellTitle.text = product.title
    
    cell.selectionStyle = .none
    
    return cell
}

이렇게 구현이 완료되면 내가 저장한 코어데이터가 테이블뷰에 나올 수 있게 된다 🙂

코어데이터 삭제 하기

그럼 이제 데이터를 삭제할 수 있는 방법도 정리해보자

먼저 CoreDataManager에 이번엔 삭제하는 메서드를 구현하자

func deleteProduct(_ product: Product, completion: @escaping () -> Void) {
    guard let context = context else {
        print("content를 가져올 수 없습니다.")
        return
    }
    
    let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: coreDataName)
    if let title = product.title {
        fetchRequest.predicate = NSPredicate(format: "title == %@", title)
    }
    
    do {
        if let result = try context.fetch(fetchRequest) as? [NSManagedObject] {
            for object in result {
                context.delete(object)
            }
            
            try context.save()
            print("삭제가 완료되었습니다.")
            completion()
        }
    } catch {
        print("삭제가 실패했습니다.", error)
        completion()
    }
}

이렇게 선택한 데이터를 삭제하면 내 코어데이터에서 삭제될 수 있도록 메서드를 구현했다.

여기서 나온 문제점은 특정 데이터를 추적하는 과정인

fetchRequest.predicate = NSPredicate(format: "title == %@", title)

이 부분에서 id 값을 사용해 “id == %@”, id 로 구성했으나 메모리 오류가 발생하였다.

 

곰곰히 생각해보니 첫번째 VC에서 네트워킹해 보여주는 상품창에는 id 값이 표시되지 않고 있는 상태라서 이런 오류가 발생하는 걸까.. 라고 생각해 id 가 아닌 title 로 값을 변경하니 정상적으로 구현되었다.

 

이렇게 삭제 데이터 메서드를 구현한 뒤 다시 테이블 뷰로 넘어가 특정 셀을 왼쪽으로 스와이프 하면 삭제 버튼이 나올 수 있는 테이블 뷰 기능을 이용해 데이터를 삭제하는 기능을 구현했다.

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        let productToDelete = wishList[indexPath.row]
        
        CoreDataManager.shared.deleteProduct(productToDelete) {
            self.wishList.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
        }
    }
}

이렇게 테이블 뷰 셀를 스와이프해 삭제 버튼을 토글하면 해당하는 데이터를 삭제하고 테이블 뷰의 셀도 삭제하는 기능을 구현했다.

 

RefreshControl 구현하기

이제 데이터도 잘 뜨고 삭제도 잘되니 테이블 뷰를 아래로 당겨 새로고침을 실행 할 수 있도록 구현하자

먼저 리프레쉬 컨트롤을 구현해야한다.

func setupRefreshControl() {
    refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(refreshData(_:)), for: .valueChanged)
    wishListTableView.refreshControl = refreshControl
    fetchWishListData()
}

@objc func refreshData(_ sender: Any) {
    fetchWishListData()
    wishListTableView.refreshControl?.endRefreshing()
}

이렇게 리프레쉬 컨트롤을 설정해여 현재 저장된 값을 다시 가져오는 메서드를 구현해주면 된다.

이렇게 구현을 하니 끝난 줄 알았지만 잠시 새로고쳐지는 과정에서 셀이 정지되어있고 새로고침이 끝나면 원래대로 돌아오는 과정이 남아있었다.

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    wishListTableView.refreshControl?.beginRefreshing()
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !decelerate {
        wishListTableView.refreshControl?.endRefreshing()
    }
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    wishListTableView.refreshControl?.endRefreshing()
}

리프레쉬 컨트롤이 가지고 있는 기능을 활용해 드래그가 시작되었을때 , 끝났을때 셀이 잠시 정지되어 새로고쳐지는 과정을 표현하는 내용을 담고 있는 메서드를 구현하면 모든 과정이 끝난다 🙂

 


처음에 코어데이터와 URLSession은 너무 생소한 단어와 문법들이 많이 등장해 갈피를 못잡고 어려움을 겪었지만 계속 반복해서 보고 써보니 어느정도는 익숙해 진 것 같다.

 

아직 문법이나 용어들을 전부 이해하기는 어렵지만 월요일 부터 남은 기간동안 구현한 내용을 다시 뜯어보고 이전에 만들었던 ToDoList 에 코어데이터를 적용해보면서 다시 한번 더 익히는 과정을 가져야겠다.

 

끄으읕