Xóa / Đặt lại tất cả các mục trong Dữ liệu cốt lõi?


235

Bạn có biết cách nào để xóa tất cả các mục được lưu trữ trong Dữ liệu cốt lõi không? Lược đồ của tôi nên giữ nguyên; Tôi chỉ muốn đặt lại nó để trống.


Biên tập

Tôi đang tìm cách làm điều này theo chương trình để người dùng về cơ bản có thể nhấn resetnút.


6
Nhiều câu trả lời dưới đây là ngày. Sử dụng NSBatchDeleteRequest. stackoverflow.com/a/31961330/3681880
Suragch

Câu trả lời:


198

Bạn vẫn có thể xóa tệp theo chương trình, sử dụng phương thức NSFileManager: removeItemAtPath ::.

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

Sau đó, chỉ cần thêm cửa hàng liên tục trở lại để đảm bảo nó được tạo lại đúng cách.

Cách lập trình để lặp qua từng thực thể là chậm hơn và dễ bị lỗi. Việc sử dụng để làm theo cách đó là nếu bạn muốn xóa một số thực thể chứ không phải các thực thể khác. Tuy nhiên, bạn vẫn cần đảm bảo rằng bạn giữ được tính toàn vẹn tham chiếu hoặc bạn sẽ không thể tiếp tục thay đổi.

Chỉ cần loại bỏ các cửa hàng và tạo lại nó là nhanh chóng và an toàn, và chắc chắn có thể được thực hiện theo chương trình trong thời gian chạy.

Cập nhật cho iOS5 +

Với việc giới thiệu bộ nhớ nhị phân ngoài (allowExternalBinaryDataStorage hoặc Store trong Tệp ghi ngoài) trong iOS 5 và OS X 10.7, chỉ cần xóa các tệp được lưu trữ bởi storeURLs là không đủ. Bạn sẽ để lại các tập tin hồ sơ bên ngoài phía sau. Vì sơ đồ đặt tên của các tệp bản ghi bên ngoài này không công khai, tôi chưa có giải pháp chung. - an0 ngày 8 tháng 5 năm 12 lúc 23:00


1
Đây có lẽ là giải pháp tốt nhất cho độ tin cậy. Nếu tôi muốn xóa một số nhưng không phải tất cả dữ liệu, tôi sẽ sử dụng dữ liệu này: stackoverflow.com/questions/1077810/
dọa

12
Tôi biết làm thế nào để lấy đúng StoreCoordinator. Tuy nhiên tôi không biết làm thế nào để có được kiên trì. Vì vậy, bạn có thể vui lòng đưa ra một ví dụ thích hợp thay vì chỉ: NSPersistentStore * store = ...;
Pascal Klein

11
[[NSFileManager defaultManager] removeItemAtURL: lỗi storeURL: & error] là tốt hơn.
an0

3
@Pascal Nếu bạn có thể có được điều phối viên cửa hàng thì bạn có quyền truy cập vào tất cả các cửa hàng liên tục của nó thông qua thuộc tính PersentStores.
Mihai Damian

2
Mã ví dụ bao gồm cách tạo lại một cửa hàng trống mới tại đây: stackoverflow.com/a/8467628
Joshua C. Lerner

140

Bạn có thể xóa tệp SQLite - nhưng tôi chọn thực hiện bằng cách xóa các bảng riêng lẻ bằng một hàm:

- (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);
    }

}

Lý do tôi chọn thực hiện theo từng bảng là vì nó khiến tôi xác nhận khi tôi đang thực hiện chương trình xóa nội dung của bảng là hợp lý và không có dữ liệu mà tôi muốn giữ.

Làm điều này sẽ chậm hơn nhiều so với việc chỉ xóa tệp và tôi sẽ thay đổi thành xóa tệp nếu phương pháp này mất quá nhiều thời gian.


Giải pháp tuyệt vời. Cảm ơn. DLog () là gì?
Michael Grinich

