ลบ / รีเซ็ตรายการทั้งหมดใน Core Data หรือไม่


235

คุณรู้วิธีการลบรายการทั้งหมดที่เก็บไว้ใน Core Data หรือไม่? สคีมาของฉันควรคงเดิม ฉันต้องการรีเซ็ตเป็นค่าว่าง


แก้ไข

ฉันต้องการทำสิ่งนี้โดยทางโปรแกรมเพื่อให้ผู้ใช้สามารถกดresetปุ่มได้


6
คำตอบหลายข้อด้านล่างนี้เป็นวันที่ NSBatchDeleteRequestใช้ stackoverflow.com/a/31961330/3681880
Suragch

คำตอบ:


198

คุณยังสามารถลบไฟล์โดยทางโปรแกรมโดยใช้วิธี NSFileManager: removeItemAtPath ::

NSPersistentStore *store = ...;
NSError *error;
NSURL *storeURL = store.URL;
NSPersistentStoreCoordinator *storeCoordinator = ...;
[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

จากนั้นเพียงเพิ่มที่เก็บถาวรกลับเพื่อให้แน่ใจว่าได้สร้างใหม่อย่างถูกต้อง

วิธีการเขียนโปรแกรมสำหรับการวนซ้ำผ่านแต่ละเอนทิตีนั้นช้าลงและมีแนวโน้มที่จะเกิดข้อผิดพลาด การใช้สำหรับการทำเช่นนั้นคือถ้าคุณต้องการลบเอนทิตีบางอย่างและไม่ใช่อื่น ๆ อย่างไรก็ตามคุณยังคงต้องตรวจสอบให้แน่ใจว่าคุณรักษาความสมบูรณ์ของการอ้างอิงไม่เช่นนั้นคุณจะไม่สามารถยืนยันการเปลี่ยนแปลงของคุณได้

เพียงแค่ลบที่จัดเก็บและสร้างใหม่ทั้งสองอย่างรวดเร็วและปลอดภัยและสามารถทำได้อย่างเป็นระบบที่รันไทม์

อัปเดตสำหรับ iOS5 +

ด้วยการแนะนำของที่เก็บข้อมูลไบนารีภายนอก (อนุญาตให้ภายนอก BinaryDataStorage หรือเก็บในไฟล์บันทึกภายนอก) ใน iOS 5 และ OS X 10.7 เพียงแค่การลบไฟล์ที่ชี้โดย storeURLs ไม่เพียงพอ คุณจะทิ้งไฟล์บันทึกภายนอกไว้ เนื่องจากรูปแบบการตั้งชื่อของไฟล์บันทึกภายนอกเหล่านี้ยังไม่เปิดเผยฉันยังไม่มีวิธีแก้ปัญหาสากล - an0 8 พฤษภาคม 2555 เวลา 23:00 น


1
นี่อาจเป็นทางออกที่ดีที่สุดสำหรับความน่าเชื่อถือ หากฉันต้องการลบข้อมูลบางส่วน แต่ไม่ใช่ทั้งหมดฉันจะใช้สิ่งนี้: stackoverflow.com/questions/1077810/…
Michael Grinich

12
ฉันรู้วิธีการดึง storeCoordinator อย่างถูกต้อง อย่างไรก็ตามฉันไม่รู้วิธีรับ persistentStore ดังนั้นคุณสามารถให้ตัวอย่างที่เหมาะสมแทนเพียงแค่: NSPersistentStore * store = ... ;
ปาสกาลไคลน์

11
[[NSFileManager defaultManager] removeItemAtURL: ข้อผิดพลาด storeURL: & ข้อผิดพลาด] ดีกว่า
an0

3
@Pascal หากคุณสามารถรับผู้ประสานงานร้านค้าคุณจะสามารถเข้าถึงร้านค้าถาวรทั้งหมดได้ผ่านคุณสมบัติร้านค้าถาวร
Mihai Damian

2
รหัสตัวอย่างรวมถึงวิธีการสร้างร้านค้าใหม่ที่ว่างเปล่าที่นี่: stackoverflow.com/a/8467628
Joshua C. Lerner

140

คุณสามารถลบไฟล์ SQLite - แต่ฉันเลือกที่จะทำโดยล้างตารางแต่ละรายการด้วยฟังก์ชั่น:

- (void) deleteAllObjects: (NSString *) entityDescription  {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityDescription inManagedObjectContext:_managedObjectContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
    [fetchRequest release];


    for (NSManagedObject *managedObject in items) {
        [_managedObjectContext deleteObject:managedObject];
        DLog(@"%@ object deleted",entityDescription);
    }
    if (![_managedObjectContext save:&error]) {
        DLog(@"Error deleting %@ - error:%@",entityDescription,error);
    }

}

เหตุผลที่ฉันเลือกที่จะทำทีละโต๊ะก็เพราะมันทำให้ฉันยืนยันในขณะที่ฉันกำลังเขียนโปรแกรมที่ลบเนื้อหาของตารางนั้นมีเหตุผลและไม่มีข้อมูลที่ฉันอยากจะเก็บไว้

การทำเช่นนี้จะช้ากว่าการลบไฟล์และฉันจะเปลี่ยนเป็นการลบไฟล์ถ้าฉันใช้วิธีนี้ใช้เวลานานเกินไป


ทางออกที่ดี ขอบคุณ DLog () คืออะไร
Michael Grinich

อ่าใช่ - ขอโทษที่เป็นฟังก์ชั่นพิเศษที่ฉันใช้นั่นทำ NSLog เมื่อบิลด์เป็นบิลด์ DEBUG - แค่แทนที่ด้วย NSLog
Grouchal

6
คุณสามารถดูการนำ DLog มาใช้ได้ที่นี่: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long

3
มันใช้งานได้ดีสำหรับฉัน แต่เพื่อให้เร็วขึ้นมีวิธีลบวัตถุทั้งหมดของเอนทิตีที่แน่นอนด้วยคำสั่งเดียวหรือไม่? เช่นเดียวกับใน SQL คุณสามารถทำสิ่งต่างๆเช่น DROP TABLE entity_name ฉันไม่ต้องการลบไฟล์ SQL ทั้งหมดเพราะฉันเพียงต้องการลบวัตถุทั้งหมดของเอนทิตีที่ระบุไม่ใช่เอนทิตีอื่น ๆ
ma11hew28

8
ใช้ NSDictionary * allEntities = _managedObjectModel.entitiesByName; เพื่อให้เอนทิตีทั้งหมดในแบบจำลองของคุณและจากนั้นคุณสามารถวนซ้ำคีย์ใน NSDictionary นี้เพื่อล้างเอนทิตีทั้งหมดในร้าน
adam0101

60

โซลูชันที่อัปเดตสำหรับ iOS 10+

ใช้NSBatchDeleteRequestเพื่อลบวัตถุทั้งหมดในเอนทิตีโดยไม่ต้องโหลดลงในหน่วยความจำหรือวนซ้ำผ่านวัตถุเหล่านั้น

// create the delete request for the specified entity
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = MyEntity.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

// get reference to the persistent container
let persistentContainer = (UIApplication.shared.delegate as! AppDelegate).persistentContainer

// perform the delete
do {
    try persistentContainer.viewContext.execute(deleteRequest)
} catch let error as NSError {
    print(error)
}

รหัสนี้ได้รับการอัพเดตสำหรับ iOS 10 และ Swift 3 หากคุณต้องการรองรับ iOS 9 ให้ดูคำถามนี้

แหล่งที่มา:


3
ฉันจะวางที่บล็อกทั้งหมดภายใน...moc.performBlockAndWait({ () -> Void in })
SwiftArchitect

2
ตรวจสอบให้แน่ใจว่าคุณเห็นทำไมรายการไม่ถูกลบจนกว่าจะรีสตาร์ทแอพหรือฉันรัน NSBatchDeleteRequest สองครั้ง เรื่องยาวโค้ดข้างต้นไม่เพียงพอหากเอนทิตีถูกโหลดลงในหน่วยความจำ
ฮันนี่

38

ฉันได้เขียนclearStoresวิธีการที่ผ่านทุกร้านและลบทั้งจากผู้ประสานงานและระบบแฟ้ม (การจัดการข้อผิดพลาดซ้าย):

NSArray *stores = [persistentStoreCoordinator persistentStores];

for(NSPersistentStore *store in stores) {
    [persistentStoreCoordinator removePersistentStore:store error:nil];
    [[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:nil];
}

[persistentStoreCoordinator release], persistentStoreCoordinator = nil;

วิธีนี้อยู่ในcoreDataHelperชั้นเรียนที่ดูแล (เหนือสิ่งอื่นใด) เพื่อสร้าง persistentStore เมื่อมันเป็นศูนย์


"ไม่มีวิธีการเรียนที่รู้จักสำหรับตัวเลือก 'persistentStores'"
Aviram Netanel

27

ฉันลบข้อมูลทั้งหมดจากข้อมูลหลักในเหตุการณ์ปุ่มในคลาส HomeViewController: บทความนี้ช่วยฉันมากฉันคิดว่าฉันมีส่วนร่วม

-(IBAction)buttonReset:(id)sender
{
    NSLog(@"buttonReset Pressed");

    //Erase the persistent store from coordinator and also file manager.
    NSPersistentStore *store = [self.persistentStoreCoordinator.persistentStores lastObject];
    NSError *error = nil;
    NSURL *storeURL = store.URL;
    [self.persistentStoreCoordinator removePersistentStore:store error:&error];
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];


    NSLog(@"Data Reset");

    //Make new persistent store for future saves   (Taken From Above Answer)
    if (![self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // do something with the error
    }

}

โปรดทราบว่าเพื่อที่จะเรียกใช้ self.persistentStoreCoordinator ฉันประกาศคุณสมบัติใน Home View Controller (ไม่ต้องกังวลกับ managedObjectContext ที่ฉันใช้สำหรับการบันทึกและการโหลด)

@property (nonatomic, retain) NSManagedObjectContext        *   managedObjectContext;
@property (nonatomic, retain) NSPersistentStoreCoordinator  *   persistentStoreCoordinator;

จากนั้นใน AppDelegate ApplicationDidFinishLaunching ด้านล่างสร้าง HomeViewController ฉันมี:

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;

@ayteat ใช้งานได้กับคุณหรือไม่ สำหรับฉันมันไม่ทำงานโปรดดูที่stackoverflow.com/questions/14646595/
Ranjit

1
นี่คือคำตอบยกเว้นใช้ "AppDelegate * ad = [[UIApplication sharedApplication] ผู้รับมอบสิทธิ์];" และแทนที่ตัวเองด้วยโฆษณา และอย่าคัดลอกโค้ดสองบิตสุดท้าย
Cescy

1
ทำไมคุณไม่โทรไปที่ reset บน managedObjectContext? เกิดอะไรขึ้นถ้าคุณมีการอ้างอิงที่รัดกุมเกี่ยวกับ managedObject
Parag Bafna

@ParagBafna คุณถูกต้องตัวอย่างโค้ดข้างต้นถือว่าไม่มีการอ้างอิงที่แข็งแกร่งไปยังวัตถุที่ได้รับการจัดการ หากคุณมีบางอย่างคุณควรดูที่การเรียก 'รีเซ็ต' บน managedObjectContext และยกเลิกการอ้างอิงวัตถุที่มีการจัดการใด ๆ ที่คุณมี
atreat

เฮ้ขอบคุณ นอกจากนี้มีวิธีใดในการอัปเกรดแอพ เพื่อความแม่นยำข้อกำหนดของฉันคือเมื่อฉันเปิดแอพเวอร์ชันถัดไปของเราในเวลานั้นเมื่อผู้ใช้อัปเดตแอพจาก appStore ไฟล์หลักข้อมูล n sqlite ควรถูกลบและเริ่มต้นใหม่เป็นค่าว่าง ฉันหาวิธีตรวจหากิจกรรมเปิดตัวแอปครั้งแรกโดยใช้ค่า Bool ใน NSUserDefaults และตรวจสอบค่านี้ใน didfinishLaunchingWithOptions ของตัวแทนผู้รับมอบสิทธิ์แอพ แต่ไม่เข้าใจวิธีล้างสิ่งเหล่านี้ทั้งหมด เนื่องจากไม่มีปุ่มและผู้ได้รับมอบหมายแอพไม่ได้ตรวจพบ "persistentStore" ของฉันเพื่อล้างข้อมูลดังที่คุณทำด้านบน ความช่วยเหลือใด ๆ
Tejas

19

MagicalRecordทำให้ง่ายมาก

[MyCoreDataObject MR_truncateAll];

16
นี่มันเจ๋ง แต่ปิดหัวข้อตั้งแต่ฉันระบุโซลูชัน CoreData
Michael Grinich

8
Active Record Fetching เป็นโซลูชั่นข้อมูลหลัก
casademora

7
แต่คำตอบเช่นนี้มันเกินขอบเขตของคำถาม ไม่มีเหตุผลที่จะถือว่าเขาต้องการใช้เฟรมเวิร์กของ addt'l เพื่อทำสิ่งนี้
jpswain

ฉันขอยืนยันว่านี่ไม่ได้ตอบคำถาม นี่เป็นวิธีที่ดีในการลบรายการออกจากเอนทิตี้หนึ่งไม่ใช่เอนทิตีทั้งหมด ... ! คุณแจกแจงผ่านเอนทิตีทั้งหมดในโมเดลและส่งMR_truncateAllไปยังพวกเขาอย่างไร?
fatuhoku

ดูแหล่งที่มาของ MR_truncate ทั้งหมด - มันดึงข้อมูลวัตถุทั้งหมด แต่ไม่ใช่คุณสมบัติของมัน (ตามที่เราตั้งใจจะทิ้ง NSMO) จากนั้นจะวนซ้ำวัตถุสำหรับเอนทิตีที่ระบุและลบออก github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/ …
1in9ui5t

19

iOS9 +, Swift 2

ลบวัตถุทั้งหมดในเอนทิตีทั้งหมด

func clearCoreDataStore() {
    let entities = managedObjectModel.entities
    for entity in entities {
        let fetchRequest = NSFetchRequest(entityName: entity.name!)
        let deleteReqest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try context.executeRequest(deleteReqest)
        } catch {
            print(error)
        }
    }
}

1
ตรวจสอบให้แน่ใจว่าคุณเห็นทำไมรายการไม่ถูกลบจนกว่าจะรีสตาร์ทแอพหรือฉันรัน NSBatchDeleteRequest สองครั้ง เรื่องยาวโค้ดข้างต้นไม่เพียงพอหากมีการโหลดเอนทิตีเข้าไปในหน่วยความจำ
ฮันนี่

13

[ตอบช้าเมื่อตอบรับความโปรดปรานเพื่อขอคำตอบที่ใหม่กว่า]

ดูคำตอบก่อนหน้า

  • การดึงและลบรายการทั้งหมดตามที่แนะนำโดย @Grouchal และอื่น ๆ ยังคงเป็นโซลูชันที่มีประสิทธิภาพและมีประโยชน์ หากคุณมีแหล่งข้อมูลขนาดใหญ่มากมันอาจช้า แต่ก็ยังใช้งานได้ดี
  • เพียงแค่ลบแหล่งข้อมูลออกเนื่องจากคุณและ @ groundhog note ไม่มีประสิทธิภาพอีกต่อไป มันล้าสมัยแม้ว่าคุณจะไม่ได้ใช้ที่เก็บข้อมูลไบนารีภายนอกเนื่องจาก iOS 7 ใช้โหมด WAL สำหรับการทำเจอร์นัล SQLite ด้วยโหมด WAL อาจจะมีไฟล์เจอร์นัล (อาจใหญ่) นั่งล้อมรอบสำหรับที่เก็บข้อมูล Core ใด ๆ

แต่มีวิธีที่แตกต่างและคล้ายกันในการลบที่เก็บถาวรที่ใช้งานได้ กุญแจสำคัญคือการวางไฟล์ที่เก็บถาวรของคุณในไดเรกทอรีย่อยของตัวเองที่ไม่มีสิ่งอื่นใด อย่าเพิ่งติดมันในไดเรกทอรีเอกสาร (หรือที่ใดก็ได้) สร้างไดเรกทอรีย่อยใหม่สำหรับเก็บถาวร เนื้อหาของไดเรกทอรีนั้นจะเป็นไฟล์เก็บถาวรไฟล์เจอร์นัลและไฟล์ไบนารีภายนอก หากคุณต้องการดักฟังที่เก็บข้อมูลทั้งหมดให้ลบไดเรกทอรีนั้นและพวกเขาทั้งหมดจะหายไป

คุณจะทำสิ่งนี้เมื่อตั้งค่าร้านค้าถาวรของคุณ:

NSURL *storeDirectoryURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"persistent-store"];
if ([[NSFileManager defaultManager] createDirectoryAtURL:storeDirectoryURL
        withIntermediateDirectories:NO
        attributes:nil
        error:nil]) {
    NSURL *storeURL = [storeDirectoryURL URLByAppendingPathComponent:@"MyApp.sqlite"];
    // continue with storeURL as usual...
}

