J'ai essayé beaucoup d'options, mais je ne trouve pas la solution à ce problème. J'ai créé un fichier de données principal et nommé l'entité Compte, Créé un attribut de chaîne appelé nom d'utilisateur. Puis modifié la classe de l'entité en NSManagedObject, ne sachant pas si cela est correct. Maintenant, le code suivant est dans mon 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]);
}
J'ai suivi Ce tutoriel et mes fichiers de code ressemblent à ceci:
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
Compte.h
#import "AccountBase.h"
#import <CoreData/CoreData.h>
@interface Account : AccountBase
@property (nonatomic, assign) NSString *password;
@end
Compte.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
Porte-clésHelper.h
#import <Foundation/Foundation.h>
@interface KeychainHelper : NSObject
+ (NSString*)getPasswordForKey:(NSString*)aKey;
+ (void)setPassword:(NSString*)aPassword forKey:(NSString*)aKey;
+ (void)removePasswordForKey:(NSString*)aKey;
@end
Porte-clés.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
Toute aide appréciée. Merci.
- (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
sera toujours nil
nil
de cette méthodePour expliquer l'erreur:
+ entityForName: nil n'est pas un paramètre légal de NSManagedObjectContext recherchant le nom d'entité 'Compte'
Ce n’est pas immédiatement évident de le lire, mais cela signifie que nil
n’est pas une chose légale à passer pour le contexte de l’objet géré. En première lecture, on dirait que vous utilisez entityForName:nil
mais ce n'est pas le cas.
Pour résoudre le problème, vous devez fournir un coordinateur de magasin persistant valide. J'ai un petit article ici qui explique à quel point il vous faut peu de code pour configurer une pile de données principale, cela peut vous aider.
J'ai rencontré cette erreur entityForName: nil
, mais cela a fini par être un peu un fil rouge qui ne s'est manifesté que lors de l'exécution de tests unitaires sur mon CI. Lors des tests, l'application rencontrait des conditions de threads étranges causées par L'importateur HTML de NSAttributedString . Une répartition asynchrone sur la file principale pour interagir avec Core Data se produisait au moment même où la variable NSAttributedString
était créée à partir de HTML.
Il suffit de poster mon expérience ici au cas où cela aiderait quelqu'un d'autre. :)
Dans mon cas, j'utilise plusieurs contextes (parent/enfant) avec différents types de concurrence pour améliorer les performances. J'ai trois contextes:
storeContext
qui est le seul contexte pour lequel persistentStoreCoordinator
a été défini.viewContext
dont le parent est storeContext
backgroundContext
dont le parent aurait dû être viewContext
mais J'ai oublié de définir backgroundContext.parent = viewContext
. L'enregistrement d'une entité sur la backgroundContext
a produit la même erreur ...
+ entityForName: nil n'est pas un paramètre légal de NSManagedObjectContext recherchant un nom d'entité ...
... parce que backgroundContext
ne faisait pas partie de la chaîne de contexte parent/enfant.
Définir backgroundContext
's parent
sur viewContext
a établi la chaîne de nouveau au coordinateur de magasin persistant et a corrigé l'erreur.