+entityForName: nil не является допустимым параметром NSManagedObjectContext, ищущим имя сущности 'Account''

Я перепробовал много вариантов, но не могу найти решение этой проблемы. Я создал файл Core Data и назвал сущность Account, создал строковый атрибут с именем username. Затем отредактировал класс сущности в NSManagedObject, не уверенный, если это правильно. Теперь следующий код находится в моем LoginViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    ITAppDelegate *appDelegate = (ITAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = appDelegate.managedObjectContext;

    Account *newAccount = [NSEntityDescription insertNewObjectForEntityForName:@"Account" inManagedObjectContext:context];
    [newAccount setValue:@"Jorge" forKey:@"username"];
    [newAccount setPassword:@"password"];

    NSLog(@"username:%@   password: %@", [newAccount username], [newAccount password]);

}

Я следовал этому уроку, и мои файлы кода выглядят так:

ITAppDelegate.h

#import <UIKit/UIKit.h>

@interface ITAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

@end

ITAppDelegate.m

#import "ITAppDelegate.h"
#import "LoginViewController.h"

@implementation ITAppDelegate

@synthesize managedObjectContext = _managedObjectContext;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
@synthesize managedObjectModel = _managedObjectModel;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary    *)launchOptions
{
    // Override point for customization after application launch.
    return YES;
}

#pragma mark - Core Data stack

- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil)
{
    return _managedObjectContext;
}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext  setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}


- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil)
{
    return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
    return _persistentStoreCoordinator;
}

    return _persistentStoreCoordinator;
}

@end

AccountBase.h

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@interface AccountBase : NSManagedObject

@property (nonatomic, retain) NSString *username;


@end

AccountBase.m

#import "AccountBase.h"

@implementation AccountBase

@dynamic username;

@end

Account.h

#import "AccountBase.h"
#import <CoreData/CoreData.h>

@interface Account : AccountBase

@property (nonatomic, assign) NSString *password;

@end

Account.m

#import "Account.h"
#import "KeychainHelper.h"

@implementation Account

- (NSString*)password
{
    if (self.username)
        return [KeychainHelper getPasswordForKey:self.username];
    return nil;
}

- (void)setPassword:(NSString*)aPassword
{
    if (self.username)
        [KeychainHelper setPassword:aPassword forKey:self.username];
}

- (void)prepareForDeletion
{
    if (self.username)
        [KeychainHelper removePasswordForKey:self.username];
}
@end

KeychainHelper.h

#import <Foundation/Foundation.h>

@interface KeychainHelper : NSObject

+ (NSString*)getPasswordForKey:(NSString*)aKey;
+ (void)setPassword:(NSString*)aPassword forKey:(NSString*)aKey;
+ (void)removePasswordForKey:(NSString*)aKey;

@end

KeychainHelper.m

#import "KeychainHelper.h"
#import <Security/Security.h>

@interface KeychainHelper ()
+ (NSMutableDictionary*)dictionaryForKey:(NSString*)aKey;
@end

@implementation KeychainHelper


static const NSString *ironTrainers = @"com.domain.myapplication";