จากนั้นเมื่อคุณต้องการที่จะลบร้านค้า

[[NSFileManager defaultManager] removeItemAtURL:storeDirectoryURL error:nil];

ซึ่งจะลบทั้งไดเร็กทอรีย่อยที่กำหนดเองและไฟล์ Core Data ทั้งหมดในนั้นซ้ำ ๆ

นี้จะทำงานเฉพาะถ้าคุณไม่ได้มีการเก็บถาวรของคุณในโฟลเดอร์เดียวกันกับอื่น ๆ ข้อมูลที่สำคัญ เช่นเดียวกับไดเรกทอรีเอกสารซึ่งอาจมีสิ่งที่มีประโยชน์อื่น ๆ อยู่ในนั้น หากเป็นสถานการณ์ของคุณคุณจะได้รับผลเช่นเดียวกันโดยการมองหาไฟล์ที่คุณไม่ต้องการที่จะเก็บและลบทุกอย่างอื่น สิ่งที่ต้องการ:

NSString *docsDirectoryPath = [[self applicationDocumentsDirectory] path];
NSArray *docsDirectoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsDirectoryPath error:nil];
for (NSString *docsDirectoryItem in docsDirectoryContents) {
    // Look at docsDirectoryItem. If it's something you want to keep, do nothing.
    // If it's something you don't recognize, remove it.
}

