问题
I have tried a lot of options, but can't find the solution for this problem. I created a Core Data file and named the entity Account, Created an string attribute called username. Then edited the class of the entity to NSManagedObject, not sure if this is right. Now, the following code is in my 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]);
}
I followed This Tutorial and my code files look like this:
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
Any help appreciated. Thanks.
回答1:
- (NSManagedObjectContext *)managedObjectContext
{
if (managedObjectContext != nil) return managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext;
}
- You haven't provided a lazy loading implementation of
persistentStoreCoordinator
- so
coordinator
will always benil
- so you will always be returning
nil
from this method - which means you will always get the error above.
To explain the error:
+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Account'
It's not immediately obvious from reading it, but this means that nil
is not a legal thing to pass for the managed object context. On first reading, it looks like you're doing entityForName:nil
but that isn't the case.
To fix the problem, you will need to provide a valid persistent store coordinator. I have a small article here which explains just how little code you need to set up a core data stack, this may help you.
回答2:
In my case, I'm using multiple contexts (parent/child) with different concurrency types to improve performance. I have three contexts:
storeContext
which is the only context whosepersistentStoreCoordinator
had been set.viewContext
whose parent isstoreContext
backgroundContext
whose parent should have beenviewContext
but I forgot to setbackgroundContext.parent = viewContext
.
Saving an entity on the backgroundContext
produced the same error...
+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name...
...because backgroundContext
wasn't a part of the parent/child context chain.
Setting backgroundContext
's parent
to viewContext
established the chain back to the persistent store coordinator and resolved the error.
回答3:
I encountered this entityForName: nil
error, but it ended up being somewhat of a red herring that only manifested itself when running unit tests on my CI. During testing, the app was encountering some weird threading conditions caused by NSAttributedString's HTML Importer. An asynchronous dispatch onto the main queue to interact with Core Data was happening just as the NSAttributedString
was being created from HTML.
Just posting my experience here in case it ends up helping someone else. :)
回答4:
I encountered the same error while fetching data from Core Data. The reason was value to context object was not set properly and It was setting to it after fetching the result. So, setting context properly before hitting fetch request makes the work done.
回答5:
It might happens because of mismatch of entity name and its class name. Ensure that your Account entity has an appropriate class name in .xcdatamodeld file.
来源:https://stackoverflow.com/questions/20472465/entityforname-nil-is-not-a-legal-nsmanagedobjectcontext-parameter-searching-fo