好的,所以我正在制作一个gps跟踪应用程序,所有用于跟踪用户的代码都很好,但现在我正在尝试传递要保存并显示在摘要视图中的数据。我有一个在模型中正确设置的实体Run,我知道我需要向appDelegate.mdidFinishLaunching with options方法添加一些东西,以便正确初始化managedObjectContext,但我似乎无法解决。任何帮助都将不胜感激。
这是我的错误
由于未捕获的异常而终止应用"NSInvalidArgumentException",原因:"+entityForName:nil不是搜索实体名称的合法NSManagedObjectContext参数"运行"
这是我的应用程序代表.m
'import "AppDelegate.h"
#import <CoreData/CoreData.h>
#import "SummaryViewController.h"
#import "CardioViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
#pragma mark - Core Data stack
// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Beginner Fitness" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
// 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;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Beginner Fitness.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
@end'
这是我的CardioViewController,我使用了断点,错误发生在saveRun方法的开头,第一次提到"Run"时,正如您所期望的那样。
static NSString * const detailSegueName = @"NewRunDetails";
@interface CardioViewController ()<UIActionSheetDelegate, CLLocationManagerDelegate, MKMapViewDelegate>
@property int seconds;
@property float distance;
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, strong) NSMutableArray *locations;
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, strong) Run *run;
@property (nonatomic, weak) IBOutlet UILabel *timeLabel;
@property (nonatomic, weak) IBOutlet UILabel *distLabel;
@property (nonatomic, weak) IBOutlet UILabel *paceLabel;
@property (nonatomic, weak) IBOutlet UIImageView *progressImageView;
@property (nonatomic, weak) IBOutlet UIButton *startButton;
@property (nonatomic, weak) IBOutlet UIButton *stopButton;
@property (nonatomic, weak) IBOutlet MKMapView *mapView;
@end
@implementation CardioViewController{
NSMutableArray *locationsArray;
}
@synthesize mapView = _mapView;
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationItem.title = _DetailModal2[0];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.timer invalidate];
}
#pragma mark - IBActions
-(IBAction)startPressed:(id)sender
{
// hide the start UI
// show the running UI
self.seconds = 0;
// initialize the timer
self.timer = [NSTimer scheduledTimerWithTimeInterval:(1.0) target:self selector:@selector(eachSecond) userInfo:nil repeats:YES];
self.distance = 0;
self.locations = [NSMutableArray array];
[self startLocationUpdates];
}
- (IBAction)stopPressed:(id)sender
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Save", @"Discard", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView:self.view];
}
#pragma mark - Private
- (void)saveRun
{
Run *newRun = [NSEntityDescription insertNewObjectForEntityForName:@"Run" inManagedObjectContext:self.managedObjectContext];
newRun.distance = [NSNumber numberWithFloat:self.distance];
newRun.duration = [NSNumber numberWithInt:self.seconds];
newRun.timestamp = [NSDate date];
NSMutableArray *locationArray = [NSMutableArray array];
for (CLLocation *location in self.locations) {
Location *locationObject = [NSEntityDescription insertNewObjectForEntityForName:@"Location" inManagedObjectContext:self.managedObjectContext];
locationObject.timestamp = location.timestamp;
locationObject.latitude = [NSNumber numberWithDouble:location.coordinate.latitude];
locationObject.longitude = [NSNumber numberWithDouble:location.coordinate.longitude];
[locationArray addObject:locationObject];
}
newRun.locations = [NSOrderedSet orderedSetWithArray:locationArray];
self.run = newRun;
// Save the context.
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
- (void)eachSecond
{
self.seconds++;
[self updateProgressImageView];
[self updateLabels];
}
- (void)updateProgressImageView
{
int currentPosition = self.progressImageView.frame.origin.x;
CGRect newRect = self.progressImageView.frame;
switch (currentPosition) {
case 20:
newRect.origin.x = 80;
break;
case 80:
newRect.origin.x = 140;
break;
default:
newRect.origin.x = 20;
break;
}
self.progressImageView.frame = newRect;
}
- (void)updateLabels
{
self.timeLabel.text = [NSString stringWithFormat:@"Time: %@", [MathController stringifySecondCount:self.seconds usingLongFormat:NO]];
self.distLabel.text = [NSString stringWithFormat:@"Distance: %@", [MathController stringifyDistance:self.distance]];
self.paceLabel.text = [NSString stringWithFormat:@"Pace: %@", [MathController stringifyAvgPaceFromDist:self.distance overTime:self.seconds]];
}
- (void)startLocationUpdates
{
// Create the location manager if this object does not
// already have one.
if (self.locationManager == nil) {
self.locationManager = [[CLLocationManager alloc] init];
}
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.activityType = CLActivityTypeFitness;
// Movement threshold for new events.
self.locationManager.distanceFilter = 10; // meters
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self.locationManager stopUpdatingLocation];
// save
if (buttonIndex == 0) {
[self saveRun];
[self performSegueWithIdentifier:detailSegueName sender:nil];
// discard
} else if (buttonIndex == 1) {
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
for (CLLocation *newLocation in locations) {
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (fabs(howRecent) < 10.0 && newLocation.horizontalAccuracy < 20) {
// update distance
if (self.locations.count > 0) {
self.distance += [newLocation distanceFromLocation:self.locations.lastObject];
CLLocationCoordinate2D coords[2];
coords[0] = ((CLLocation *)self.locations.lastObject).coordinate;
coords[1] = newLocation.coordinate;
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 500, 500);
[self.mapView setRegion:region animated:YES];
[self.mapView addOverlay:[MKPolyline polylineWithCoordinates:coords count:2]];
}
[self.locations addObject:newLocation];
}
}
}
#pragma mark - MKMapViewDelegate
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *polyLine = (MKPolyline *)overlay;
MKPolylineRenderer *aRenderer = [[MKPolylineRenderer alloc] initWithPolyline:polyLine];
aRenderer.strokeColor = [UIColor blueColor];
aRenderer.lineWidth = 3;
return aRenderer;
}
return nil;
}
- (void)dealloc
{
//
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.locationManager.delegate = nil;
}
- (void)initilizeLocationTracking
{
_locationManager = [[CLLocationManager alloc] init];
assert(self.locationManager);
self.locationManager.delegate = self; // tells the location manager to send updates to this object
//
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}
// start tracking the user's location
[self.locationManager startUpdatingLocation];
}
- (MKCoordinateRegion)coordinateRegionWithCenter:(CLLocationCoordinate2D)centerCoordinate approximateRadiusInMeters:(CLLocationDistance)radiusInMeters
{
// Multiplying by MKMapPointsPerMeterAtLatitude at the center is only approximate, since latitude isn't fixed
//
double radiusInMapPoints = radiusInMeters*MKMapPointsPerMeterAtLatitude(centerCoordinate.latitude);
MKMapSize radiusSquared = {radiusInMapPoints,radiusInMapPoints};
MKMapPoint regionOrigin = MKMapPointForCoordinate(centerCoordinate);
MKMapRect regionRect = (MKMapRect){regionOrigin, radiusSquared}; //origin is the top-left corner
regionRect = MKMapRectOffset(regionRect, -radiusInMapPoints/2, -radiusInMapPoints/2);
// clamp the rect to be within the world
regionRect = MKMapRectIntersection(regionRect, MKMapRectWorld);
MKCoordinateRegion region = MKCoordinateRegionForMapRect(regionRect);
return region;
}
- (IBAction)setMap:(id)sender {
switch (((UISegmentedControl*) sender).selectedSegmentIndex) {
case 0:
_mapView.mapType = MKMapTypeStandard;
break;
case 1:
_mapView.mapType = MKMapTypeSatellite;
break;
case 2:
_mapView.mapType = MKMapTypeHybrid;
break;
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:detailSegueName]) {
[[segue destinationViewController] setRun:self.run];
}
}
这基本上意味着当调用该方法时,核心数据堆栈没有正确设置。(self.managedObjectContext可能为零。)
虽然thorb65的建议可能会奏效,但我不建议这样做。您尝试使用依赖项注入是一个更好的想法,尽管很明显,在这种情况下,由于某种原因,上下文没有被插入(或创建)。可能是由于国家恢复?
你的另一个选择是在一个中心位置而不是应用程序委托中设置核心数据堆栈,这样无论何时你尝试使用它,它都会被设置。我已经成功地使用了SLCoreDataStack,尽管还有很多其他方法,而且自己创建类似的结构并不困难。
您的CardioViewController
有一个属性self.managedObjectContext
,但您的代码中没有显示分配给它的值。因此,它为零。出现此异常是因为您的代码在self.managedObjectContext
没有值时尝试使用它。
你的应用程序委托创建了一个托管对象上下文,但这本身还不够。它不会自动传播到视图控制器。在应用程序委托中,您需要将视图控制器的NSManagedObjectContext
分配为与在应用程序代理中创建的值相同的值。您的代码没有显示任何对CardioViewController
的引用,但它可能是类似的
self.cardioViewController.managedObjectContext = self.managedObjectContext;
在saveRun
中将self.managedObjectContext
更改为[(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext]
。。。