The is the code for the fetchRequest in viewDidLoad and the code is followed from a tutorial found here just that I'm linking the navigation controller and the tableview programmatically instead of using interface builder. The entity ProductInfo exists. However when I run the program I get the error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'ProductInfo''
I have reset the simulator incase it was an old model but the error still occurs. I have also switched to use a FetchedResultsController but the problem still persists. Is the problem because these fetchedResultsController methods aren't inside the appdelegate? They are currently in a TableViewController. How can I solve this problem?
viewDidLoad Method:
- (void)viewDidLoad{
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:#"ProductInfo" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError * error;
self.productInfos = [_context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
[super viewDidLoad];}
ProductInfo.h:
#class ProductDetails;
#interface ProductInfo : NSManagedObject {
#private
}
#property (nonatomic, retain) NSString * productName;
#property (nonatomic, retain) NSString * productPrice;
#property (nonatomic, retain) ProductDetails * details;
#end
FetchedResultsController
-(NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:#"ProductInfo" inManagedObjectContext:_context]; //line that is causing the problem
[fetchRequest setEntity:entity];
NSSortDescriptor * sort = [[NSSortDescriptor alloc] initWithKey:#"productInfos.productName" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController * theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext: _context sectionNameKeyPath:nil cacheName:#"Root"];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = nil;
[sort release];
[fetchRequest release];
[theFetchedResultsController release];
return _fetchedResultsController;
}
Any help much appreciated.Thanks in advance.
In case the above fragments i pasted did not help, I attached the whole project with the data model inside too.
http://www.mediafire.com/?5cns4q0sv9hqn6s
This happens to me every time a switch development computers. What I have to do is
Uninstall the app from the simulator.
Rename the database file that stores the UIManagedDocument.
Perform a Build Clean.
Build and run the application.
Having run into this problem before, it sounds like it might be a simple misspelling of the entity name in the xcdatamodeld file. The string "ProductInfo" must match exactly the name of the entity in the model file.
It might also be that your context is not making the correct reference. Consider showing some more of your code related to the context if the above doesn't fix the issue.
Related
I am working on a new project and for that I reuse my old saving and fetching code that is working just fine in the old app. Unfortunately, it doesn't work in my new project where I'm doing something very similar.
The user is presented with a table view and possibility to add new data by tapping the plus button that takes them to a different view controller where they can add the appropriate data and save. Saving works just fine without any problems.
Here's the code that is working fine:
+ (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).persistentContainer.viewContext;
return context;
}
In main view that is table view I try to fetch the data with the following code:
// Fetch the data from persistent data store
NSManagedObjectContext *context = [MGManagedObjectContext managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Data"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
[fetchRequest setSortDescriptors:#[sortDescriptor]];
self.dataArray = [[context executeRequest:fetchRequest error:nil] mutableCopy];
For whatever reason I get the "[NSAsynchronousFetchResult mutableCopyWithZone:]: unrecognized selector sent to instance 0x283619220" error that I can't work out why.
Any ideas how to fix this issue ?
Instead of method
- (__kindof NSPersistentStoreResult *)executeRequest:(NSPersistentStoreRequest *)request error:(NSError * _Nullable *)error;
use method
- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError * _Nullable *)error;
Example:
self.dataArray = [[context executeFetchRequest:fetchRequest error:nil] mutableCopy];
With the latest LLVM build, the requirement for synthesizing properties has been removed.
Therefore I was able to remove all my #synthesize statements except for the ones for NSFetchedResultsController. Does anyone know why the compiler is warning me when I remove the #synthesize fetchedResultsController; line?
Error:
Use of undeclared identifier "fetchedResultsController", did you mean _fetchedResultsController?
This is my code:
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
#synthesize fetchedResultsController;
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController) {
return fetchedResultsController;
}
if (!self.managedObjectContext) {
self.managedObjectContext = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Session" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate: self.predicate];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchedResultsController= [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
fetchedResultsController.delegate = self;
NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return fetchedResultsController;
}
When you don't put an #synthesize in your code, the instance variable created to back the property is named _propertyName. You are referring to the instance variable fetchedResultsController which no longer exists after you remove the #synthesize. Instead, change all references to fetchedResultsController to _fetchedResultsController.
Because the default synthesized variable is _fetchedResultsController not fetchedResultsController
The property fetchedResultsController is automatically synthesized to _fetchedResultsController, and this happens for every synthesized variable.
You should synthesize it explicitly to change its name.
I have a helper class designed to get data from Core Data and pass it back to a view controller. Here's the code:
View Controller:
#interface AnnouncementsController : UIViewController
#property (nonatomic, retain) NSMutableArray *announcements;
#end
#implementation AnnouncementsController
#synthesize announcements;
- (void)viewDidLoad
{
AnnouncementCoreDataHelper *announcementHelper = [[AnnouncementCoreDataHelper alloc] init];
self.announcements = [announcementHelper selectAnnouncementsWithPredicate:#"isActive = 1" sortDescriptor:#"lastUpdated" sortAscending:NO];
[super viewDidLoad];
}
#end
And the Core Data Helper implementation:
// Select one or more announcements based on a predicate if passed in and a sort order
- (NSMutableArray*)selectAnnouncementsWithPredicate:(NSString *)predicateString sortDescriptor:(NSString *)sortBy sortAscending:(BOOL)isAscending
{
NSError *error = nil;
// Build the entity and request
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Announcement" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
if(predicateString)
{
// Set the search criteria
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
[request setPredicate:predicate];
}
if(sortBy)
{
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortBy ascending:isAscending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
}
// Perform the search
NSMutableArray *results = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if(results == Nil)
{
NSLog(#"%#", error);
}
return results;
}
The problem is that the Core Data Helper returns two objects in its NSMutableArray results but the View Controller's NSMutableArray announcements gets nil. What is getting lost in the passing the NSMutableArray back from the helper to the controller? If I change all the variables and results to a NSArray, everything works.
I believe this was a funky issue with Xcode. I clean and reran the build and everything is working. I apologize for wasting your time and thanks for the help! I would like to know more about the memory management issues though.
This is the original header file:
#interface TestDataHelper : NSObject {
}
+(void) populateTestData:(NSManagedObjectContext*) managedObjectContext;
+(void) testPopulateTestData:(NSManagedObjectContext*) managedObjectContext;
#end
When I compile this file, I got this warning:
method definiton not found
for testPopulateTestData
When I ignore the warning and run the app in iphone simulator, I got a runtime exception:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[TestDataHelper testPopulateTestData:]: unrecognized selector sent to class 0x104d8'
Rename the method to 'test' alone seems to solve the problem
What is special about testXXX method name?
EDIT: implementation is there and done. Renaming the method name (in both .h and .m) removes the warning, and the final app works.
EDIT 2:
Here is the implementation of the function test (originally named as testPopulatedTestData):
+(void) test:(NSManagedObjectContext*) managedObjectContext {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Stock" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
NSEnumerator *e = [mutableFetchResults objectEnumerator];
id object;
while (object = [e nextObject]) {
// do something with object
Stock* fc = (Stock*) object;
NSLog(#"get a fc %s", [[fc name] description]);
}
}
The error message is telling you that you've declared a method in your header file that you never implemented anywhere. The runtime error is telling you the same thing - you've sent the selector testPopulateTestData to the class TestDataHelper but it was never implemented.
I am using CoreData and have an Entity ContactList defined, which I created using the XCode xcdatamodel tool (or whatever you call that built-in thing:). I also set the Entity's Class name to "ContactList". I then used rentzsch's mogenerator (http://github.com/rentzsch/mogenerator) to generate my custom class files and added the simple method "toString" to my ContactList class.
The fetchedResultsController callback is pretty much standard and looks as follows:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController_ != nil) {
return fetchedResultsController_;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ContactList" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![fetchedResultsController_ performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return fetchedResultsController_;
}
Now, when I start my application and try to call that method on a "ContactList" object, which in turn I get from a NSFetchedResultsController, I get
ContactList *contactList = (ContactList *) [self.fetchedResultsController objectAtIndexPath:indexPath];
[contactList toString];
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject toString]: unrecognized selector sent to instance 0x6af7bf0'
As the message shows, somehow the NSFetchedResultsController does not return a "ContactList" object, but a more general NSManagedObject instead.
Does anybody know why and how to resolve this???
I had this same problem - Caused because I had previously renamed the Entity's Managed Object subclass. In the Data Modeler, make sure in the Inspector for the entity, both the "Name" and the "Class" are set correctly.
Ok, I figured this it out.
The problem was that the mogenerator script did not add its generated source files to the project's compile target. This way the classes never got compiled and included (I wonder how it worked without any model object classes :)
After adding the .xcdatamodel file to the Target (RightClick on .xcdatamodel file -> Targets -> check your project) everything works now.
For further info go here