วิธีนี้อาจเป็นข้อผิดพลาดง่าย คุณต้องแน่ใจว่าคุณรู้ทุกไฟล์ที่คุณต้องการเก็บไว้เพราะมิฉะนั้นคุณอาจลบข้อมูลสำคัญ ในทางกลับกันคุณสามารถลบไฟล์ไบนารีภายนอกโดยไม่ทราบชื่อไฟล์ / ไดเรกทอรีที่ใช้ในการจัดเก็บ


หากคุณกลัวไฟล์ wal ให้ปิดการใช้งาน
onmyway133

11

นี่คือการแก้ปัญหาแบบรวมสำหรับการล้างข้อมูล Core

- (void)deleteAllObjectsInCoreData
{
    NSArray *allEntities = self.managedObjectModel.entities;
    for (NSEntityDescription *entityDescription in allEntities)
    {
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        [fetchRequest setEntity:entityDescription];

        fetchRequest.includesPropertyValues = NO;
        fetchRequest.includesSubentities = NO;

        NSError *error;
        NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

        if (error) {
                NSLog(@"Error requesting items from Core Data: %@", [error localizedDescription]);
            }

        for (NSManagedObject *managedObject in items) {
            [self.managedObjectContext deleteObject:managedObject];
        }

        if (![self.managedObjectContext save:&error]) {
            NSLog(@"Error deleting %@ - error:%@", entityDescription, [error localizedDescription]);
        }
    }  
}