À đúng rồi - xin lỗi, đó là một chức năng đặc biệt tôi sử dụng chỉ thực hiện NSLog khi bản dựng là bản dựng DEBUG - chỉ cần thay thế bằng NSLog.
Grouchal

6
Bạn có thể xem triển khai DLog tại đây: cimgf.com/2009/01/24/dropping-nslog-in-release-builds
Matt Long

3
Điều này làm việc độc đáo cho tôi. Nhưng để làm cho nó đi nhanh hơn, có cách nào để xóa tất cả các đối tượng của một thực thể nhất định bằng một lệnh không? Giống như trong SQL, bạn có thể làm một cái gì đó như, DROP TABLE entity_name. Tôi không muốn xóa toàn bộ tệp SQL vì tôi chỉ muốn xóa tất cả các đối tượng của một thực thể cụ thể, không phải các thực thể khác.
ma11hew28

8
Sử dụng NSDadata * allEntities = _managedObjectModel.entitiesByName; để có được tất cả các thực thể trong mô hình của bạn và sau đó bạn có thể lặp lại các khóa trong NSDipedia này để lọc tất cả các thực thể trong cửa hàng.
adam0101

60

Giải pháp cập nhật cho iOS 10+

Sử dụng NSBatchDeleteRequestđể xóa tất cả các đối tượng trong thực thể mà không phải tải chúng vào bộ nhớ hoặc lặp qua chúng.

// 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)
}

Mã này đã được cập nhật cho iOS 10 và Swift 3. Nếu bạn cần hỗ trợ iOS 9, hãy xem câu hỏi này .

Nguồn:


3
Tôi sẽ đặt rằng toàn bộ khối bên trong một moc.performBlockAndWait({ () -> Void in... }).
SwiftArchitect

2
Hãy chắc chắn rằng bạn thấy Tại sao các mục không bị xóa cho đến khi ứng dụng được khởi động lại hoặc tôi thực thi NSBatchDeleteRequest của mình hai lần? Câu chuyện dài mã trên là KHÔNG đủ nếu các thực thể được tải vào bộ nhớ
Honey

38

Tôi đã viết một clearStoresphương thức đi qua mọi cửa hàng và xóa cả hai khỏi bộ điều phối và hệ thống tập tin (xử lý lỗi sang một bên):

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;

Phương thức này nằm trong một coreDataHelperlớp chăm sóc (trong số những thứ khác) tạo ra kiên trìStore khi nó không.


"không có phương thức lớp nào được biết cho bộ chọn 'kiên
trìStores

27

Tôi xóa tất cả dữ liệu khỏi dữ liệu cốt lõi trên một nút Sự kiện trong lớp HomeViewControll: Bài viết này đã giúp tôi rất nhiều, tôi nghĩ rằng tôi đã đóng góp.

-(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
    }

}

Lưu ý rằng để gọi self.persistentStoreCoordinator, tôi đã khai báo một thuộc tính trong Trình điều khiển Home View. (Đừng lo lắng về ManagedObjectContext mà tôi sử dụng để lưu và tải.)

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

Sau đó, trong AppDelegate ApplicationDidFinishLaunching ngay bên dưới tạo HomeViewControll tôi có:

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

@ayteat, đã làm việc này cho bạn?. Đối với tôi nó không hoạt động, xin hãy xem stackoverflow.com/questions/14646595/iêu
Ranjit

1
ĐÂY LÀ TRẢ LỜI ngoại trừ sử dụng "AppDelegate * ad = [[UIApplication sharedApplication] đại biểu];" và tự thay thế bằng quảng cáo. và không sao chép hai bit mã cuối cùng
Cescy

1
Tại sao bạn không gọi thiết lập lại trên ManagedObjectContext? Điều gì nếu bạn có một số tài liệu tham khảo mạnh mẽ về ManagedObject?
Parag Bafna

@ParagBafna Bạn đã đúng, mẫu mã ở trên giả định rằng không có tham chiếu mạnh đến các đối tượng được quản lý. Nếu bạn có một số, bạn nên xem việc gọi 'reset' trên ManagedObjectContext và hủy tham chiếu bất kỳ đối tượng được quản lý nào bạn có.
vào

