私は、Webサービス呼び出しからの結果をローカルに保持するためにCore Dataを使用しています。たとえば、 "Cars"の場合、Webサービスは完全なオブジェクトモデルを返します。そのうち約2000個になる可能性があります(そして、Webサービスに1台以下の自動車を返させることはできません)。
次回アプリケーションを開くときに、すべてのCarsに対してWeb Serviceを再度呼び出してCore Data永続コピーを更新したいのですが、重複を防ぐために、最初にローカルキャッシュのすべてのデータを消去する必要があります。
管理オブジェクトコンテキスト内の特定のエンティティのすべてのインスタンス(たとえば、タイプ "CAR"のすべてのエンティティ)を削除するより早い方法はありますか。それとも呼び出してクエリし、結果を繰り返して削除して保存する必要がありますか。
理想的には、実体がBlahの場所ですべて削除すると言うことができます。
iOS 9では、NSBatchDeleteRequest
という新しいクラスが追加されました。これを使用すると、述語に一致するオブジェクトをすべてメモリに読み込むことなく簡単に削除できます。使い方は次のとおりです。
let fetchRequest = NSFetchRequest(entityName: "Car")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try myPersistentStoreCoordinator.executeRequest(deleteRequest, withContext: myContext)
} catch let error as NSError {
// TODO: handle the error
}
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Car"];
NSBatchDeleteRequest *delete = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];
NSError *deleteError = nil;
[myPersistentStoreCoordinator executeRequest:delete withContext:myContext error:&deleteError];
バッチ削除の詳細については、 WWDC 2015の "Core Dataの新機能" (〜14:10以降)を参照してください。
「すべてを取得してすべてを削除」:
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
もう少しクリーンで普遍的:このメソッドを追加してください:
- (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];
}
Swiftでエンティティをリセットします。
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")
}
}
Swift 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")
}
}
Swift:
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)")
}
これは こちら とよく似た質問です。関係削除規則を設定して、1つのオブジェクトだけを削除すればよいという人もいます。そのため、上位のエンティティを削除するときに、自動車に対して1対多の関係を持つエンティティを作成し、削除ルールをカスケードに設定すると、すべての自動車も削除されます。あなたがすべての車をロードすることに関連したステップをする必要がないので、これはいくらかの処理時間を節約するかもしれません。より大きなデータセットでは、これは絶対に必要かもしれません。
良い答えがすでに投稿されています、これは単なる推奨事項です!
良い方法は、カテゴリを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
...あなたがしなければならない唯一のことは、アプリのデリゲートからmanagedObjectContextを取得することです。
その後は次のように使えます。
[NSManagedObject deleteAllFromEntity:@"EntityName"];
もう1つの最適化は、entitynameのパラメータを削除し、代わりにclazznameから名前を取得することです。これは使用法につながるでしょう:
[ClazzName deleteAllFromEntity];
(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"];
iOS 10以降
すべてのバージョンで動作します。エンティティ名を渡して、すべてのエントリを削除してコンテキストを保存するまで繰り返します。
func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) {
let context = NSManagedObjectContext()
context = your 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)")
}
}
Swift 3.XとSwift 4.X、簡単な方法です。変更のみYourTable
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "YourTable")
fetchRequest.returnsObjectsAsFaults = false
do
{
let results = try context.fetch(fetchRequest)
for managedObject in results
{
let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
context.delete(managedObjectData)
}
} catch let error as NSError {
print("Detele all my data in \(entity) error : \(error) \(error.userInfo)")
}
Dave Delongの答えを拡張する。
IOS 9とそれ以前のバージョンにも対応しているSwiftバージョン。私はまたこれでエラー処理をカバーしました:
appDelegate:AppDelegate = UIApplication.sharedApplication()を委任してください。 AppDelegate
let fetchRequest = NSFetchRequest(entityName: "Car")
if #available(iOS 9.0, *) {
let delete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try appDelegate.persistentStoreCoordinator.executeRequest(delete, withContext: appDelegate.managedObjectContext)
} catch let error as NSError {
print("Error occured while deleting: \(error)")
}
} else {
// Fallback on earlier versions
let carRequest = NSFetchRequest()
carRequest.entity = NSEntityDescription.entityForName("Cars", inManagedObjectContext: appDelegate.managedObjectContext)
carRequest.includesPropertyValues = false
do {
let cars: NSArray = try appDelegate.managedObjectContext.executeFetchRequest(carRequest)
for car in cars {
appDelegate.managedObjectContext.delete(car)
}
try appDelegate.managedObjectContext.save()
} catch let error as NSError {
print("Error occured while fetching or saving: \(error)")
}
}
Swift 4、iOS 12、Xcode 10 Update
100%作業中のカットアンドペースト
この関数を適切なクラスに入れるだけです。
そしてこの関数をself.deleteData()
内でviewDidLoad()
と呼びます。
ボタンをクリックすることでentityからのすべてのデータが削除され、あなたがあなたのコアデータで定義したあなたのエンティティとしての "myEntity"を置き換えるように
func deleteData() {
let appDel:AppDelegate = (UIApplication.shared.delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "myEntity")
fetchRequest.returnsObjectsAsFaults = false
do
{
let results = try context.fetch(fetchRequest)
for managedObject in results
{
let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
context.delete(managedObjectData)
}
} catch let error as NSError {
print("Deleted all my data in myEntity error : \(error) \(error.userInfo)")
}
}
受信したデータを既存のキャッシュに入れないのはなぜですか。それ以外の場合は、実際には「リフレッシュ」ではなく、「再開」しているので、SQLLiteファイルを削除または削除してから再開することもできます(他のデータも保持されていないと仮定)。
エンティティに多くのエントリが含まれている場合は、メモリを節約するため、最善の方法は次のようになります。
- (void)deleteAll:(NSManagedObjectContext *)managedObjectContext entityName:(NSString *)entityName
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[managedObjectContext setUndoManager:nil];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setIncludesPropertyValues:NO];
[fetchRequest setFetchLimit:100]; // you can change this number if you want
NSError *error;
NSArray *items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
while ([items count] > 0) {
@autoreleasepool {
for (NSManagedObject *item in items) {
[managedObjectContext deleteObject:item];
}
if (![managedObjectContext save:&error]) {
NSLog(@"Error deleting %@ - error:%@",self.entityName, error);
}
}
items = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
}
}
Swift 4、iOS 10以降
すべてのデータを削除するために任意のエンティティに適用できる静的関数
protocol NSManagedObjectHelper {
}
extension NSManagedObject: NSManagedObjectHelper {
}
extension NSManagedObjectHelper where Self: NSManagedObject {
static func removeAllObjectsInContext(_ managedContext: NSManagedObjectContext) {
let request: NSFetchRequest = Self.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)
do {
deleteRequest.resultType = .resultTypeObjectIDs//to clear objects from memory
let result = try managedContext.execute(deleteRequest) as? NSBatchDeleteResult
if let objectIDArray = result?.result as? [NSManagedObjectID] {
let changes = [NSDeletedObjectsKey : objectIDArray]
/*By calling mergeChangesFromRemoteContextSave, all of the NSManagedObjectContext instances that are referenced will be notified that the list of entities referenced with the NSManagedObjectID array have been deleted and that the objects in memory are stale. This causes the referenced NSManagedObjectContext instances to remove any objects in memory that are loaded which match the NSManagedObjectID instances in the array.*/
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [managedContext])
}
try managedContext.save()
} catch let error {
print(error)
}
}
}
「部屋」は実体です
Room.removeAllObjectsInContext(self.persistentContainer.viewContext)
Swift 3.0では
func deleteAllRecords() {
//delete all data
let context = appDelegate.persistentContainer.viewContext
let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "YourClassName")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
do {
try context.execute(deleteRequest)
try context.save()
} catch {
print ("There was an error")
}
}
このコードはiOS 9以下で動作します。
class func deleteAllRecords(in entity : String) // entity = Your_Entity_Name
{
let context = CoreDataStack.getContext() // Note:- Replace your context here with CoreDataStack.getContext()
let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entity)
if #available(iOS 9, *)
{
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
do
{
try context.execute(deleteRequest)
try context.save()
}
catch
{
print("There was an error:\(error)")
}
}
else
{
do{
let deleteRequest = try context.fetch(deleteFetch)
for anItem in deleteRequest {
context.delete(anItem as! NSManagedObject)
}
}
catch
{
print("There was an error:\(error)")
}
}
CoreDataStack.saveContext() // Note:- Replace your savecontext here with CoreDataStack.saveContext()
}
iOS 9.0以降
NSBatchDeleteRequest
は、コアデータ内のレコードを削除するために使用されます。それは非常に速く動作し、エンティティからすべてのレコードを削除するのにより少ない時間がかかります。引数にNSFetchRequest
が必要です。あなたがエンティティからすべてのレコードを削除したい場合は、それを使用することができ、それは私のために働く。
let manageObject:NSManagedObjectContext = appDelegateObject.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: “EnityName”)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
let persistCor:NSPersistentStoreCoordinator = appDelegateObject.persistentObject
do {
try persistCor.executeRequest(deleteRequest, withContext: manageObject)
try manageObject.save()
} catch {
print(error?.localizedDescription)
}
func deleteAll(entityName: String) {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
deleteRequest.resultType = .resultTypeObjectIDs
guard let context = self.container?.viewContext
else { print("error in deleteAll")
return }
do {
let result = try context.execute(deleteRequest) as? NSBatchDeleteResult
let objectIDArray = result?.result as? [NSManagedObjectID]
let changes: [AnyHashable : Any] = [NSDeletedObjectsKey : objectIDArray as Any]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context])
} catch {
print(error.localizedDescription)
}
}
dB内のすべてのオブジェクトのクイックパージ:
func purgeAllData() {
let uniqueNames = persistentContainer.managedObjectModel.entities.compactMap({ $0.name })
uniqueNames.forEach { (name) in
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name)
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try persistentContainer.viewContext.execute(batchDeleteRequest)
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
IOS 9「NSBatchDeleteRequest」を使用したSwift 3ソリューション、および「NSManagedObjectContext」の拡張機能として実装された以前のiOSバージョンへのフォールバック。アップルリファレンス https://developer.Apple.com/library/content/featuredarticles/CoreData_Batch_Guide/BatchDeletes/BatchDeletes.html
extension NSManagedObjectContext {
func batchDeleteEntities<T: NSManagedObject>(ofType type: T.Type) throws {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: type.self))
if #available(iOS 9.0, *) {
let request = NSBatchDeleteRequest(fetchRequest: fetchRequest)
let result = try execute(request) as? NSBatchDeleteResult
if let objectIDArray = result?.result as? [NSManagedObjectID] {
let changes = [NSDeletedObjectsKey: objectIDArray]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
}
} else {
fetchRequest.includesPropertyValues = false
let results = try fetch(fetchRequest)
if let actualResults = results as? [NSManagedObject], !actualResults.isEmpty {
actualResults.forEach { delete($0) }
}
}
}
}
Minimum iOSが9.0の場合は、NSBatchDeleteRequestを使用して複数のレコードを削除します。バックグラウンドスレッドの場合は、NSManagedObjectContext saveを実行します。それ以外の場合はNSFetchRequestを使用してレコードを取得し、forループ内のすべてのレコードを削除します。
iOS 11.3およびSwift 4.1の場合
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest )
batchDeleteRequest.resultType = .resultTypeCount
do {
let batchDeleteResult = try dataController.viewContext.execute(batchDeleteRequest) as! NSBatchDeleteResult
print("The batch delete request has deleted \(batchDeleteResult.result!) records.")
dataController.viewContext.reset() // reset managed object context (need it for working)
} catch {
let updateError = error as NSError
print("\(updateError), \(updateError.userInfo)")
}
実行後にresetを呼び出す必要があります。そうでない場合は、テーブルビューでは更新されません。
Dave DelongsのSwift 2.0の答えが私のためにクラッシュしていました(iOS 9)
しかしこれはうまくいった:
let fetchRequest = NSFetchRequest(entityName: "Car")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try managedObjectContext.executeRequest(deleteRequest)
try managedObjectContext.save()
}
catch let error as NSError {
// Handle error
}