[ios] 핵심 데이터 : 엔티티의 모든 인스턴스를 삭제하는 가장 빠른 방법

핵심 데이터를 사용하여 웹 서비스 호출의 결과를 로컬로 유지하고 있습니다. 웹 서비스는 “Cars”에 대해 전체 객체 모델을 반환합니다. “Cars”는 약 2000 개가 될 수 있습니다 (웹 서비스가 1 개 또는 모든 자동차보다 작은 값을 반환하도록 할 수는 없습니다).

다음에 응용 프로그램을 열 때 모든 자동차에 대해 웹 서비스를 다시 호출하여 Core Data 지속 복사본을 새로 고치려고하지만 중복을 방지하려면 먼저 로컬 캐시의 모든 데이터를 제거해야합니다.

관리 객체 컨텍스트 (예 : “CAR”유형의 모든 엔터티)에서 특정 엔터티의 모든 인스턴스를 제거하는 더 빠른 방법이 있습니까? 아니면 쿼리를 호출 한 다음 결과를 반복하여 각 인스턴스를 삭제 한 다음 저장해야합니까?

이상적으로 엔티티가 Blah 인 모든 것을 삭제한다고 말할 수 있습니다.



답변

iOS 9 이상 :

iOS 9 NSBatchDeleteRequest에는 술어와 일치하는 객체를 모두 메모리에로드하지 않고도 쉽게 삭제할 수 있는 새로운 클래스가 추가되었습니다 . 사용 방법은 다음과 같습니다.

스위프트 5

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Car")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

do {
    try myPersistentStoreCoordinator.execute(deleteRequest, with: myContext)
} catch let error as NSError {
    // TODO: handle the error
}

목표 -C

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Car"];
NSBatchDeleteRequest *delete = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];

NSError *deleteError = nil;
[myPersistentStoreCoordinator executeRequest:delete withContext:myContext error:&deleteError];

배치 삭제에 대한 자세한 내용은 WWDC 2015의 “핵심 데이터의 새로운 기능”세션 (~ 14 : 10에서 시작)에서 확인할 수 있습니다.

iOS 8 이하 :

모두 가져 오기 및 모두 삭제 :

NSFetchRequest *allCars = [[NSFetchRequest alloc] init];
[allCars setEntity:[NSEntityDescription entityForName:@"Car" inManagedObjectContext:myContext]];
[allCars setIncludesPropertyValues:NO]; //only fetch the managedObjectID

NSError *error = nil;
NSArray *cars = [myContext executeFetchRequest:allCars error:&error];
[allCars release];
//error handling goes here
for (NSManagedObject *car in cars) {
  [myContext deleteObject:car];
}
NSError *saveError = nil;
[myContext save:&saveError];
//more error handling here


답변

Swift 3 에서 엔티티 재설정 :

func resetAllRecords(in entity : String) // entity = Your_Entity_Name
    {

        let context = ( UIApplication.shared.delegate as! AppDelegate ).persistentContainer.viewContext
        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
        do
        {
            try context.execute(deleteRequest)
            try context.save()
        }
        catch
        {
            print ("There was an error")
        }
    }


답변

조금 더 깨끗하고 보편적 인 방법 :이 방법을 추가하십시오 :

- (void)deleteAllEntities:(NSString *)nameEntity
{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:nameEntity];
    [fetchRequest setIncludesPropertyValues:NO]; //only fetch the managedObjectID

    NSError *error;
    NSArray *fetchedObjects = [theContext executeFetchRequest:fetchRequest error:&error];
    for (NSManagedObject *object in fetchedObjects)
    {
        [theContext deleteObject:object];
    }

    error = nil;
    [theContext save:&error];
}


답변

스위프트 2.0 :

class func clearCoreData(entity:String) {
  let fetchRequest = NSFetchRequest()
  fetchRequest.entity = NSEntityDescription.entityForName(entity, inManagedObjectContext: moc!)
  fetchRequest.includesPropertyValues = false
  do {
    if let results = try moc!.executeFetchRequest(fetchRequest) as? [NSManagedObject] {
      for result in results {
        moc!.deleteObject(result)
      }

      try moc!.save()
    }
  } catch {
    LOG.debug("failed to clear core data")
  }
}


답변

빠른:

let fetchRequest = NSFetchRequest()
fetchRequest.entity = NSEntityDescription.entityForName(entityName, inManagedObjectContext: context)
fetchRequest.includesPropertyValues = false

var error:NSError?
if let results = context.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject] {
    for result in results {
        context.deleteObject(result)
    }

    var error:NSError?
    if context.save(&error) {
        // do something after save

    } else if let error = error {
        println(error.userInfo)
    }

} else if let error = error {
    println("error: \(error)")
}


답변

이것은 하나에 비슷한 질문입니다 여기에 누군가 당신이 하나의 개체를 삭제해야하므로 관계 삭제 규칙을 설정 제안했다. 따라서 자동차와 많은 관계가있는 엔터티를 가지고 있거나 만들 수 있고 더 높은 엔터티를 삭제할 때 삭제 규칙을 계단식으로 설정하면 모든 자동차도 삭제됩니다. 모든 차량 적재와 관련된 단계를 수행 할 필요가 없으므로 처리 시간이 절약 될 수 있습니다. 더 큰 데이터 세트에서는 이것이 절대적으로 필요할 수 있습니다.


답변

좋은 답변이 이미 게시되었습니다. 이것은 추천 일뿐입니다!

좋은 방법은 카테고리를 추가하고 NSManagedObject내가 한 것처럼 메소드를 구현하는 것입니다.

헤더 파일 (예를 들어 NSManagedObject+Ext.h)

@interface NSManagedObject (Logic)

+ (void) deleteAllFromEntity:(NSString*) entityName;

@end

코드 파일 : (예 : NSManagedObject + Ext.m)

@implementation NSManagedObject (Logic)

+ (void) deleteAllFromEntity:(NSString *)entityName {
    NSManagedObjectContext *managedObjectContext = [AppDelegate managedObjectContext];
    NSFetchRequest * allRecords = [[NSFetchRequest alloc] init];
    [allRecords setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]];
    [allRecords setIncludesPropertyValues:NO];
    NSError * error = nil;
    NSArray * result = [managedObjectContext executeFetchRequest:allRecords error:&error];
    for (NSManagedObject * profile in result) {
        [managedObjectContext deleteObject:profile];
    }
    NSError *saveError = nil;
    [managedObjectContext save:&saveError];
}

@end

… 당신이해야 할 유일한 것은 app delegate에서 managedObjectContext를 가져 오는 것입니다.

나중에 다음과 같이 사용할 수 있습니다.

[NSManagedObject deleteAllFromEntity:@"EntityName"];

하나의 추가 최적화는 tha entityname에 대한 매개 변수를 제거하고 clazzname에서 대신 이름을 얻는 것입니다. 이것은 사용법으로 이어질 것입니다 :

[ClazzName deleteAllFromEntity];

보다 깨끗한 impl (NSManagedObjectContext의 카테고리로) :

@implementation NSManagedObjectContext (Logic)

- (void) deleteAllFromEntity:(NSString *)entityName {
    NSFetchRequest * allRecords = [[NSFetchRequest alloc] init];
    [allRecords setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:self]];
    [allRecords setIncludesPropertyValues:NO];
    NSError * error = nil;
    NSArray * result = [self executeFetchRequest:allRecords error:&error];
    for (NSManagedObject * profile in result) {
        [self deleteObject:profile];
    }
    NSError *saveError = nil;
    [self save:&saveError];
}

@end

그런 다음 사용법 :

[managedObjectContext deleteAllFromEntity:@"EntityName"];