Này cảm ơn nhé. Ngoài ra, có cách nào để làm điều này khi nâng cấp ứng dụng không? Nói chính xác, yêu cầu của tôi là khi tôi tung phiên bản ứng dụng tiếp theo của chúng tôi, thời điểm đó khi người dùng cập nhật ứng dụng của họ từ appStore, các tệp n sqlite dữ liệu cốt lõi sẽ bị xóa và sắp xếp lại thành trống. Tôi đã tìm ra cách để phát hiện sự kiện khởi chạy ứng dụng đầu tiên bằng cách sử dụng giá trị Bool trong NSUserDefaults và kiểm tra giá trị này trong didfinishLaunchingWithOptions của đại biểu ứng dụng, nhưng không hiểu cách xóa tất cả những điều này. Vì không có nút và đại biểu ứng dụng sẽ không phát hiện ra "ContinentStore" của tôi để xóa nó như bạn đã làm ở trên. Có ai giúp đỡ không?
Tejas

19

MagicalRecord làm điều này rất dễ dàng.

[MyCoreDataObject MR_truncateAll];

16
Điều này thật tuyệt, nhưng lạc đề vì tôi đã chỉ định một giải pháp CoreData
Michael Grinich

8
Active Record Fetching một giải pháp dữ liệu cốt lõi.
casademora

7
Nhưng một câu trả lời như thế này vượt ra ngoài phạm vi của câu hỏi. Không có lý do gì để cho rằng anh ta muốn sử dụng khung addt'l để làm điều này.
jpswain

Tôi cho rằng điều này không trả lời câu hỏi. Đây là một cách tốt để xóa các mục khỏi một thực thể, không phải tất cả các thực thể ...! Làm thế nào để bạn liệt kê thông qua tất cả các thực thể trong mô hình và gửi MR_truncateAllchúng?
fatuhoku

Xem nguồn cho MR_truncate ALL - nó tìm nạp tất cả các đối tượng nhưng không phải thuộc tính của chúng (vì chúng tôi dự định loại bỏ NSMO), sau đó nó lặp lại các đối tượng cho thực thể được chỉ định và xóa chúng. github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/ory
1in9ui5t

19

iOS9 +, Swift 2

Xóa tất cả các đối tượng trong tất cả các thực thể

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
Hãy chắc chắn rằng bạn thấy Tại sao các mục không bị xóa cho đến khi ứng dụng được khởi động lại hoặc tôi thực thi NSBatchDeleteRequest của mình hai lần? Câu chuyện dài mã trên là KHÔNG đủ nếu các thực thể được tải vào bộ nhớ
Honey

13

[Trả lời muộn để trả lời tiền thưởng yêu cầu trả lời mới hơn]

Nhìn qua các câu trả lời trước đó,

  • Tìm nạp và xóa tất cả các mục, theo đề xuất của @Grouchal và các mục khác, vẫn là một giải pháp hiệu quả và hữu ích. Nếu bạn có kho dữ liệu rất lớn thì có thể chậm, nhưng nó vẫn hoạt động rất tốt.
  • Đơn giản chỉ cần xóa kho lưu trữ dữ liệu là, như bạn và @groundoose lưu ý, không còn hiệu quả. Nó đã lỗi thời ngay cả khi bạn không sử dụng bộ nhớ nhị phân bên ngoài vì iOS 7 sử dụng chế độ WAL để ghi nhật ký SQLite. Với chế độ WAL, có thể có các tệp nhật ký (có khả năng lớn) nằm xung quanh cho bất kỳ cửa hàng lưu trữ liên tục Core Data nào.

