+ 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
Любая помощь приветствуется. Благодарю.
Ответы
Ответ 1
- (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
, но это не так.
Чтобы устранить проблему, вам нужно будет предоставить действительный постоянный координатор хранилища. У меня есть небольшая статья здесь, в которой объясняется, как мало кода вам нужно настроить основной стек данных, это может вам помочь.
Ответ 2
В моем случае я использую несколько контекстов (родительский/дочерний) с разными типами параллелизма для повышения производительности. У меня есть три контекста:
-
storeContext
который является единственным контекстом, для которого был установлен persistentStoreCoordinator
. -
viewContext
чьим родителем является storeContext
-
backgroundContext
чьим родителем должен был быть viewContext
но я забыл установить backgroundContext.parent = viewContext
.
Сохранение объекта в backgroundContext
вызвало ту же ошибку...
+entityForName: nil не является допустимым параметром NSManagedObjectContext, который ищет имя объекта...
... потому что backgroundContext
не был частью цепочки родительского/дочернего контекста.
Установка backgroundContext
parent
для viewContext
установила цепочку обратно в координатор постоянного хранилища и viewContext
ошибку.
Ответ 3
Я столкнулся с этой entityForName: nil
, но в итоге она стала чем-то вроде красной сельди, которая проявлялась только при запуске модульных тестов на моем CI. Во время тестирования приложение столкнулось с некоторыми странными условиями потоков, вызванными NSAttributedString HTML Importer. Асинхронная отправка в основную очередь для взаимодействия с Core Data происходила так же, как NSAttributedString
создавалась из HTML.
Просто разместите мой опыт здесь на случай, если он в итоге поможет кому-то еще. :)
Ответ 4
Я столкнулся с той же ошибкой при получении данных из Core Data. Причиной было то, что значение объекта контекста не было установлено правильно, и оно устанавливало его после получения результата. Таким образом, правильная установка контекста перед созданием запроса на выборку завершает работу.
Ответ 5
Это может произойти из-за несоответствия имени сущности и имени его класса. Убедитесь, что ваш объект Account имеет соответствующее имя класса в файле .xcdatamodeld.