10

หากคุณต้องการลบวัตถุทั้งหมดและไม่ต้องการลบไฟล์สำรองคุณสามารถใช้วิธีการต่อไปนี้:

- (void)deleteAllObjectsInContext:(NSManagedObjectContext *)context
                       usingModel:(NSManagedObjectModel *)model
{
    NSArray *entities = model.entities;
    for (NSEntityDescription *entityDescription in entities) {
        [self deleteAllObjectsWithEntityName:entityDescription.name
                                   inContext:context];
    }
}

- (void)deleteAllObjectsWithEntityName:(NSString *)entityName
                             inContext:(NSManagedObjectContext *)context
{
    NSFetchRequest *fetchRequest =
        [NSFetchRequest fetchRequestWithEntityName:entityName];
    fetchRequest.includesPropertyValues = NO;
    fetchRequest.includesSubentities = NO;

    NSError *error;
    NSArray *items = [context executeFetchRequest:fetchRequest error:&error];

    for (NSManagedObject *managedObject in items) {
        [context deleteObject:managedObject];
        NSLog(@"Deleted %@", entityName);
    }
}

ระวังว่ามันอาจช้ามาก (ขึ้นอยู่กับจำนวนวัตถุในกราฟวัตถุของคุณ)


วิธีลบข้อมูลเก่า (พูดสามตารางจากตารางเดียวฉันต้องการลบข้อมูล) เมื่อมีการอัปเดตแอป
Madan Mohan