Nhưng có một cách tiếp cận khác, tương tự để loại bỏ các cửa hàng liên tục hoạt động. Điều quan trọng là đặt tệp lưu trữ liên tục của bạn vào thư mục con riêng không chứa bất kỳ thứ gì khác. Đừng chỉ dán nó vào thư mục tài liệu (hoặc bất cứ nơi nào), hãy tạo một thư mục con mới chỉ dành cho cửa hàng liên tục. Nội dung của thư mục đó cuối cùng sẽ là tệp lưu trữ liên tục, tệp nhật ký và tệp nhị phân bên ngoài. Nếu bạn muốn nuke toàn bộ kho dữ liệu, hãy xóa thư mục đó và tất cả chúng sẽ biến mất.

Bạn sẽ làm một cái gì đó như thế này khi thiết lập cửa hàng liên tục của bạn:

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...
}

Sau đó, khi bạn muốn loại bỏ các cửa hàng,

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

Điều đó đệ quy loại bỏ cả thư mục con tùy chỉnh và tất cả các tệp Dữ liệu lõi trong đó.

Điều này chỉ hoạt động nếu bạn chưa có cửa hàng liên tục trong cùng thư mục với các dữ liệu quan trọng khác . Giống như thư mục tài liệu, có lẽ có những thứ hữu ích khác trong đó. Nếu đó là tình huống của bạn, bạn có thể có được hiệu ứng tương tự bằng cách tìm kiếm các tệp mà bạn làm muốn giữ lại và loại bỏ tất cả mọi thứ khác. Cái gì đó như:

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.
}

Cách tiếp cận này có thể dễ bị lỗi . Bạn phải hoàn toàn chắc chắn rằng bạn biết mọi tệp bạn muốn giữ, vì nếu không, bạn có thể xóa dữ liệu quan trọng. Mặt khác, bạn có thể xóa các tệp nhị phân bên ngoài mà không thực sự biết tên tệp / thư mục được sử dụng để lưu trữ chúng.


nếu bạn sợ tập tin wal, chỉ cần vô hiệu hóa nó
onmyway133 27/07/14

11

Đây là giải pháp kết hợp để thanh lọc dữ liệu cốt lõi.

- (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

Nếu bạn muốn xóa tất cả các đối tượng và không muốn xóa các tệp sao lưu, bạn có thể sử dụng các phương pháp sau:

- (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);
    }
}

Coi chừng rằng nó có thể rất chậm (phụ thuộc vào số lượng đối tượng trong biểu đồ đối tượng của bạn).


cách xóa dữ liệu cũ hơn (giả sử ba bảng, từ một bảng tôi muốn xóa dữ liệu) khi cập nhật ứng dụng
Madan Mohan

6

Nếu bạn muốn đi theo lộ trình xóa tất cả các đối tượng (đơn giản hơn nhiều so với phá bỏ ngăn xếp Dữ liệu lõi, nhưng ít hiệu suất hơn), thì đây là cách triển khai tốt hơn:

- (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];
}

Việc triển khai này tận dụng NSOperationđể thực hiện xóa khỏi luồng chính và thông báo khi hoàn thành. Bạn có thể muốn phát ra một thông báo hoặc một cái gì đó trong khối hoàn thành để đưa trạng thái trở lại luồng chính.


Lưu ý rằng NSManagedObjectContext của bạn phải được khởi tạo như thế nào NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];để sử dụng phương thức này nếu không bạn sẽ gặp lỗi:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
Sẽ

6

Giải pháp 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()
        }
    }
}

Lặp lại thông qua tất cả các thực thể dữ liệu cốt lõi và xóa chúng


4

Cảm ơn vì bài đăng. Tôi đã làm theo nó và nó làm việc cho tôi. Nhưng tôi có một vấn đề khác không được đề cập trong bất kỳ câu trả lời nào. Vì vậy, tôi không chắc chắn nếu đó chỉ là tôi.

Dù sao, nghĩ rằng tôi sẽ đăng ở đây vấn đề và cách của tôi đã giải quyết nó.

Tôi đã có một vài bản ghi trong cơ sở dữ liệu, tôi muốn xóa sạch mọi thứ trước khi ghi dữ liệu mới vào db, vì vậy tôi đã làm mọi thứ kể cả

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