+ (NSMutableDictionary*)dictionaryForKey:(NSString*)aKey
{
    NSData *encodedKey = [aKey dataUsingEncoding:NSUTF8StringEncoding];

    NSMutableDictionary *searchDictionary = [NSMutableDictionary dictionary];

    [searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    [searchDictionary setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [searchDictionary setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [searchDictionary setObject:ironTrainers forKey:(__bridge id)kSecAttrService];

    return searchDictionary;
}  

+ (NSString*)getPasswordForKey:(NSString*)aKey
{
    NSString *password = nil;

    NSMutableDictionary *searchDictionary = [self dictionaryForKey:aKey];
    [searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    [searchDictionary setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];

    CFTypeRef result = NULL;
    BOOL statusCode = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &result);
    if (statusCode == errSecSuccess) {
        NSData *resultData = CFBridgingRelease(result);
        password = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
    }
    return (__bridge NSString *)(result);
}

+ (void)removePasswordForKey:(NSString*)aKey
{
    NSMutableDictionary *keyDictionary = [self dictionaryForKey:aKey];
    SecItemDelete((__bridge CFDictionaryRef)keyDictionary);
 }

+ (void)setPassword:(NSString*)aPassword forKey:(NSString*)aKey
{
    [KeychainHelper removePasswordForKey:aKey];

    NSData *encodedPassword = [aPassword dataUsingEncoding:NSUTF8StringEncoding];

    NSMutableDictionary *keyDictionary = [self dictionaryForKey:aKey];
    [keyDictionary setObject:encodedPassword forKey:(__bridge id)kSecValueData];
    SecItemAdd((__bridge CFDictionaryRef)keyDictionary, nil);
}

@end

Любая помощь приветствуется. Благодарю.

6 ответов

Решение
- (NSManagedObjectContext *)managedObjectContext
{
    if (managedObjectContext != nil) return managedObjectContext;

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {

        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return managedObjectContext;
}
  • Вы не предоставили реализацию отложенной загрузки persistentStoreCoordinator
  • так coordinator всегда будет nil
  • так что вы всегда будете возвращаться nil из этого метода
  • Это означает, что вы всегда получите ошибку выше.

Чтобы объяснить ошибку:

+ entityForName: nil не является допустимым параметром NSManagedObjectContext, который ищет имя объекта "Account"

Это не сразу видно из прочтения, но это означает, что nil недопустимо передавать контекст управляемого объекта. При первом чтении похоже, что вы делаете entityForName:nil но это не так.

Чтобы решить эту проблему, вам нужно будет предоставить действительный постоянный координатор хранилища. У меня есть небольшая статья, которая объясняет, как мало кода вам нужно для установки основного стека данных, это может вам помочь.

В моем случае я использую несколько контекстов (родительский / дочерний) с разными типами параллелизма для повышения производительности. У меня есть три контекста:

  1. storeContext который является единственным контекстом которого persistentStoreCoordinator был установлен.
  2. viewContext чей родитель storeContext
  3. backgroundContext чей родитель должен былviewContext но я забыл установитьbackgroundContext.parent = viewContext,

Сохранение объекта на backgroundContext выдает ту же ошибку...

+ entityForName: nil не является допустимым параметром NSManagedObjectContext, который ищет имя объекта...

...так как backgroundContext не был частью цепочки родительского / дочернего контекста.

настройка backgroundContext"s parent в viewContext установил цепочку обратно в координатор постоянного хранилища и исправил ошибку.

Я сталкивался с этим entityForName: nil ошибка, но в итоге она стала чем-то вроде красной сельди, которая проявлялась только при запуске модульных тестов на моем CI. Во время тестирования приложение столкнулось с некоторыми странными условиями потоков, вызванными HTML-импортером NSAttributedString. Асинхронная отправка в основную очередь для взаимодействия с Core Data происходила так же, как NSAttributedString был создан из HTML.

Просто разместите мой опыт здесь на случай, если он в конечном итоге поможет кому-то еще.:)

Я столкнулся с той же ошибкой при получении данных из Core Data. Причина заключалась в том, что значение для объекта контекста не было установлено должным образом, и оно было установлено для него после получения результата. Таким образом, правильная установка контекста перед отправкой запроса на выборку делает работу выполненной.

Я использую следующие исправления

До NotesListModel.xcdatamodeld

После того, как я изменил NotesList.xcdatamodeld

Имя NotesList я использовал для всех мест, но имя файла NotesListModel

Вот почему я столкнулся с этой проблемой

Это может произойти из-за несоответствия имени объекта и имени его класса. Убедитесь, что ваша сущность Account имеет соответствующее имя класса в файле .xcdatamodeld .

Это может произойти из-за несоответствия имени объекта и имени его класса. Убедитесь, что у вашей учетной записи есть соответствующее имя класса в файле.xcdatamodeld.

Другие вопросы по тегам