6

หากคุณต้องการลบเส้นทางของวัตถุทั้งหมด (ซึ่งง่ายกว่าการทำลาย Core Data stack แต่มีประสิทธิภาพน้อยกว่า) ซึ่งเป็นการใช้งานที่ดีกว่า:

- (void)deleteAllManagedObjectsInModel:(NSManagedObjectModel *)managedObjectModel context:(NSManagedObjectContext *)managedObjectContext
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [managedObjectContext performBlockAndWait:^{
            for (NSEntityDescription *entity in managedObjectModel) {
                NSFetchRequest *fetchRequest = [NSFetchRequest new];
                [fetchRequest setEntity:entity];
                [fetchRequest setIncludesSubentities:NO];
                NSArray *objects = [managedObjectContext executeFetchRequest:fetchRequest error:nil];
                for (NSManagedObject *managedObject in objects) {
                    [managedObjectContext deleteObject:managedObject];
                }            
            }

            [managedObjectContext save:nil];
        }];
    }];
    [operation setCompletionBlock:^{
        // Do stuff once the truncation is complete
    }];
    [operation start];
}

การนำNSOperationไปใช้งานนี้ใช้เพื่อทำการลบเธรดหลักและแจ้งเตือนเมื่อเสร็จสิ้น คุณอาจต้องการส่งการแจ้งเตือนหรือบางสิ่งภายในบล็อกการทำให้เสร็จสมบูรณ์เพื่อทำให้ฟองสบู่สถานะกลับไปที่เธรดหลัก


โปรดทราบว่า NSManagedObjectContext ของคุณจะต้องเริ่มต้นเช่นNSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];เพื่อที่จะใช้วิธีนี้มิฉะนั้นคุณจะได้รับข้อผิดพลาด:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
จะ

6

โซลูชัน iOS 10 + Swift 3:

func clearCoreDataStore() {
    let delegate = UIApplication.shared.delegate as! AppDelegate
    let context = delegate.persistentContainer.viewContext

    for i in 0...delegate.persistentContainer.managedObjectModel.entities.count-1 {
        let entity = delegate.persistentContainer.managedObjectModel.entities[i]

        do {
            let query = NSFetchRequest<NSFetchRequestResult>(entityName: entity.name!)
            let deleterequest = NSBatchDeleteRequest(fetchRequest: query)
            try context.execute(deleterequest)
            try context.save()

        } catch let error as NSError {
            print("Error: \(error.localizedDescription)")
            abort()
        }
    }
}

ทำซ้ำผ่านเอนทิตีข้อมูลหลักทั้งหมดและล้างข้อมูล


4

ขอบคุณสำหรับการโพสต์ ฉันติดตามมันและมันก็ได้ผลกับฉัน แต่ฉันมีปัญหาอื่นที่ไม่ได้กล่าวถึงในการตอบกลับใด ๆ ดังนั้นฉันไม่แน่ใจว่ามันเป็นเพียงฉัน

อย่างไรก็ตามคิดว่าฉันจะโพสต์ปัญหาที่นี่และวิธีการของฉันที่แก้ไขได้

ฉันมีบันทึกในฐานข้อมูลไม่กี่ฉันต้องการล้างทุกอย่างให้สะอาดก่อนเขียนข้อมูลใหม่ไปยังฐานข้อมูลดังนั้นฉันจึงทำทุกอย่างรวมถึง

[[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error]; 

แล้วใช้managedObjectContextเพื่อเข้าถึงฐานข้อมูล (ควรว่างเปล่าในตอนนี้) ข้อมูลก็ยังอยู่ที่นั่น หลังจากที่ในขณะของการแก้ไขปัญหาที่ฉันพบว่าฉันต้องรีเซ็ตmanagedObjectContext, managedObject, managedObjectModelและ persistentStoreCoordinatorก่อนที่ผมจะใช้managedObjectContextในการเข้าถึง dabase ตอนนี้ฉันมีฐานข้อมูลที่สะอาดที่จะเขียน


ดังนั้นการรีเซ็ต managedObjectContext, managedObject, managedObjectModel และ persistentStoreCoordinator จะวางไฟล์ที่มีฐานข้อมูลกลับหลังจากที่ถูกลบไปหรือไม่
Daniel Brower

4

นี่เป็นเวอร์ชันที่ค่อนข้างง่ายโดยมีการเรียก AppDelegate ด้วยตนเองน้อยลงและรหัสสุดท้ายที่เหลือจากคำตอบยอดนิยม นอกจากนี้ฉันยังได้รับข้อผิดพลาด "ที่เก็บถาวรของวัตถุไม่สามารถเข้าถึงได้จากผู้ประสานงานของ NSManagedObjectContext นี้" ดังนั้นเพียงแค่ต้องการเพิ่มที่ด้านหลัง

NSPersistentStoreCoordinator *storeCoordinator = [self persistentStoreCoordinator];
NSPersistentStore *store = [[storeCoordinator persistentStores] lastObject];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"dataModel"];
NSError *error;

