在我的应用程序中,我使用sqlite数据库和核心数据来显示数据库中的数据,一切正常。 我希望用户能够在app的文档目录中添加照片,所以我为app定义了两个模型。
我使用了这个链接http://blog.atwam.com/blog/2012/05/11/multiple-persistent-stores-and-seed-data-with-core-data/ 以及来自Apple示例代码(https://developer.apple.com/library/ios/samplecode/PhotoLocations/Introduction/Intro.html)的PhotoLocations,用于添加照片功能。
从sql显示数据很好但是当我向app添加另一个模型并操纵AppDelegate时,应用程序崩溃了。
我不想使用MagicalRecord,因为我对核心数据的支持已超过一半。
这是我原来的AppDelegate:
// AppDelegate.m
// iranbirds
//
// Created by Mehdi on 7/31/16.
// Copyright © 2016 Mehdi. All rights reserved.
//
#import "AppDelegate.h"
#import "BirdsTableViewController.h"
#import "GeneralViewController.h"
#import "FavoriteTableViewController.h"
#import "MapViewController.h"
#import "MoreViewController.h"
//#import "Bird.h" //maybe delete
#import "BirdInfo.h"
#import "BirdImage.h"
#import "Favorite.h"
#import <CoreData/CoreData.h>
@interface AppDelegate () //class extension
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, strong) NSArray *fetchedObjects;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UINavigationController *naviController = (UINavigationController *)tabBarController.viewControllers[0];
naviController = (UINavigationController *)tabBarController.viewControllers[0];
BirdsTableViewController *catalogViewController = (BirdsTableViewController *)[naviController topViewController];
// catalogViewController.managedojbectContext = self.managedObjectContext;
//pass managed context to species view controller
naviController = (UINavigationController *)tabBarController.viewControllers[0];
MapViewController *mapViewController = (MapViewController *)[naviController topViewController];
mapViewController.managedOjbectContext = self.managedObjectContext;
naviController = (UINavigationController *)tabBarController.viewControllers[0];
FavoriteTableViewController *favoriteViewcontroller = (FavoriteTableViewController *)[naviController topViewController];
favoriteViewcontroller.managedOjbectContext = self.managedObjectContext;
//pass managed context view controller
naviController = (UINavigationController *)tabBarController.viewControllers[0];
MoreViewController *moreViewController = (MoreViewController *)[naviController topViewController];
moreViewController.managedOjbectContext = self.managedObjectContext;
//pass managed context view controller
naviController = (UINavigationController *)tabBarController.viewControllers[0];
APLViewController *aplViewController = (APLViewController *)[naviController topViewController];
aplViewController.managedOjbectContext = self.managedObjectContext;
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
#pragma mark - Core Data stack
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel == nil) {
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"TaxonModel" ofType:@"mom"];
NSURL *modelUrl = [NSURL fileURLWithPath:modelPath];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelUrl];
}
return _managedObjectModel;
}
- (NSString *)documentsDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths lastObject];
//NSLog(@"document directory: %@", documentsDirectory);
return documentsDirectory;
}
- (NSString *)dataStorePath
{
return [[self documentsDirectory] stringByAppendingPathComponent:@"DataStore.sqlite"];
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
if (_persistentStoreCoordinator == nil) {
//if the expected store doesn't exist, copy the default store from main bundle
if (![[NSFileManager defaultManager] fileExistsAtPath:[self dataStorePath]]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"DataStore" ofType:@"sqlite"]; // we construct a path to our database file We’re storing the database in our application’s bundle,o we use the pathForResource method to obtain the path.
if (defaultStorePath) {
[[NSFileManager defaultManager] copyItemAtPath:defaultStorePath toPath:[self dataStorePath] error:NULL];
}
}
NSURL *storeUrl = [NSURL fileURLWithPath:[self dataStorePath]];
// NSURL *storeUrl= [[self applicationDirectory] URLByAppendingPathComponent:@"Card.sqlite"];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
NSError *error;
//NSDictionary *options = @{NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}};
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeUrl
options:nil
error:&error]) {
//NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]);
abort();
}
}
[self addSkipBackupAttributeToItemAtPath:[self dataStorePath]];
return _persistentStoreCoordinator;
}
- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
{
NSURL* URL= [NSURL fileURLWithPath:filePathString];
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
}
//NSLog(@"Added %@",[NSNumber numberWithBool: success]);
return success;
}
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext == nil) {
NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator;
if (coordinator !=nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
}
return _managedObjectContext;
}
- (void)preloadData {
NSString *path = [[NSBundle mainBundle] pathForResource:@"acachecklist" ofType:@"txt"];
NSError *error;
NSString *allBirds = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if (allBirds == nil) {
//NSLog(@"Error reading file: %@",[error localizedDescription]);
}
NSArray *lines=[allBirds componentsSeparatedByString:@"\n"];
unsigned long count = [lines count];
NSArray *bird;
for(int i=0;i<count;i++) {
bird=[[lines objectAtIndex:i] componentsSeparatedByString:@"\t"];
BirdInfo *info = [NSEntityDescription insertNewObjectForEntityForName:@"BirdInfo"
inManagedObjectContext:self.managedObjectContext];
BirdImage *imageObj = [NSEntityDescription insertNewObjectForEntityForName:@"BirdImage"
inManagedObjectContext:self.managedObjectContext];
UIImage *tempImage = [UIImage imageNamed:@"Placeholder"];
imageObj.image = UIImageJPEGRepresentation(tempImage,1);
info.category = [bird objectAtIndex:0];
info.com_name = [bird objectAtIndex:1];
info.sci_name = [bird objectAtIndex:2];
//info.taxon_id = [bird objectAtIndex:2];
info.thumbnailImage = imageObj;
NSError *error;
if (![self.managedObjectContext save:&error]) {
//NSLog(@"Error: %@", error);
abort();
}
}
}
- (void)preLoadSpecies
{
NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
privateContext.persistentStoreCoordinator = self.managedObjectContext.persistentStoreCoordinator;
NSEntityDescription *entity = [NSEntityDescription insertNewObjectForEntityForName:@"BirdInfo"
inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *allSpeciesRequest = [[NSFetchRequest alloc] init];
[allSpeciesRequest setEntity:entity];
[privateContext performBlock:^{
NSError *error;
self.fetchedObjects = [privateContext executeFetchRequest:allSpeciesRequest error:&error];
if (error) {
//NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}];
}
@end
编辑后的AppDelegate:
#import "AppDelegate.h"
#import "BirdsTableViewController.h"
#import "GeneralViewController.h"
#import "FavoriteTableViewController.h"
#import "MapViewController.h"
#import "MoreViewController.h"
//#import "Bird.h" //maybe delete
#import "BirdInfo.h"
#import "BirdImage.h"
#import "Favorite.h"
#import <CoreData/CoreData.h>
#import "APLViewController.h"
@interface AppDelegate () //class extension
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, strong) NSArray *fetchedObjects;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UINavigationController *naviController = (UINavigationController *)tabBarController.viewControllers[0];
naviController = (UINavigationController *)tabBarController.viewControllers[0];
BirdsTableViewController *catalogViewController = (BirdsTableViewController *)[naviController topViewController];
// catalogViewController.managedojbectContext = self.managedObjectContext;
//pass managed context to species view controller
naviController = (UINavigationController *)tabBarController.viewControllers[0];
MapViewController *mapViewController = (MapViewController *)[naviController topViewController];
mapViewController.managedOjbectContext = self.managedObjectContext;
naviController = (UINavigationController *)tabBarController.viewControllers[0];
FavoriteTableViewController *favoriteViewcontroller = (FavoriteTableViewController *)[naviController topViewController];
favoriteViewcontroller.managedOjbectContext = self.managedObjectContext;
//pass managed context view controller
naviController = (UINavigationController *)tabBarController.viewControllers[0];
APLViewController *aplViewController = (APLViewController *)[naviController topViewController];
aplViewController.managedOjbectContext = self.managedObjectContext;
/*
//[self preloadData]; //preload birds info into core data
// UITabBarController *tabBarController ;
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
//pass managed context to first view controller
UINavigationController *naviController = (UINavigationController *)tabBarController.viewControllers[0];
BirdsTableViewController *birdsTableViewController = (BirdsTableViewController *)[naviController topViewController];
birdsTableViewController.managedOjbectContext = self.managedObjectContext;
//pass managed context to nearby view controller
naviController = (UINavigationController *)tabBarController.viewControllers[1];
GeneralViewController *generalViewController = (GeneralViewController *)[naviController topViewController];
generalViewController.managedOjbectContext = self.managedObjectContext;
//pass managed context to species view controller
naviController = (UINavigationController *)tabBarController.viewControllers[2];
SpeciesViewController *catalogViewController = (SpeciesViewController *)[naviController topViewController];
catalogViewController.managedOjbectContext = self.managedObjectContext;
//pass managed context to favorite view controller
naviController = (UINavigationController *)tabBarController.viewControllers[3];
FavoritesViewController *favoriteViewcontroller = (FavoritesViewController *)[naviController topViewController];
favoriteViewcontroller.managedOjbectContext = self.managedObjectContext;
UIColor* navColor = [UIColor colorWithRed:0.175f green:0.458f blue:0.831f alpha:1.0f];
[[UINavigationBar appearance] setBarTintColor:navColor];
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
[[UINavigationBar appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor whiteColor]}];
//UIColor *barColor = [UIColor colorWithRed:0.012 green:0.286 blue:0.553 alpha:1.0];
[tabBarController.tabBar setTintColor:navColor];
//[self preLoadSpecies];
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
//set tab bar item selected images;
NSArray *array = tabBarController.tabBar.items;
((UITabBarItem *)array[2]).selectedImage = [UIImage imageNamed:@"Pelican Filled"];
((UITabBarItem *)array[0]).selectedImage = [UIImage imageNamed:@"Log Cabin Filled"];
((UITabBarItem *)array[1]).selectedImage = [UIImage imageNamed:@"Binoculars Filled"];
((UITabBarItem *)array[3]).selectedImage = [UIImage imageNamed:@"Like Filled"];
//pass managed context to general view controller
UINavigationController *naviController = (UINavigationController *)tabBarController.viewControllers[0];
GeneralViewController *Genralviewcontroler = (GeneralViewController *)[naviController topViewController];
Genralviewcontroler.managedOjbectContext = self.managedObjectContext;
[window addSubview:_navController.view];
*/
//set tab bar item selected images;
NSArray *array = tabBarController.tabBar.items;
//((UITabBarItem *)array[2]).selectedImage = [UIImage imageNamed:@"Pelican Filled"];
((UITabBarItem *)array[0]).selectedImage = [UIImage imageNamed:@"Log Cabin Filled"];
//((UITabBarItem *)array[1]).selectedImage = [UIImage imageNamed:@"Falcon Filled"];
((UITabBarItem *)array[2]).selectedImage = [UIImage imageNamed:@"Like Filled"];
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
#pragma mark - Core Data stack
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *uModelURL = [[NSBundle mainBundle] URLForResource:@"Locations" withExtension:@"momd"];
NSManagedObjectModel* uModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:uModelURL];
NSURL *pdModelURL = [[NSBundle mainBundle] URLForResource:@"TaxonModel" withExtension:@"mom"];
NSManagedObjectModel* pdModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:pdModelURL];
_managedObjectModel = [NSManagedObjectModel modelByMergingModels:[NSArray arrayWithObjects:uModel, pdModel, nil]];
return _managedObjectModel;
}
- (NSString *)documentsDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths lastObject];
//NSLog(@"document directory: %@", documentsDirectory);
return documentsDirectory;
}
- (NSString *)dataStorePath
{
return [[self documentsDirectory] stringByAppendingPathComponent:@"DataStore.sqlite"];
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
[self addSeedDataToCoordinator:_persistentStoreCoordinator];
NSURL* userURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"UserData.sqlite"];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
/*
// Allow inferred migration from the original version of the application.
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption : @YES, NSInferMappingModelAutomaticallyOption : @YES };
*/
// Note that we use our UserConf here
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:@"UserConf" URL:userURL options:nil error:&error])
{
NSLog(@"Error %@",error);
}
[self addSkipBackupAttributeToItemAtPath:[self dataStorePath]]; // *******i added*******
return _persistentStoreCoordinator;
}
- (void) addSeedDataToCoordinator:(NSPersistentStoreCoordinator *)storeCoordinator
{
// Our destination url, writtable. Make sure this is in Library/Cache if you don't want iCloud to backup this.
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"DataStore.sqlite"];
NSError *error = nil; //************ i define
//NSURL* adURL;//********************i define
// If we don't have our migrated store, prepare it
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURL path]])
{
// Our source url should come from a download, but let's use our bundle for debug purposes in the simulator
NSURL *baseURL = [[NSBundle mainBundle] URLForResource:@"DataStore" withExtension:@"sqlite"];
// [[NSFileManager defaultManager] copyItemAtPath:baseURL toPath:[self dataStorePath] error:NULL]; ///######@#@#this line
// [NSFileManager defaultManager]copyItemAtPath:<#(nonnull NSString *)#> toPath:<#(nonnull NSString *)#> error:NULL];
[[NSFileManager defaultManager]contentsAtPath:[self dataStorePath]]; // I ADD THIS LINE
// Create one coordinator that just migrates, but isn't used.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
// This will just handle the migration, without any configuration or else ...
NSPersistentStore* tmpStore = [storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
// And remove it !
[storeCoordinator removePersistentStore:tmpStore error:&error];
}
// And now add the coordinator with the correct 'PostCodesConf' configuration, in readonly mode
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption, nil];
[storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:@"PostCodesConf" URL:storeURL options:options error:&error];
}
- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
{
NSURL* URL= [NSURL fileURLWithPath:filePathString];
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
}
//NSLog(@"Added %@",[NSNumber numberWithBool: success]);
return success;
}
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext == nil) {
NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator;
if (coordinator !=nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
}
return _managedObjectContext;
}
- (void)preloadData {
NSString *path = [[NSBundle mainBundle] pathForResource:@"acachecklist" ofType:@"txt"];
NSError *error;
NSString *allBirds = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if (allBirds == nil) {
//NSLog(@"Error reading file: %@",[error localizedDescription]);
}
NSArray *lines=[allBirds componentsSeparatedByString:@"\n"];
unsigned long count = [lines count];
NSArray *bird;
for(int i=0;i<count;i++) {
bird=[[lines objectAtIndex:i] componentsSeparatedByString:@"\t"];
BirdInfo *info = [NSEntityDescription insertNewObjectForEntityForName:@"BirdInfo"
inManagedObjectContext:self.managedObjectContext];
BirdImage *imageObj = [NSEntityDescription insertNewObjectForEntityForName:@"BirdImage"
inManagedObjectContext:self.managedObjectContext];
UIImage *tempImage = [UIImage imageNamed:@"Placeholder"];
imageObj.image = UIImageJPEGRepresentation(tempImage,1);
info.category = [bird objectAtIndex:0];
info.com_name = [bird objectAtIndex:1];
info.sci_name = [bird objectAtIndex:2];
//info.taxon_id = [bird objectAtIndex:2];
info.thumbnailImage = imageObj;
NSError *error;
if (![self.managedObjectContext save:&error]) {
//NSLog(@"Error: %@", error);
abort();
}
}
}
- (void)preLoadSpecies
{
NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
privateContext.persistentStoreCoordinator = self.managedObjectContext.persistentStoreCoordinator;
NSEntityDescription *entity = [NSEntityDescription insertNewObjectForEntityForName:@"BirdInfo"
inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *allSpeciesRequest = [[NSFetchRequest alloc] init];
[allSpeciesRequest setEntity:entity];
[privateContext performBlock:^{
NSError *error;
self.fetchedObjects = [privateContext executeFetchRequest:allSpeciesRequest error:&error];
if (error) {
//NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}];
}
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
@end
当我想在第一个视图控制器中使用以下日志加载数据时,应用程序崩溃:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'BirdInfo''