在CoreData中:+ entityForName:nil不是合法的NSManagedObjectContext参数search实体名称“XMPPUserCoreDataStorageObject

我对Core Data非常陌生,并且一直在尝试遵循许多教程,但是他们中的大多数都将所有的Core Data方法放到了AppDelegate.so中,任何一个人都可以帮助我

- (NSFetchedResultsController *)fetchedResultsController { // NSLog(@"Calling fetchedResultsController @ rootviewController"); if (is_Searching && [search_string length]) { NSManagedObjectContext *moc = [[AppDelegate appdelegate] managedObjectContext_roster]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPUserCoreDataStorageObject" inManagedObjectContext:moc]; NSSortDescriptor *sd1 = [[NSSortDescriptor alloc] initWithKey:@"sectionNum" ascending:YES]; NSSortDescriptor *sd2 = [[NSSortDescriptor alloc] initWithKey:@"displayName" ascending:YES]; NSArray *sortDescriptors = [NSArray arrayWithObjects:sd1, sd2, nil]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSMutableArray * predicateArray = [[NSMutableArray alloc]init]; if (is_Searching && [search_string length]) { NSPredicate *predecate = [NSPredicate predicateWithFormat:@"displayName CONTAINS [c] %@",search_string]; [predicateArray addObject:predecate]; } if ([[AppDelegate get_update_privacy_Array] count]) { for (NSString * jids in [AppDelegate get_update_privacy_Array]) { NSPredicate *predecate_blocked = [NSPredicate predicateWithFormat:@"NOT(nickname CONTAINS [c] %@ OR jidStr CONTAINS %@)" ,jids, jids]; [predicateArray addObject:predecate_blocked]; } } NSPredicate *predicate_final = [NSCompoundPredicate andPredicateWithSubpredicates: predicateArray]; [fetchRequest setPredicate:predicate_final]; [fetchRequest setEntity:entity]; [fetchRequest setSortDescriptors:sortDescriptors]; [fetchRequest setFetchBatchSize:10]; fetchedResultsController_search = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:@"sectionNum" cacheName:nil]; [fetchedResultsController_search setDelegate:self]; NSError *error = nil; if (![fetchedResultsController_search performFetch:&error]) { //DDLogError(@"Error performing fetch: %@", error); } if (![[fetchedResultsController_search fetchedObjects]count] && ![groupChatArray count]) { [AppDelegate alertWithTitle:@"Alert" message:@"No contact found!"]; } return fetchedResultsController_search; } else { NSManagedObjectContext *moc = [[AppDelegate appdelegate] managedObjectContext_roster]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPUserCoreDataStorageObject" inManagedObjectContext:moc]; NSSortDescriptor *sd1 = [[NSSortDescriptor alloc] initWithKey:@"sectionNum" ascending:YES]; NSSortDescriptor *sd2 = [[NSSortDescriptor alloc] initWithKey:@"displayName" ascending:YES]; NSArray *sortDescriptors = [NSArray arrayWithObjects:sd1, sd2, nil]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSMutableArray *predicateArray = [[NSMutableArray alloc]init]; if ([[AppDelegate get_update_privacy_Array] count]) { for (NSString * jids in [AppDelegate get_update_privacy_Array]) { NSPredicate *predecate_blocked = [NSPredicate predicateWithFormat:@"NOT(nickname CONTAINS [c] %@ OR jidStr CONTAINS %@)" ,jids, jids]; [predicateArray addObject:predecate_blocked]; } } NSPredicate *predicate_final = [NSCompoundPredicate andPredicateWithSubpredicates: predicateArray]; [fetchRequest setPredicate:predicate_final]; [fetchRequest setEntity:entity]; [fetchRequest setSortDescriptors:sortDescriptors]; [fetchRequest setFetchBatchSize:10]; fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:@"sectionNum" cacheName:nil]; [fetchedResultsController setDelegate:self]; NSError *error = nil; if (![fetchedResultsController performFetch:&error]) { //DDLogError(@"Error performing fetch: %@", error); } return fetchedResultsController; } } 

XMPPUserCoreDataStorageObject.m类

 #import "XMPP.h" #import "XMPPRosterCoreDataStorage.h" #import "XMPPUserCoreDataStorageObject.h" #import "XMPPResourceCoreDataStorageObject.h" #import "XMPPGroupCoreDataStorageObject.h" #import "NSNumber+XMPP.h" #if ! __has_feature(objc_arc) #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). #endif @interface XMPPUserCoreDataStorageObject () @property(nonatomic,strong) XMPPJID *primitiveJid; @property(nonatomic,strong) NSString *primitiveJidStr; @property(nonatomic,strong) NSString *primitiveDisplayName; @property(nonatomic,assign) NSInteger primitiveSection; @property(nonatomic,strong) NSString *primitiveSectionName; @property(nonatomic,strong) NSNumber *primitiveSectionNum; @end //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @implementation XMPPUserCoreDataStorageObject //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark Accessors //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @dynamic jid, primitiveJid; @dynamic jidStr, primitiveJidStr; @dynamic streamBareJidStr; @dynamic nickname; @dynamic displayName, primitiveDisplayName; @dynamic subscription; @dynamic ask; @dynamic unreadMessages; @dynamic photo; @dynamic section, primitiveSection; @dynamic sectionName, primitiveSectionName; @dynamic sectionNum, primitiveSectionNum; @dynamic groups; @dynamic primaryResource; @dynamic resources; @dynamic status; - (XMPPJID *)jid { // Create and cache the jid on demand [self willAccessValueForKey:@"jid"]; XMPPJID *tmp = [self primitiveJid]; [self didAccessValueForKey:@"jid"]; if (tmp == nil) { tmp = [XMPPJID jidWithString:[self jidStr]]; [self setPrimitiveJid:tmp]; } return tmp; } - (void)setJid:(XMPPJID *)jid { self.jidStr = [jid bare]; } - (void)setJidStr:(NSString *)jidStr { [self willChangeValueForKey:@"jidStr"]; [self setPrimitiveJidStr:jidStr]; [self didChangeValueForKey:@"jidStr"]; // If the jidStr changes, the jid becomes invalid. [self setPrimitiveJid:nil]; } - (NSInteger)section { // Create and cache the section on demand [self willAccessValueForKey:@"section"]; NSInteger tmp = [self primitiveSection]; [self didAccessValueForKey:@"section"]; // section uses zero, so to distinguish unset values, use NSNotFound if (tmp == NSNotFound) { tmp = [[self sectionNum] integerValue]; [self setPrimitiveSection:tmp]; } return tmp; } - (void)setSection:(NSInteger)value { self.sectionNum = [NSNumber numberWithInteger:value]; } - (NSInteger)primitiveSection { return section; } - (void)setPrimitiveSection:(NSInteger)primitiveSection { section = primitiveSection; } - (void)setSectionNum:(NSNumber *)sectionNum { [self willChangeValueForKey:@"sectionNum"]; [self setPrimitiveSectionNum:sectionNum]; [self didChangeValueForKey:@"sectionNum"]; // If the sectionNum changes, the section becomes invalid. // section uses zero, so to distinguish unset values, use NSNotFound [self setPrimitiveSection:NSNotFound]; } - (NSString *)sectionName { // Create and cache the sectionName on demand [self willAccessValueForKey:@"sectionName"]; NSString *tmp = [self primitiveSectionName]; [self didAccessValueForKey:@"sectionName"]; if (tmp == nil) { // Section names are organized by capitalizing the first letter of the displayName NSString *upperCase = [self.displayName uppercaseString]; // return the first character with support UTF-16: tmp = [upperCase substringWithRange:[upperCase rangeOfComposedCharacterSequenceAtIndex:0]]; [self setPrimitiveSectionName:tmp]; } return tmp; } - (void)setDisplayName:(NSString *)displayName { [self willChangeValueForKey:@"displayName"]; [self setPrimitiveDisplayName:displayName]; [self didChangeValueForKey:@"displayName"]; // If the displayName changes, the sectionName becomes invalid. [self setPrimitiveSectionName:nil]; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark NSManagedObject //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (void)awakeFromInsert { // Section uses zero, so to distinguish unset values, use NSNotFound. self.primitiveSection = NSNotFound; } - (void)awakeFromFetch { // Section uses zero, so to distinguish unset values, use NSNotFound. // // Note: Do NOT use "self.section = NSNotFound" as this will in turn set the sectionNum. self.primitiveSection = NSNotFound; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark Creation & Updates //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + (id)insertInManagedObjectContext:(NSManagedObjectContext *)moc withJID:(XMPPJID *)jid streamBareJidStr:(NSString *)streamBareJidStr { if (jid == nil) { NSLog(@"XMPPUserCoreDataStorageObject: invalid jid (nil)"); return nil; } XMPPUserCoreDataStorageObject *newUser; newUser = [NSEntityDescription insertNewObjectForEntityForName:@"XMPPUserCoreDataStorageObject" inManagedObjectContext:moc]; newUser.streamBareJidStr = streamBareJidStr; newUser.jid = jid; newUser.nickname = nil; newUser.displayName = [jid bare]; return newUser; } + (id)insertInManagedObjectContext:(NSManagedObjectContext *)moc withItem:(NSXMLElement *)item streamBareJidStr:(NSString *)streamBareJidStr { NSString *jidStr = [item attributeStringValueForName:@"jid"]; XMPPJID *jid = [XMPPJID jidWithString:jidStr]; if (jid == nil) { NSLog(@"XMPPUserCoreDataStorageObject: invalid item (missing or invalid jid): %@", item); return nil; } XMPPUserCoreDataStorageObject *newUser; newUser = [NSEntityDescription insertNewObjectForEntityForName:@"XMPPUserCoreDataStorageObject" inManagedObjectContext:moc]; newUser.streamBareJidStr = streamBareJidStr; [newUser updateWithItem:item]; return newUser; } - (void)updateGroupsWithItem:(NSXMLElement *)item { XMPPGroupCoreDataStorageObject *group = nil; // clear existing group memberships first if ([self.groups count] > 0) { [self removeGroups:self.groups]; } NSArray *groupItems = [item elementsForName:@"group"]; NSString *groupName = nil; for (NSXMLElement *groupElement in groupItems) { groupName = [groupElement stringValue]; group = [XMPPGroupCoreDataStorageObject fetchOrInsertGroupName:groupName inManagedObjectContext:[self managedObjectContext]]; if (group != nil) { [self addGroupsObject:group]; } } } - (void)updateWithItem:(NSXMLElement *)item { NSString *jidStr = [item attributeStringValueForName:@"jid"]; XMPPJID *jid = [XMPPJID jidWithString:jidStr]; if (jid == nil) { NSLog(@"XMPPUserCoreDataStorageObject: invalid item (missing or invalid jid): %@", item); return; } self.jid = jid; self.nickname = [item attributeStringValueForName:@"name"]; self.displayName = (self.nickname != nil) ? self.nickname : jidStr; self.subscription = [item attributeStringValueForName:@"subscription"]; self.ask = [item attributeStringValueForName:@"ask"]; [self updateGroupsWithItem:item]; } - (void)recalculatePrimaryResource { self.primaryResource = nil; NSArray *sortedResources = [[self allResources] sortedArrayUsingSelector:@selector(compare:)]; if ([sortedResources count] > 0) { XMPPResourceCoreDataStorageObject *resource = [sortedResources objectAtIndex:0]; // Primary resource must have a non-negative priority if ([resource priority] >= 0) { self.primaryResource = resource; if (resource.intShow >= 3) self.section = 0; else self.section = 1; } } if (self.primaryResource == nil) { self.section = 2; } } - (void)updateWithPresence:(XMPPPresence *)presence streamBareJidStr:(NSString *)streamBareJidStr { XMPPResourceCoreDataStorageObject *resource = (XMPPResourceCoreDataStorageObject *)[self resourceForJID:[presence from]]; if ([[presence type] isEqualToString:@"unavailable"] || [presence isErrorPresence]) { if (resource) { [self removeResourcesObject:resource]; [[self managedObjectContext] deleteObject:resource]; } } else { if (resource) { [resource updateWithPresence:presence]; } else { XMPPResourceCoreDataStorageObject *newResource; newResource = [XMPPResourceCoreDataStorageObject insertInManagedObjectContext:[self managedObjectContext] withPresence:presence streamBareJidStr:streamBareJidStr]; [self addResourcesObject:newResource]; } } [self recalculatePrimaryResource]; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark XMPPUser Protocol //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (BOOL)isOnline { return (self.primaryResource != nil); } - (BOOL)isPendingApproval { // Either of the following mean we're waiting to have our presence subscription approved: // <item ask='subscribe' subscription='none' jid='robbiehanson@deusty.com'/> // <item ask='subscribe' subscription='from' jid='robbiehanson@deusty.com'/> NSString *subscription = self.subscription; NSString *ask = self.ask; if ([subscription isEqualToString:@"none"] || [subscription isEqualToString:@"from"]) { if ([ask isEqualToString:@"subscribe"]) { return YES; } } return NO; } - (id <XMPPResource>)resourceForJID:(XMPPJID *)jid { NSString *jidStr = [jid full]; for (XMPPResourceCoreDataStorageObject *resource in [self resources]) { if ([jidStr isEqualToString:[resource jidStr]]) { return resource; } } return nil; } - (NSArray *)allResources { NSMutableArray *allResources = [NSMutableArray array]; for (XMPPResourceCoreDataStorageObject *resource in [[self resources] allObjects]) { if(![resource isDeleted]) { [allResources addObject:resource]; } } return allResources; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark Comparisons //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns the result of invoking compareByName:options: with no options. **/ - (NSComparisonResult)compareByName:(XMPPUserCoreDataStorageObject *)another { return [self compareByName:another options:0]; } /** * This method compares the two users according to their display name. * * Options for the search — you can combine any of the following using a C bitwise OR operator: * NSCaseInsensitiveSearch, NSLiteralSearch, NSNumericSearch. * See "String Programming Guide for Cocoa" for details on these options. **/ - (NSComparisonResult)compareByName:(XMPPUserCoreDataStorageObject *)another options:(NSStringCompareOptions)mask { NSString *myName = [self displayName]; NSString *theirName = [another displayName]; return [myName compare:theirName options:mask]; } /** * Returns the result of invoking compareByAvailabilityName:options: with no options. **/ - (NSComparisonResult)compareByAvailabilityName:(XMPPUserCoreDataStorageObject *)another { return [self compareByAvailabilityName:another options:0]; } /** * This method compares the two users according to availability first, and then display name. * Thus available users come before unavailable users. * If both users are available, or both users are not available, * this method follows the same functionality as the compareByName:options: as documented above. **/ - (NSComparisonResult)compareByAvailabilityName:(XMPPUserCoreDataStorageObject *)another options:(NSStringCompareOptions)mask { if ([self isOnline]) { if ([another isOnline]) return [self compareByName:another options:mask]; else return NSOrderedAscending; } else { if ([another isOnline]) return NSOrderedDescending; else return [self compareByName:another options:mask]; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark KVO compliance methods //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + (NSSet *)keyPathsForValuesAffectingJid { // If the jidStr changes, the jid may change as well. return [NSSet setWithObject:@"jidStr"]; } + (NSSet *)keyPathsForValuesAffectingIsOnline { return [NSSet setWithObject:@"primaryResource"]; } + (NSSet *)keyPathsForValuesAffectingSection { // If the value of sectionNum changes, the section may change as well. return [NSSet setWithObject:@"sectionNum"]; } + (NSSet *)keyPathsForValuesAffectingSectionName { // If the value of displayName changes, the sectionName may change as well. return [NSSet setWithObject:@"displayName"]; } + (NSSet *)keyPathsForValuesAffectingAllResources { return [NSSet setWithObject:@"resources"]; } @end - (NSManagedObjectContext *)managedObjectContext_roster { return [xmppRosterStorage mainThreadManagedObjectContext]; } - (NSManagedObjectContext *)mainThreadManagedObjectContext { NSAssert([NSThread isMainThread], @"Context reserved for main thread only"); if (mainThreadManagedObjectContext) { return mainThreadManagedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator) { XMPPLogVerbose(@"%@: Creating mainThreadManagedObjectContext", [self class]); if ([NSManagedObjectContext instancesRespondToSelector:@selector(initWithConcurrencyType:)]) mainThreadManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; else mainThreadManagedObjectContext = [[NSManagedObjectContext alloc] init]; mainThreadManagedObjectContext.persistentStoreCoordinator = coordinator; mainThreadManagedObjectContext.undoManager = nil; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(managedObjectContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:nil]; // Todo: If we knew that our private managedObjectContext was going to be the only one writing to the database, // then a small optimization would be to use it as the object when registering above. } return mainThreadManagedObjectContext; } - (void)managedObjectContextDidSave:(NSNotification *)notification { NSManagedObjectContext *sender = (NSManagedObjectContext *)[notification object]; if ((sender != mainThreadManagedObjectContext) && (sender.persistentStoreCoordinator == mainThreadManagedObjectContext.persistentStoreCoordinator)) { XMPPLogVerbose(@"%@: %@ - Merging changes into mainThreadManagedObjectContext", THIS_FILE, THIS_METHOD); dispatch_async(dispatch_get_main_queue(), ^{ [mainThreadManagedObjectContext mergeChangesFromContextDidSaveNotification:notification]; [self mainThreadManagedObjectContextDidMergeChanges]; }); } } - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { // This is a public method. // It may be invoked on any thread/queue. __block NSPersistentStoreCoordinator *result = nil; dispatch_block_t block = ^{ @autoreleasepool { if (persistentStoreCoordinator) { result = persistentStoreCoordinator; return; } NSManagedObjectModel *mom = [self managedObjectModel]; if (mom == nil) { return; } XMPPLogVerbose(@"%@: Creating persistentStoreCoordinator", [self class]); persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; if (databaseFileName) { // SQLite persistent store NSString *docsPath = [self persistentStoreDirectory]; NSString *storePath = [docsPath stringByAppendingPathComponent:databaseFileName]; if (storePath) { // If storePath is nil, then NSURL will throw an exception if(autoRemovePreviousDatabaseFile) { if ([[NSFileManager defaultManager] fileExistsAtPath:storePath]) { [[NSFileManager defaultManager] removeItemAtPath:storePath error:nil]; } } [self willCreatePersistentStoreWithPath:storePath options:storeOptions]; NSError *error = nil; BOOL didAddPersistentStore = [self addPersistentStoreWithPath:storePath options:storeOptions error:&error]; if(autoRecreateDatabaseFile && !didAddPersistentStore) { [[NSFileManager defaultManager] removeItemAtPath:storePath error:NULL]; didAddPersistentStore = [self addPersistentStoreWithPath:storePath options:storeOptions error:&error]; } if (!didAddPersistentStore) { [self didNotAddPersistentStoreWithPath:storePath options:storeOptions error:error]; } } else { XMPPLogWarn(@"%@: Error creating persistentStoreCoordinator - Nil persistentStoreDirectory", [self class]); } } else { // In-Memory persistent store [self willCreatePersistentStoreWithPath:nil options:storeOptions]; NSError *error = nil; if (![self addPersistentStoreWithPath:nil options:storeOptions error:&error]) { [self didNotAddPersistentStoreWithPath:nil options:storeOptions error:error]; } } result = persistentStoreCoordinator; }}; if (dispatch_get_specific(storageQueueTag)) block(); else dispatch_sync(storageQueue, block); return result; } 

错误iam得到是

 Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'XMPPUserCoreDataStorageObject''