[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

[_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];

if (storeCoordinator != nil) {
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext setPersistentStoreCoordinator:storeCoordinator];
}

4

สวิฟท์โซลูชั่น:

class func deleteAllManagedObjects() {

        let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "mom")
        let mom = NSManagedObjectModel(contentsOfURL: modelURL)

        for entityName in mom.entitiesByName.keys {
            let fr = NSFetchRequest(entityName: entityName as String)
            let a = Utility.managedObjectContext().executeFetchRequest(fr, error: nil) as [NSManagedObject]
            for mo in a {
                Utility.managedObjectContext().deleteObject(mo)
            }
        }

        Utility.managedObjectContext().save(nil)
    }

สำหรับสวิฟต์ 2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Saorikido

3

เป็นการอ้างอิงด่วนเพื่อบันทึกการค้นหาที่อื่น - สร้างที่จัดเก็บถาวรใหม่หลังจากลบแล้วสามารถทำได้ด้วย:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// do something with the error
}

ฉันลองใช้โค้ดของคุณแล้ว แต่ xcode มีข้อยกเว้นในบรรทัดนี้ดังนั้นสิ่งที่คุณต้องพูดเกี่ยวกับเรื่องนี้
Ranjit

3

คำตอบที่ดีสำหรับคำถามนี้ นี่คือข้อสรุปที่ดี สองบรรทัดแรกลบฐานข้อมูล sqlite จากนั้นวง for: จะลบวัตถุใด ๆ ในหน่วยความจำ managedObjectContext

NSURL *storeURL = [[(FXYAppDelegate*)[[UIApplication sharedApplication] delegate] applicationDocumentsDirectory] URLByAppendingPathComponent:@"AppName.sqlite"];
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
for (NSManagedObject *ct in [self.managedObjectContext registeredObjects]) {
    [self.managedObjectContext deleteObject:ct];
}

1
อย่าละเมิดการมอบหมายเพื่อวัตถุประสงค์นี้: hollance.com/2012/02/dont-abuse-the-app-delegate
Michael Dorner

1
ฉันเห็นด้วยกับ @MichaelDorner การเพิ่มสิ่งต่างๆลงใน AppDelegate สามารถส่งผลกระทบต่อประสิทธิภาพการทำงานและขยายขนาดของไบนารีของคุณด้วยใยแมงมุมที่เชื่อมโยงถึงกันซึ่ง AppDelegate จำเป็นต้องรวมไว้ในทุก ๆ ชั้น หากคุณพบว่าการปลูกพืชนี้สร้างตัวควบคุมแยกเฉพาะสำหรับวัตถุประสงค์นี้ AppDelegate ควรจะยังคงอยู่สำหรับการเริ่มต้นขั้นพื้นฐานและการจัดการการเปลี่ยนแปลงสถานะในแอปพลิเคชันไม่มาก
jcpennypincher

2

คุณยังสามารถค้นหาชื่อเอนทิตีทั้งหมดและลบออกโดยใช้ชื่อ มันเป็นรุ่นที่ยาวกว่า แต่ใช้งานได้ดีในแบบที่คุณไม่ต้องทำงานกับร้านขายติดตา

 - (void)clearCoreData
{
NSError *error;
NSEntityDescription *des = [NSEntityDescription entityForName:@"Any_Entity_Name" inManagedObjectContext:_managedObjectContext];
NSManagedObjectModel *model = [des managedObjectModel];
NSArray *entityNames = [[model entities] valueForKey:@"name"];

for (NSString *entityName in entityNames){

    NSFetchRequest *deleteAll = [NSFetchRequest fetchRequestWithEntityName:entityName];
    NSArray *matches = [self.database.managedObjectContext executeFetchRequest:deleteAll error:&error];

}
    if (matches.count > 0){
        for (id obj in matches){

            [_managedObjectContext deleteObject:obj];
        }
       [self.database.managedObjectContext save:&error];
    }
}

สำหรับ "Any_Entity_Name" เพียงแค่ให้ชื่อใด ๆ ของเอนทิตี้ของคุณเราจะต้องหาคำอธิบายเอนทิตีที่เอนทิตีของคุณอยู่ภายใน ValueForKey @ "name" จะส่งคืนชื่อเอนทิตีทั้งหมด สุดท้ายอย่าลืมที่จะบันทึก


2

คำตอบที่ยอมรับนั้นถูกต้องโดยการลบ URL โดย NSFileManager นั้นถูกต้อง แต่ตามที่ระบุไว้ในการแก้ไข iOS 5+ ที่จัดเก็บแบบต่อเนื่องไม่ได้แสดงเพียงไฟล์เดียว สำหรับการจัดเก็บ SQLite เป็น * .sqlite, * .sqlite-shm และ * .sqlite-wal ... โชคดีตั้งแต่ iOS 7+ เราสามารถใช้วิธีการได้

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: ตัวเลือก: ข้อผิดพลาด:]