và sau đó được sử dụng managedObjectContextđể truy cập cơ sở dữ liệu (được cho là trống bây giờ), bằng cách nào đó dữ liệu vẫn còn đó. Sau một thời gian khắc phục sự cố, tôi thấy rằng tôi cần phải thiết lập lại managedObjectContext, managedObject, managedObjectModelpersistentStoreCoordinator, trước khi tôi sử dụng managedObjectContextđể truy cập dabase. Bây giờ tôi có một cơ sở dữ liệu sạch để viết.


Vì vậy, đặt lại ManagedObjectContext, ManagedObject, ManagedObjectModel và continentStoreCoordinator đặt tệp chứa cơ sở dữ liệu trở lại sau khi nó đã bị xóa?
Daniel Brower

4

Đây là một phiên bản được đơn giản hóa với ít cuộc gọi đến bản thân AppDelegate và đoạn mã cuối cùng bị loại khỏi câu trả lời được xếp hạng hàng đầu. Ngoài ra, tôi đã nhận được một lỗi "Cửa hàng liên tục của đối tượng không thể truy cập được từ điều phối viên NSManagedObjectContext này" vì vậy chỉ cần thêm lại.

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

giải pháp nhanh chóng:

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)
    }

Dành cho người nhanh 2let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
Saorikido

3

Là một tài liệu tham khảo nhanh để lưu tìm kiếm ở nơi khác - tạo lại cửa hàng liên tục sau khi xóa nó có thể được thực hiện với:

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

Tôi đã thử mã của bạn, nhưng xcode ném một ngoại lệ trên dòng này, vì vậy bạn phải nói gì về điều này.
Ranjit

3

Một số câu trả lời tốt cho câu hỏi này. Đây là một súc tích tốt đẹp. Hai dòng đầu tiên xóa cơ sở dữ liệu sqlite. Sau đó, vòng lặp for: xóa bất kỳ đối tượng nào trong bộ nhớ 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
Đừng lạm dụng phái đoàn cho mục đích này: hollance.com/2012/02/dont-abuse-the-app-delegate
Michael Dorner

1
Tôi đồng ý với @MichaelDorner. Thêm nhiều vào AppDelegate có thể ảnh hưởng đến hiệu suất và làm tăng kích thước nhị phân của bạn với một mạng nhện phụ thuộc được kết nối với nhau, nơi AppDelegate đột nhiên cần được đưa vào mỗi lớp. Nếu bạn thấy việc cắt xén này, hãy tạo một bộ điều khiển riêng biệt cho mục đích này. AppDelegate nên duy trì khởi tạo cơ bản và xử lý các thay đổi trạng thái trong ứng dụng, không nhiều hơn thế.
jcpennypincher

2

bạn cũng có thể tìm thấy tất cả các tên thực thể và xóa chúng theo tên. Đây là phiên bản dài hơn nhưng hoạt động tốt, theo cách đó bạn không phải làm việc với cửa hàng kiên trì

 - (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];
    }
}

đối với "Any_Entity_Name" chỉ cần cung cấp bất kỳ tên nào trong tên thực thể của bạn, chúng tôi chỉ cần tìm ra mô tả thực thể mà thực thể của bạn nằm trong. ValueForKey @ "name" sẽ trả về tất cả các tên thực thể. Cuối cùng, đừng quên tiết kiệm.


2

Câu trả lời được chấp nhận là chính xác với việc xóa URL bởi NSFileManager là chính xác, nhưng như đã nêu trong chỉnh sửa iOS 5+, cửa hàng liên tục không chỉ được đại diện bởi một tệp. Đối với cửa hàng SQLite, đó là * .sqlite, * .sqlite-shm và * .sqlite-wal ... may mắn là từ iOS 7+ chúng ta có thể sử dụng phương thức

[NSPersistentStoreCoordinator + removeUbiquitousContentAndPersistentStoreAtURL: tùy chọn: lỗi:]

