CoreData:+entityForName: nil 不是合法的 NSManagedObjectContext 参数搜索实体名称 'XMPPUserCoreDataStorageObject

Posted

技术标签:

【中文标题】CoreData:+entityForName: nil 不是合法的 NSManagedObjectContext 参数搜索实体名称 \'XMPPUserCoreDataStorageObject【英文标题】:CoreData:+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'XMPPUserCoreDataStorageObjectCoreData:+entityForName: nil 不是合法的 NSManagedObjectContext 参数搜索实体名称 'XMPPUserCoreDataStorageObject 【发布时间】:2015-03-02 12:57:15 【问题描述】:

我对 Core Data 很陌生,并且一直在尝试学习许多教程,但其中大多数都将所有 Core Data 方法都放入了 AppDelegate。所以请任何人帮助我提前谢谢

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

我得到的错误是

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

【问题讨论】:

你能展示你的CoreDataModel和你的“XMPPUserCoreDataStorageObject”类吗? 我已经编辑了,检查一下@geo 有谁能帮帮我吗 1.阅读我对我的回答的更新/评论! 2. 如果您还有其他问题,请写下来(可能会创建新问题) 3. 不要使用快捷方式/聊天语言... 我现在正面临这个错误。我不知道如何解决。 @geo。你能指导我吗? 【参考方案1】:

nil is not a legal NSManagedObjectContext parameter - 似乎您的 NSManagedObjectContext 对象在此部分无效。检查你从你的代表那里得到它的部分,启动时可能有错误:)

更新

NSManagedObjectContext *moc = [[AppDelegate appdelegate] managedObjectContext_roster]; // <- this seems to be nil

NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPUserCoreDataStorageObject"
                                              inManagedObjectContext:moc]; // <- crashing because "nil is not a legal NSManagedObjectContext parameter"

【讨论】:

我一直保持 breckpoint 听到 NSManagedObjectContext *moc = [[AppDelegate appdelegate] managedObjectContext_roster]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPUserCoreDataStorageObject" inManagedObjectContext:moc]; 错误是从这一行开始的 NSManagedObjectContext *moc = [[AppDelegate appdelegate] managedObjectContext_roster]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPUserCoreDataStorageObject" inManagedObjectContext:moc]; @geo 我已经在我的代码中构建了你的场景,首先将实体更改为无效,然后设置moc = nil;。在我的代码中,它也在创建实体的行处崩溃。再次查看变量的状态并判断 moc 是 nil 还是有效的 moc ^^ 并请删除不需要保持干净的 cmets ;) 在问题中的代码中添加注释,所以人们不必阅读每条评论来获取所有信息:) + 不要使用聊天语言,但总是写得干净、易于阅读和理解;) 对不起,我没听懂你能告诉我,请给我写两行代码【参考方案2】:

在 didFinishLaunchingWithOptions 中

[self setupStream];
你不初始化 xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];

【讨论】:

以上是关于CoreData:+entityForName: nil 不是合法的 NSManagedObjectContext 参数搜索实体名称 'XMPPUserCoreDataStorageObject的主要内容,如果未能解决你的问题,请参考以下文章

CoreData:“NSInternalInconsistencyException”,原因:“+entityForName:无法在此模型中找到名为“DocumentLocations”的实体。

OSX CoreData:仅针对某些实体的问题:+entityForName:在此模型中找不到名为“myEntity”的实体

iOS:Swift:核心数据:错误:+entityForName:nil 不是搜索实体名称的合法 NSManagedObjectContext 参数

扩展教程材料时 entityForName 和 ManagedObjectContext 的问题

+entityForName:在此模型中找不到名为“EntityName”的实体

CoreData - 一对多关系