ดูแลการลบดังนั้นรหัสควรเป็นดังนี้:

NSPersistentStore *store = ...;
NSError *error;
NSURL *storeURL = store.URL;
NSString *storeName = ...;
NSPersistentStoreCoordinator *storeCoordinator = ...;
[storeCoordinator removePersistentStore:store error:&error];
[NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:storeURL.path options:@{NSPersistentStoreUbiquitousContentNameKey: storeName} error:&error];

2
คุณต้องผ่านตัวเลือก dict โดยเฉพาะชื่อร้านเช่น: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
tomi44g

2

นี่คือเวอร์ชันที่ลบทุกระเบียนในทุกตารางที่คุณมี

สวิฟต์ 4

static func resetDatabase() {
    do {
        try dataStore.persistentStoreCoordinator.managedObjectModel.entities.forEach { (entity) in
            if let name = entity.name {
                let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: name)
                let request = NSBatchDeleteRequest(fetchRequest: fetch)
                try mainContext.execute(request)
            }
        }

        try mainContext.save()
    } catch {
        print("error resenting the database: \(error.localizedDescription)")
    }
}

2

Swift 4/5, iOS 9+

การสร้างCoreDataไฟล์ SQLite ใหม่ทั้งหมดจะทำให้แน่ใจว่าข้อมูลทั้งหมดถูกลบดังนั้นเอนทิตีทั้งหมดจะถูกลบ แค่โทรdeleteAndRebuild()มา

class CoreDataStack {
    // Change this
    static let datamodelName = "ProjectName"
    static let storeType = "sqlite"

    static let persistentContainer = NSPersistentContainer(name: datamodelName)
    private static let url: URL = {
        let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).\(storeType)")

        assert(FileManager.default.fileExists(atPath: url.path))

        return url
    }()

    static func loadStores() {
        persistentContainer.loadPersistentStores(completionHandler: { (nsPersistentStoreDescription, error) in
            if let error = error {
                fatalError(error.localizedDescription)
            }
        })
    }

    static func deleteAndRebuild() {
        try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: url, ofType: storeType, options: nil)

        loadStores()
    }
}

สำหรับทุกคนที่ใช้สิ่งนี้โปรดทราบว่ามันจะพัง "ครั้งแรก" เมื่อไม่มีไฟล์ sql อยู่ที่นั่น (ฉันเพิ่งใช้ "ยาม" ในคำตอบของฉัน)
Fattie

1

ใช้ได้กับทุกรุ่น ส่งชื่อเอนทิตีและวนซ้ำเพื่อลบรายการทั้งหมดและบันทึกบริบท

func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) {
    var context = NSManagedObjectContext()
    if #available(iOS 10.0, *) {
        context = self.persistentContainer.viewContext
    } else {
        context = self.managedObjectContext
    }

    let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
    fetchRequest.entity = NSEntityDescription.entity(forEntityName: entityToFetch, in: context)
    fetchRequest.includesPropertyValues = false
    do {
        let results = try context.fetch(fetchRequest) as! [NSManagedObject]
        for result in results {
            context.delete(result)
        }
        try context.save()
        completion(true)
    } catch {
        completion(false)
        print("fetch error -\(error.localizedDescription)")
    }
}

1

อีกวิธีหนึ่ง (นอกเหนือจากคำขอลบแบตช์) ฉันมักจะใช้ (ตามความต้องการของแอพ) คือการรีเซ็ตที่จัดเก็บแบบต่อเนื่อง การใช้งานมีลักษณะเช่นนี้สำหรับ iOS 10+ และ Swift (สมมติว่าคุณมีคลาส CoreDataManager):

let persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "<Data-Model-Name>“)
    container.loadPersistentStores(completionHandler: { (storeDescription, err) in
        if let err = err {
            fatalError("loading of store failed: \(err)")
        }
    })
    return container
}()

func resetPersistentStore() {

    if let persistentStore = persistentContainer.persistentStoreCoordinator.persistentStores.last {
        let storeURL = persistentContainer.persistentStoreCoordinator.url(for: persistentStore)

        do {
            try persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: storeURL, ofType: NSSQLiteStoreType, options: nil)
        } catch {
            print("failed to destroy persistent store:", error.localizedDescription)
        }

        do {
            try persistentContainer.persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
        } catch {
            print("failed to re-add persistent store:", error.localizedDescription)
        }
    }

}

ข้อดีอย่างหนึ่งของวิธีนี้คือมันตรงไปตรงมามากขึ้นโดยเฉพาะเมื่อคุณมีการบันทึกข้อมูลจำนวนมากสำหรับเอนทิตีจำนวนมากในข้อมูลหลักของคุณ ในกรณีนี้คำขอลบแบตช์จะต้องใช้หน่วยความจำมาก



0

ลบไฟล์ร้านค้าถาวรและตั้งค่าผู้ประสานงานร้านค้าถาวรใหม่หรือไม่