để chăm sóc loại bỏ, vì vậy mã phải giống như thế này:

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
Bạn cần phải vượt qua các tùy chọn dict, đặc biệt là tên cửa hàng, ví dụ: @ {NSPersistentStoreUbiquitousContentNameKey: @ "MyData"};
tomi44g

2

Swift 4/5, iOS 9+

Việc xây dựng lại toàn bộ CoreDatatệp SQLite sẽ đảm bảo tất cả dữ liệu bị xóa, do đó tất cả các thực thể đều bị xóa. Chỉ cần gọi 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()
    }
}

Đối với bất kỳ ai sử dụng điều này, xin lưu ý rằng nó sẽ bị sập "lần đầu tiên" khi không có tệp sql ở đó (tôi chỉ sử dụng một "người bảo vệ" trong câu trả lời của mình)
Fattie

1

Hoạt động với tất cả các phiên bản. Truyền tên thực thể và lặp qua để xóa tất cả các mục và lưu bối cảnh.

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

Đây là phiên bản xóa mọi bản ghi trong mỗi bảng bạn có.

Swift 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)")
    }
}

1

Một phương pháp khác (ngoài yêu cầu xóa hàng loạt) tôi thường sử dụng (dựa trên yêu cầu ứng dụng) là đặt lại cửa hàng liên tục. Việc triển khai trông như thế này cho iOS 10+ và Swift (giả sử bạn có lớp 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)
        }
    }

}

Một lợi thế của phương pháp này là nó đơn giản hơn, đặc biệt là khi bạn có vô số bản ghi dữ liệu cho nhiều thực thể trong dữ liệu cốt lõi của mình. Trong trường hợp đó, một yêu cầu xóa hàng loạt sẽ cần nhiều bộ nhớ.


1

Giải pháp Swift 5.1

public static func reset() {
    let coordinator = _persistentContainer.persistentStoreCoordinator
    for store in coordinator.persistentStores where store.url != nil {
        try? coordinator.remove(store)
        try? FileManager.default.removeItem(atPath: store.url!.path)
    }
}

0

Xóa tập tin lưu trữ liên tục và thiết lập một điều phối viên lưu trữ liên tục mới?


6
Làm sạch sẽ không loại bỏ các tập tin lưu trữ liên tục, rất may. Đó sẽ là một công thức cho thảm họa nếu đúng.
Thợ săn

0

Xóa sqlite khỏi fileURLPath của bạn và sau đó xây dựng.


Tôi có nghĩa là khi ứng dụng được cài đặt.
Michael Grinich

0

Giả sử bạn đang sử dụng MagicalRecordvà có một cửa hàng lưu trữ bền vững mặc định:

Tôi không thích tất cả các giải pháp giả định các tệp nhất định tồn tại và / hoặc yêu cầu nhập tên hoặc lớp thực thể. Đây là Swift (2), cách an toàn để xóa tất cả dữ liệu khỏi tất cả các thực thể. Sau khi xóa nó cũng sẽ tạo lại một ngăn xếp mới (tôi thực sự không chắc chắn về việc phần này được xử lý như thế nào).

Thật tuyệt vời cho các tình huống kiểu "đăng xuất" khi bạn muốn xóa mọi thứ nhưng có một cửa hàng hoạt động và moc để lấy dữ liệu mới (khi người dùng đăng nhập ...)

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

Dùng cái này

+(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

Tôi đã lấy mã của Grouchal và để tăng tốc, tôi đã sử dụng phép liệt kê với chế độ đồng thời ( NSEnumerationConcurrent), nó nhanh hơn một chút so với vòng lặp (trong ứng dụng của tôi, tôi đã thêm tính năng này cho Người kiểm tra để họ có thể xóa dữ liệu và thực hiện kiểm tra thay vì xóa và kiểm tra cài đặt ứng dụng)

- (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

đây là phiên bản swift3 của tôi để xóa tất cả các hồ sơ. 'Người dùng' là tên thực thể

@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
    }   
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.