更新:在下面的讨论中,基于James Huddleston的想法,提出了更好的答案。
- (BOOL)hasManagedObjectBeenDeleted:(NSManagedObject *)managedObject {
NSParameterAssert(managedObject);
NSManagedObjectContext *moc = [self managedObjectContext];
if ([moc respondsToSelector:@selector(existingObjectWithID:error:)])
{
NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *managedObjectClone = [moc existingObjectWithID:objectID error:NULL];
if (!managedObjectClone)
return YES;
else
return NO;
}
else if ([moc respondsToSelector:@selector(countForFetchRequest:error:)])
{
if (![managedObject managedObjectContext])
return YES;
NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *managedObjectClone = [moc objectWithID:objectID];
NSEntityDescription *entityDescription = [managedObjectClone entity];
NSDictionary *propertiesByName = [entityDescription propertiesByName];
NSArray *propertyNames = [propertiesByName allKeys];
NSAssert1([propertyNames count] != 0, @"Method cannot detect if |managedObject| has been deleted because it has zero Properties defined: %@", managedObject);
@try
{
(void)[managedObjectClone valueForKey:[propertyNames objectAtIndex:0]];
return NO;
}
@catch (NSException *exception)
{
if ([[exception name] isEqualToString:NSObjectInaccessibleException])
return YES;
else
[exception raise];
}
}
else
{
NSAssert(0, @"Unsupported version of Mac OS X detected.");
}
}
旧版/废弃的回答:
我写了一个稍微好一点的方法。 self
是你的 Core Data 类/控制器。
- (BOOL)hasManagedObjectBeenDeleted:(NSManagedObject *)managedObject
{
if (![managedObject managedObjectContext])
return YES;
NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *managedObjectClone = [[self managedObjectContext] objectWithID:objectID];
NSEntityDescription *entityDescription = [managedObjectClone entity];
NSDictionary *propertiesByName = [entityDescription propertiesByName];
NSArray *propertyNames = [propertiesByName allKeys];
@try
{
for (id propertyName in propertyNames)
(void)[managedObjectClone valueForKey:propertyName];
return NO;
}
@catch (NSException *exception)
{
if ([[exception name] isEqualToString:NSObjectInaccessibleException])
return YES;
else
[exception raise];
}
}
如
James Huddleston在他的回答中提到的那样,检查 NSManagedObject 的
-managedObjectContext
是否返回
nil
是一种“相当不错”的方法,可以看出缓存/过时的 NSManagedObject 是否已从持久化存储中删除,但正如苹果在其文档中所述,它并不总是准确的:
如果接收者已从其上下文中删除,则此方法可能返回nil。
什么情况下它将不会返回 nil? 如果您使用已删除的 NSManagedObject 的 -objectID
获取了不同的 NSManagedObject,如下所示:
CoreData *coreData = ...;
NSManagedObject *apple = [coreData addManagedObject:@"Apple"];
[apple setValue:@"Mcintosh" forKey:@"name"];
[coreData saveMOCToPersistentStore];
NSManagedObjectContext *moc = [apple managedObjectContext];
if (!moc)
NSLog(@"2 - Deleted.");
else
NSLog(@"2 - Not deleted.");
[[coreData managedObjectContext] deleteObject:apple];
moc = [apple managedObjectContext];
if (!moc)
NSLog(@"3 - Deleted.");
else
NSLog(@"3 - Not deleted.");
[coreData saveMOCToPersistentStore];
moc = [apple managedObjectContext];
if (!moc)
NSLog(@"4 - Deleted.");
else
NSLog(@"4 - Not deleted.");
NSManagedObjectID *deletedAppleObjectID = [apple objectID];
NSManagedObject *appleClone = [[coreData managedObjectContext] objectWithID:deletedAppleObjectID];
moc = [appleClone managedObjectContext];
if (!moc)
NSLog(@"5 - Deleted.");
else
NSLog(@"5 - Not deleted.");
BOOL deleted = [coreData hasManagedObjectBeenDeleted:appleClone];
if (deleted)
NSLog(@"6 - Deleted.");
else
NSLog(@"6 - Not deleted.");
这是打印输出的结果:
2 - Not deleted.
3 - Not deleted.
4 - Deleted.
5 - Not deleted.
6 - Deleted.
正如您所看到的,-managedObjectContext
如果从持久存储中删除了NSManagedObject,则不会始终返回nil。
isInserted
在NSManagedObject上返回一个BOOL,据我理解,它的意义相同。在这种情况下使用它可能会更加简洁。 - de.isInserted
只有在对象保存之前是YES,然后变成NO。文档中没有提到这一点,但我的测试证明了这一点。 - phatmann