6
การทำความสะอาดจะไม่ลบไฟล์เก็บถาวรออกไปขอบคุณ นั่นจะเป็นสูตรสำหรับภัยพิบัติหากเป็นจริง
ฮันเตอร์


0

สมมติว่าคุณกำลังใช้งานMagicalRecordและมีที่เก็บข้อมูลเริ่มต้น:

ฉันไม่ชอบโซลูชันทั้งหมดที่สมมติว่ามีไฟล์บางไฟล์อยู่และ / หรือมีความต้องการป้อนชื่อเอนทิตี้หรือคลาส นี่เป็นวิธีที่รวดเร็วในการลบข้อมูลทั้งหมดออกจากเอนทิตีทั้งหมด หลังจากลบมันจะสร้างกองสดขึ้นมาใหม่ด้วย (จริง ๆ แล้วฉันไม่แน่ใจว่าจำเป็นต้องมีส่วนนี้อย่างไร)

เป็น godo สำหรับสถานการณ์สไตล์ "logout" เมื่อคุณต้องการลบทุกอย่าง แต่มีร้านค้าที่ใช้งานได้และกระทรวงพาณิชย์เพื่อรับข้อมูลใหม่ใน (เมื่อผู้ใช้ลงชื่อเข้าใช้ ... )

extension NSManagedObject {

    class func dropAllData() {

        MagicalRecord.saveWithBlock({ context in

            for name in NSManagedObjectModel.MR_defaultManagedObjectModel().entitiesByName.keys {
                do { try self.deleteAll(name, context: context) }
                catch { print("⚠️ ✏️ Error when deleting \(name): \(error)") }
            }

            }) { done, err in
                MagicalRecord.cleanUp()
                MagicalRecord.setupCoreDataStackWithStoreNamed("myStoreName")
        }
    }

    private class func deleteAll(name: String, context ctx: NSManagedObjectContext) throws {
        let all = NSFetchRequest(entityName: name)
        all.includesPropertyValues = false

        let allObjs = try ctx.executeFetchRequest(all)
        for obj in allObjs {
            obj.MR_deleteEntityInContext(ctx)
        }

    }
}

0

ใช้สิ่งนี้

+(NSArray *)fetchDataFromEntity:(NSString *)entityName context:(NSManagedObjectContext *)context
{
    NSFetchRequest * fetchRequest =[[NSFetchRequest alloc] init];
    NSEntityDescription * CategoriesEntity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
    [fetchRequest setEntity:CategoriesEntity];

    NSError * error;
    NSInteger count = [context countForFetchRequest:fetchRequest error:&error];

    if (count && count>0) {

        NSArray * fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
        if (fetchedObjects && fetchedObjects.count>0) {

            return fetchedObjects;
        }else
            return nil;

    }
    else
        return nil;
}
+ (void)deleteObjectsOfArray:(NSMutableArray*)ary context:(NSManagedObjectContext *)context {
    for (NSManagedObject * obj in ary) {
        [context deleteObject:obj];
    }
    NSError *saveError = nil;
    [context save:&saveError];
}
+ (void)deleteEntity:(NSString *)entityName context:(NSManagedObjectContext *)context {
    NSArray *listArray = [self fetchDataFromEntity:entityName context:context];
    [self deleteObjectsOfArray:[NSMutableArray arrayWithArray:listArray] context:context];
}

0

ฉันใช้รหัสของ Grouchal และเพิ่มความเร็วฉันใช้การแจงนับพร้อมโหมดการทำงานพร้อมกัน ( NSEnumerationConcurrent) มันเร็วขึ้นเล็กน้อยเมื่อเทียบกับการวนซ้ำ (ในแอปของฉันฉันเพิ่มคุณสมบัตินี้สำหรับผู้ทดสอบเพื่อล้างข้อมูลและทำการทดสอบแทนการลบและ ติดตั้งแอพ)

- (void)resetObjects
{
    [self deleteAllObjectsInEntity:@"Entity1"];
    [self deleteAllObjectsInEntity:@"Entity2"];
    [self deleteAllObjectsInEntity:@"Entity3"];
    [self deleteAllObjectsInEntity:@"Entity4"];
}

-(void) deleteAllObjectsInEntity:(NSString*) entityName
{
    MainDataContext *coreDataContext = [MainDataContext sharedInstance];
    NSManagedObjectContext *currentContext = coreDataContext.managedObjectContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:currentContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [currentContext executeFetchRequest:fetchRequest error:&error];

    [items enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSManagedObject * obj, NSUInteger idx, BOOL *stop) {
        [currentContext deleteObject:obj];
    }];


    if (![currentContext save:&error]) {
        NSLog(@"Error deleting %@ - error:%@",entityName,error);
    }
}

0

ที่นี่รุ่น swift3 ของฉันสำหรับลบบันทึกทั้งหมด 'ผู้ใช้' เป็นชื่อเอนทิตี

@IBAction func btnDelAll_touchupinside(_ sender: Any) {

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let managedObjectContext = appDelegate.persistentContainer.viewContext

    let fetchReq = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
    let req = NSBatchDeleteRequest(fetchRequest: fetchReq)

    do {
        try managedObjectContext.execute(req)

    } catch {
        // Error Handling
    }   
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.