[트러블 슈팅] CoreData 대량 데이터 처리

z-wook·2023년 8월 13일
0

트러블 슈팅

목록 보기
4/6
post-thumbnail

문제 상황

PlanBee 복귀 유저를 위해서 Firestore에 저장해둔 데이터를 받아와서 CoreData에 저장하는 작업을 하던 중 에러가 나오는 상황


문제 상황까지의 순서

  1. Firestore로부터 비동기로 TodoList를 받아옴
  2. 받아온 TodoList를 for 문을 사용하여 하나씩 CoreData에 저장
  3. CoreData에 저장하는 중 에러 발생


문제 상황의 코드

Task {
	if let todoList = await FirestoreManager.shared.getTodoList(strDate: formattedDate) {
    	for todo in todoList {
    		_ = CoreDataManager.shared.saveTodoData(todo: todo)
		}
    }
}

func saveTodoData(todo: Todo) -> Bool {
	guard let context = context else { return false }
	guard let entity = NSEntityDescription.entity(
		forEntityName: planEntityName, in: context
	) else { return false }
        
	let object = NSManagedObject(entity: entity, insertInto: context)
	object.setValue(todo.id, forKey: Todokeys.uuid.key)
	object.setValue(todo.content, forKey: Todokeys.content.key)
	object.setValue(todo.date, forKey: Todokeys.date.key)
	object.setValue(todo.priority, forKey: Todokeys.priority.key)
	object.setValue(todo.done, forKey: Todokeys.done.key)
        
	do {
		try context.save()
		return true
	} catch {
		print("error: \(error.localizedDescription)")
		return false
	}
}

원인 추론

CoreData에서 대량의 데이터를 고속 처리하는 것이 문제가 되어 에러가 발생하는 것이라고 추론 가능하다.


수정 및 조치

NSBatchInsertRequest를 사용하여 대량의 데이터를 한 번에 삽입할 수 있게 수정한다.

  • NSBatchInsertRequest란?
    • CoreData에서 여러 개의 데이터를 한 번에 삽입(추가) 하는 데 사용되는 클래스입니다.
    • CoreData 스택 내에서 단일 요청으로 여러 객체를 추가할 수 있으므로 성능 향상을 기대할 수 있습니다.

⭐️ 문제 해결 ⭐️

Task {
	if let todoList = await FirestoreManager.shared.getTodoList(strDate: formattedDate) {
    	if !todoList.isEmpty {
    		CoreDataManager.shared.saveTodoDataAtOnce(todos: todoList)
		}
	}
}

func saveTodoDataAtOnce(todos: [Todo]) {
	guard let context = context else { return }
	let object = todos.compactMap { data -> [String: Any]? in
		let todo: [String: Any] = [
			Todokeys.uuid.key: data.id,
			Todokeys.content.key: data.content,
			Todokeys.date.key: data.date,
			Todokeys.priority.key: data.priority,
			Todokeys.done.key: data.done
		]
		return todo
	}
	// NSBatchInsertRequest를 사용하면 대량의 데이터를 효율적으로 CoreData에 추가할 수 있습니다.
	// 단일 요청으로 여러 객체를 추가할 수 있으므로 성능 향상을 기대할 수 있습니다.
	let batchInsertRequest = NSBatchInsertRequest(entityName: planEntityName, objects: object)
        
	do {
		let result = try context.execute(batchInsertRequest) as? NSBatchInsertResult
		if let success = result?.result as? Bool, success {
			print("Batch insert successful")
			return
		}
	} catch {
		print("error: \(error.localizedDescription)")
		return
	}
}

NSBatchInsertRequest를 사용하여 아래와 같이 Firestore로부터 데이터를 받아온 후 CoreData에 대량의 데이터를 한 번에 삽입할 수 있게 만들었습니다. (지난 6개월간 데이터 모두 받아와서 저장하는 예시)


추가적으로 NSBatchDeleteRequest를 사용하면 한 번에 모든 데이터를 삭제할 수 있습니다.

func removeAllPlanData() {
	guard let context = context else { return }
	let entityNames: [String] = [planEntityName]
        
	for entity in entityNames {
		let fetrequest = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
		let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetrequest)
		do {
			try context.execute(deleteRequest)
			print("\(entity) 데이터 모두 삭제")
		} catch {
			print("삭제 중 오류 발생: \(error.localizedDescription)")
		}
	}
	return
}
profile
🍎 iOS Developer

2개의 댓글

comment-user-thumbnail
2023년 8월 13일

좋은 글 감사합니다. 자주 올게요 :)

답글 달기
comment-user-thumbnail
2023년 8월 19일

🦭

답글 달기