+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
но это не так.
Чтобы решить эту проблему, вам нужно будет предоставить действительный постоянный координатор хранилища. У меня есть небольшая статья, которая объясняет, как мало кода вам нужно для установки основного стека данных, это может вам помочь.
В моем случае я использую несколько контекстов (родительский / дочерний) с разными типами параллелизма для повышения производительности. У меня есть три контекста:
storeContext
который является единственным контекстом которогоpersistentStoreCoordinator
был установлен.viewContext
чей родительstoreContext
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.