NSManagedObjectContext attributes of object nil - ios

I am trying to work with core data and already am able to store records of my class "Event.m". An event has a timestamp an a note.
But as i try to read all entries in my table view to display them, I see that every timestamp and note is nil (debug). Strange thing is, that my array I get has the right size (number of entries) and also the table rows are created (only no note si visible).
Here some of my code:
- (void)fetchRecords {
// Define our table/entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:self.managedObjectContext];
// Setup the fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
// Define how we will sort the records
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
// Fetch the records and handle an error
NSError *error;
NSMutableArray *mutableFetchResults = [[self.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (!mutableFetchResults) {
NSLog(#"Error fetching data.");
}
// Save our fetched data to an array
[self setEventArray: mutableFetchResults];
NSLog(#"Records found: %i", [eventArray count]);
}
And this is where I save my object:
- (void) saveEntry: (NSString *) note
{
Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:managedObjectContext];
[event setTimeStamp: [NSDate date]];
[event setNote:#"test"];
NSError *error;
if (![managedObjectContext save:&error]) {
NSLog(#"Could not save entry.");
}
NSLog(#"Entry saved.");
[eventArray insertObject:event atIndex:0];
}
Note that there are two different views, from which I access Core Data.
And this is where I get my MOC in this views:
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
managedObjectContext = appDelegate.managedObjectContext;
}
Here I was reading, that it could come frome the MOC itself. This is how I hold my variable in SecondViewController.h
#import "Event.h"
#import <CoreData/CoreData.h>
#import "AppDelegate.h"
#interface SecondViewController : UITableViewController {
NSManagedObjectContext *managedObjectContext;
NSMutableArray *eventArray;
}
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong) NSMutableArray *eventArray;
- (void) fetchRecords;
#end
And in my .m file I have:
#synthesize managedObjectContext, eventArray;
Then I call fetchRecords.
Any ideas why I have this problem?

I was missing one line of code, concerning the request:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setReturnsObjectsAsFaults:NO];
After adding the last line I was able to access all attributes.

Related

CoreData: error: Failed to call designated initializer on NSManagedObject class 'SCTrack'

Hate to ask this question because there seems to be a bunch of other similar ones and but I still can't see what is wrong with mine after going through most of the answers.
I have two VCs, VC1 contains a list of songs fetched from a music service. VC2 contains a list of songs picked from VC1; VC2 is basically a playlist.
I've set up my entity name and class to match: SCTrack. Here is my SCTrack.h:
#interface SCTrack : NSManagedObject
#property (strong, nonatomic) NSString* title;
#property (strong, nonatomic) NSString* stream_url;
SCTrack.m:
#import "SCTrack.h"
#implementation SCTrack
#dynamic title;
#dynamic stream_url;
-(instancetype) initWithDictionary: (NSDictionary*) SCTrackDict {
self = [self init];
if (self) {
self.title = SCTrackDict[#"title"];
self.stream_url = SCTrackDict[#"stream_url"];
}
return self;
}
+(NSMutableArray *) parseJSONData: (NSData *) JSONData {
NSError* error;
NSMutableArray* SCTrackArray = [NSMutableArray new];
NSArray *JSONArray= [NSJSONSerialization JSONObjectWithData:JSONData options:0 error: &error];
if ([JSONArray isKindOfClass:[NSArray class]]) {
for (NSDictionary* trackDict in JSONArray) {
SCTrack* trackObject = [[SCTrack alloc]initWithDictionary:trackDict];
[SCTrackArray addObject:trackObject];
}
}
return SCTrackArray;
}
#end
My AppDelegate.m
UITabBarController* tabBar = (UITabBarController*) self.window.rootViewController;
SCTrackListVC *SCVC = (SCTrackListVC*) [[tabBar viewControllers]objectAtIndex:2];
SCVC.managedObjectContext = self.managedObjectContext;
return YES;
In my VC1.m
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedTrack = self.SCTrackList[indexPath.row];
self.selectedTrackRow = indexPath.row;
self.selectedTrack = [[SCTrack alloc]initWithEntity:[NSEntityDescription entityForName:#"SCTrack" inManagedObjectContext:self.managedObjectContext]insertIntoManagedObjectContext:self.managedObjectContext];
NSError* error;
NSManagedObjectContext *context = self.managedObjectContext;
if (![context save:&error]) {
NSLog(#"Error! %#", error);
}
//This is the other way I tried it _selectedTrack = [NSEntityDescription insertNewObjectForEntityForName:#"SCTrack" inManagedObjectContext:self.managedObjectContext];
In my VC2.m
-(NSFetchedResultsController*) fetchedResultController {
if (_fetchedResultController != nil) {
return _fetchedResultController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *SCTrackEntity = [NSEntityDescription entityForName:#"SCTrack" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:SCTrackEntity];
// NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:YES];
// [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
_fetchedResultController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:nil];
_fetchedResultController.delegate = self;
return _fetchedResultController;
}
This is the error I get:
CoreData: error: Failed to call designated initializer on NSManagedObject class 'SCTrack'
Very new to Core Data. Been at this for a few hours now. Thanks for pointing me in the right direction.
The designated initialiser for NSManaged Object is initWithEntity: insertIntoManagedObjectContext:.
Change
SCTrack* trackObject = [[SCTrack alloc]initWithDictionary:trackDict];
to
SCTrack *trackObject = [[SCTrack alloc]initWithEntity:entity insertIntoManagedObjectContext:context];

Deallocated Instance in UICollectionViewController

I have a class called SLCollectionViewModel that, if initiated, will fetch the latest entry with Core Data. So far there is no problem with the initial view. The Collection View will display the visible entries correctly (and also shows them in log).
But the problem occurs when I try to scroll the view, or try to call [self.collectionView reloadData] explicitly. The error log is:
-[_PFArray retain]: message sent to deallocated instance 0x8de9ab0
I think my self.viewModel object is deallocated somewhere, but I can’t pinpoint what’s wrong with my approach. Here is my - (void)viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
self.viewModel = [SLCollectionViewModel new];
[self.collectionView reloadData];
}
And here is my SLCollectionViewModel class:
- (instancetype) init {
self = [super init];
if(!self) return nil;
_managedObjectContext = [[SLCoreDataStack defaultStack] managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"SLPost"
inManagedObjectContext:_managedObjectContext];
[fetchRequest setEntity:entity];
// The _posts in an NSArray that saves all my NSManageObject
// which will be used to populate the collection view.
_posts = [_managedObjectContext executeFetchRequest:fetchRequest
error:nil];
return self;
}
I realize this is my own mistake for not creating the property properly. In my SLCollectionViewModel, the #property for NSArray *posts should use retain instead of assign.
Before:
#property (nonatomic, assign) NSArray *posts;
After:
#property (nonatomic, retain) NSArray *posts;

App crashes when accessing NSMutableArray Count ios

I landed into a weird problem where i cannot use array.count that crashes my app.
#interface LAMasterViewController ()
NSMutableArray * claimReports
#end
-(void) ViewDidLoad
{
claimReports = [[NSMutableArray alloc] init];
[claimReports addObjectsFromArray:[[LADataModelController getSingleton] getClaimReportsOrderedByIncidentDate] ];
}
-(NSArray *) getClaimReportsOrderedByIncidentDate
{ // it returns one record
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [ NSEntityDescription entityForName:#"ClaimReport" inManagedObjectContext:context];
NSSortDescriptor *sortByIncidentDate = [[NSSortDescriptor alloc] initWithKey:#"dateOfIncident" ascending:NO];
[request setEntity:entity];
[request setSortDescriptors: [NSArray arrayWithObject: sortByIncidentDate]];
NSArray *array = [context executeFetchRequest:request error:&error];
NSLog(#"Array Count %i" ,array.count);
return array;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return claimReports.count; //crashes here
}
error:
-[LSClaimReport count]: unrecognized selector sent to instance 0xa54afc0
2014-04-01 14:56:29.022 LossAdjusting[6956:70b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[LSClaimReport count]: unrecognized selector sent to instance 0xa54afc0'
What have i missed here. Seems a silly one. please guide.
Thanks
Long-story-short, you are treating an instance of LSClaimReport as if it was an NSMutableArray instance.
The end.
EDIT OK, flippany aside, you are confused about instance variable and local variables and have confused the types of one of your instance variables.
In ViewDidLoad (case incorrect, so if that's copied verbatim then it won't even be called), you reference a local version of claimReports which is created and then thrown away:
-(void)ViewDidLoad
{
NSMutableArray *claimReports = [[NSMutableArray alloc] init];
[claimReports addObjectsFromArray:[[LADataModelController getSingleton] getClaimReportsOrderedByIncidentDate] ];
}
and later you refer to the instance variable version:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return claimReports.count; //crashes here
}
Which is clearly a LSClaimReport instance and not a NSMutableArray.
So it looks like:
You have declared the wrong type in your #interface.
You are not initializing it correctly (you already fixed that bit).
please remove the local Arraydeclaration:
NSMutableArray * claimReports = [[NSMutableArray alloc] init];
instead use:
claimReports = [[NSMutableArray alloc] init];
In case this is no Class variable yet, add it to your #interface-declaration:
#interface LAMasterViewController ()
{
NSMutableArray * claimReports
}
#end
#implementation LAMasterViewController
Write this in your .h file
NSMutableArray * claimReports;
and in your .m
-(void)viewDidLoad{
claimReports = [[NSMutableArray alloc] init];
[claimReports addObjectsFromArray:[[LADataModelController getSingleton] getClaimReportsOrderedByIncidentDate] ];
}
You have few things wrong with your code which cleaning them up will help resolve the issue, the main issue '-[LSClaimReport count]: unrecognized selector sent to instance 0xa54afc0' is because you are calling count on an instance of LSClaimReport which clearly shouldn't be happening. Your code seems to think that claimReports is an instance of LSClaimReport and not an instance of NSMutableArray.
As for your code may I recommend changing to (Please see comments in code marked issue)
#interface LAMasterViewController ()
// Clearly you want this as a private property so why would you want to change
// to having this in the .h file which would make it public
// But Issue 1 is here you are missing the semi-colon (`;`) of the end.
#property (nonatomic, strong) NSMutableArray *claimReports;
#end
// Issue two you are missing the `#implementation LAMasterViewController`
#implementation LAMasterViewController
// The synthesize is done automatically so getters/setters/ivar are created automatically
// Issue 3: ViewDidLoad isn't a valid selector so ViewDidLoad will never be called
// It is viewDidLoad
-(void)viewDidLoad
{
[super viewDidLoad]; // Issue 4: you missed the call to super
claimReports = [[NSMutableArray alloc] init];
[claimReports addObjectsFromArray:[[LADataModelController getSingleton] getClaimReportsOrderedByIncidentDate]];
}
-(NSArray *)getClaimReportsOrderedByIncidentDate
{ // it returns one record
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [ NSEntityDescription entityForName:#"ClaimReport" inManagedObjectContext:context];
NSSortDescriptor *sortByIncidentDate = [[NSSortDescriptor alloc] initWithKey:#"dateOfIncident" ascending:NO];
[request setEntity:entity];
[request setSortDescriptors: [NSArray arrayWithObject: sortByIncidentDate]];
NSArray *array = [context executeFetchRequest:request error:&error];
NSLog(#"Array Count %i" ,array.count);
return array;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return claimReports.count;
}
#end

Core Data, can't save context

I'm simply trying to save a ManagedObjectContext but while I get no errors, the fetched request returns the object with none of the saved values. Consider this simple example. You have a single object, you change a property and save it. The object is there but the property is not saved. As you can see, I want only one object, and the fetch returns this one object. BTW, the code is in a simple class, not the app delegate or a view controller.
Here is the sample code:
MyAppDelegate* delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext* context = delegate.managedObjectContext;
NSEntityDescription *myEntityDesc = [NSEntityDescription entityForName:#"MyEntity" inManagedObjectContext:context];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:myEntityDesc];
NSError *error = nil;
NSArray *array = [context executeFetchRequest:request error:&error];
MyEntity* myEntity;
if (array == nil || [array count] < 1)
{
myEntity = [NSEntityDescription insertNewObjectForEntityForName:#"MyEntity" inManagedObjectContext:context];
}
else
{
myEntity = [array objectAtIndex:0];
}
myEntity.BoolValue = [NSNumber numberWithBool:someBoolValue];
myEntity.ID = #"Some ID";
if ([context save:&error])
{
NSLog(#"no error");
}
else
{
NSLog([NSString stringWithFormat:#"found core data error: %#", [error localizedDescription]]);
}
Here's the code used to retrieve the values later:
MyAppDelegate* delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext* context = delegate.managedObjectContext;
NSEntityDescription *MyEntityDesc = [NSEntityDescription entityForName:#"MyEntity" inManagedObjectContext:context];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:MyEntityDesc];
NSError *error = nil;
NSArray *array = [context executeFetchRequest:request error:&error];
MyEntity* myEntity;
if (array == nil || [array count] < 1)
{
//handle error
}
else
{
myEntity = [array objectAtIndex:0];
}
return [myEntity.BoolValue boolValue];
What does your NSManagedObject subclass look like? Since the fetch is working correctly (i.e. returning the entity), I suspect something is wrong in the subclass implementation.
You should declare a #property for each of the attributes on your data model. And in the implementation file, instead of using #synthesize you need to use #dynamic. Also make sure in your xcdatamodel that the entity has its class set, as well as the name.
#interface MyEntity : NSManagedObject
#property (nonatomic, strong) NSNumber * boolValue;
#end
#implementation MyEntity
#dynamic boolValue;
#end

Load CoreData objects' string property into UIPickerView

Currently I have an entity named "Events" in a CoreData app. "Events" has one string property named "eventName".
In the -(void)viewDidLoad I am trying to Fetch all the "Events" objects and load their "eventName" by alphabetical order into a UIPickerView.
The ultimate end goal is through the use of a textField, buttons and the pickerView being add new objects in and remove unwanted objects out. Basically turning the UIPickerView into a UITableView. Currently I am able to save objects to the CoreData store, but am not able to pull them/their properties out into the UIPickerView.
I am willing and able to share the project source code to anyone who wants it, or is willing to look at it to help out.
thanks
Chris
-(void)update
{
NSMutableArray *array2 = [[NSMutableArray alloc] init];
CDPickerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *moc = [appDelegate managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"callName" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
NSArray *array = [moc executeFetchRequest:request error:&error];
for (int i=0; i<array.count; i++) {
Event *theEvent = [array objectAtIndex:i];
NSString *StringOne = [NSString stringWithFormat:#"%#",theEvent.callName];
[array2 addObject:StringOne];
}
self.pickerData = array2;
[singlePicker reloadAllComponents];
}
-(IBAction)addCall{
CDPickerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *theEvent = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[theEvent setValue:callField.text forKey:#"callName"];
[context save:&error];
callField.text=#"";
[callField resignFirstResponder];
self.update;
}

Resources