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;
Related
I have a sample app that has a single NSManagedObject (let's call the class CustomObject) with a single property.
The app has a simple UI consisting of a view controller with a UICollectionView using an NSFetchedResultsController as the underlying data source. The NSFetchedResultsController is also setup to use the view controller as it's NSFetchedResultsControllerDelegate delegate. Additionally I have toolbar with some buttons to add/remove CustomObject items.
One button will result in 10,000 CustomObject entities being created. I'd like to be able to press this button, and once the entities are saved to the disk/ready to be used, the UICollectionView should update to reflect the new values. I am 100% aware that there will be a delay of some kind - saving values like this is not instantaneous - I want the delay to occur on a background thread to prevent the UI from locking up!
Despite me setting things up correctly from what I can tell, I experience UI lag whenever I implement any of the three "important" NSFetchedResultsControllerDelegate methods. The UI lag duration varies based on the number of CustomObjects in the data store already. For example if I just added the first 10,000, there is only a small amount of lag, less than 1 second. If I've added 50,000 CustomObjects already the lag is much more noticeable and lasts for over 5-10 seconds in some cases.
As I said, the UI lag only shows up when I implement either the controllerWillChangeContent, controller:didChangeObject:atIndexPath:forChangeType:newIndexPath, or controllerDidChangeContent methods. Even with no actual implementation in the method just the fact that it is in the view controller makes the insertion slow.
Any idea what I am doing wrong? Is there a way around this? Here's some code:
CoreDataController.m - responsible for setting up the core data stack
//
// CoreDataController.m
// CoreDataTestApp
//
// Created by ZOlbrys on 4/12/18.
// Copyright © 2018 ZOlbrys. All rights reserved.
//
#import "CoreDataController.h"
#import <UIKit/UIKit.h>
#interface CoreDataController()
#property (nonatomic, strong) NSURL *persistentStoreURL;
#property (nonatomic, strong) NSURL *managedObjectModelURL;
#property (nonatomic, strong, readwrite) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, strong, readwrite) NSManagedObjectContext *managedObjectContext;
#end
#implementation CoreDataController
+ (CoreDataController *)sharedController {
static CoreDataController *sharedController;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURL *managedObjectModelURL = [NSURL fileURLWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:#"CoreDataTestApp" ofType:#"momd"]];
NSString *applicationDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *persistentStoreURL = [NSURL fileURLWithPath:[applicationDocumentsDirectory stringByAppendingPathComponent:#"CoreDataTestApp.sqlite"]];
sharedController = [[CoreDataController alloc] initWithManagedObjectModelURL:managedObjectModelURL persistentStoreURL:persistentStoreURL];
});
return sharedController;
}
- (instancetype)initWithManagedObjectModelURL:(NSURL*)managedObjectModelURL persistentStoreURL:(NSURL*)persistentStoreURL {
self = [super init];
if (self) {
self.persistentStoreURL = persistentStoreURL;
self.managedObjectModelURL = managedObjectModelURL;
[self setupCoreDataStack];
}
return self;
}
- (void)setupCoreDataStack {
// setup managed object model
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:self.managedObjectModelURL];
// setup persistent store coordinator
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
[_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.persistentStoreURL options:nil error:nil];
// setup MOC
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
#end
ViewController.m - responsible for, well, view controller stuff!
//
// ViewController.m
// CoreDataTestApp
//
// Created by ZOlbrys on 4/12/18.
// Copyright © 2018 ZOlbrys. All rights reserved.
//
#import "ViewController.h"
#import "CustomCell.h"
#import "CoreDataController.h"
#import "CustomObject+CoreDataClass.h"
static NSString *const CUSTOM_CELL_REUSE_IDENTIFIER = #"CUSTOM_CELL_REUSE_IDENTIFIER";
#interface ViewController ()<UICollectionViewDataSource, UICollectionViewDelegate, NSFetchedResultsControllerDelegate>
#property (strong, nonatomic) IBOutlet UICollectionView *collectionView;
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
[self setupFetchedResultsController];
}
- (void)setupFetchedResultsController {
NSFetchRequest<CustomObject *> *fetchRequest = [CustomObject fetchRequest];
fetchRequest.sortDescriptors = #[ [[NSSortDescriptor alloc] initWithKey:#"identifier" ascending:YES] ];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[CoreDataController sharedController].managedObjectContext sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController.delegate = self;
[self.fetchedResultsController performFetch:nil];
[self.collectionView reloadData];
}
- (void)addObjects:(NSUInteger)objectCount {
NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = [CoreDataController sharedController].managedObjectContext;
[temporaryContext performBlock:^{
for (int i = 0; i < objectCount; i++) {
CustomObject *object = [NSEntityDescription insertNewObjectForEntityForName:#"CustomObject" inManagedObjectContext:temporaryContext];
object.identifier = [[NSUUID UUID] UUIDString];
}
NSError *error;
if (![temporaryContext save:&error]) {
NSLog(#"Error: %#", error);
}
[[CoreDataController sharedController].managedObjectContext performBlock:^{
NSError *error;
if (![[CoreDataController sharedController].managedObjectContext save:&error]) {
NSLog(#"Error: %#", error);
}
}];
}];
}
- (void)removeObjects:(NSUInteger)objectCount {
NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = [CoreDataController sharedController].managedObjectContext;
[temporaryContext performBlock:^{
NSFetchRequest<CustomObject *> *fetchRequest = [CustomObject fetchRequest];
fetchRequest.sortDescriptors = #[ [[NSSortDescriptor alloc] initWithKey:#"identifier" ascending:YES] ];
fetchRequest.fetchLimit = objectCount;
NSFetchedResultsController<CustomObject *> *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:temporaryContext sectionNameKeyPath:nil cacheName:nil];
[fetchedResultsController performFetch:nil];
for (CustomObject *object in fetchedResultsController.fetchedObjects) {
[temporaryContext deleteObject:object];
}
NSError *error;
if (![temporaryContext save:&error]) {
NSLog(#"Error: %#", error);
}
[[CoreDataController sharedController].managedObjectContext performBlock:^{
NSError *error;
if (![[CoreDataController sharedController].managedObjectContext save:&error]) {
NSLog(#"Error: %#", error);
}
}];
}];
}
- (IBAction)add10k:(id)sender {
[self addObjects:10000];
}
- (IBAction)add1:(id)sender {
[self addObjects:1];
}
- (IBAction)refetchData:(id)sender {
[self.fetchedResultsController performFetch:nil];
[self.collectionView reloadData];
}
- (IBAction)remove1:(id)sender {
[self removeObjects:1];
}
- (IBAction)remove10k:(id)sender {
[self removeObjects:10000];
}
#pragma mark UICollectionViewDataSource
- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.fetchedResultsController.sections objectAtIndex:section].numberOfObjects;
}
- (nonnull __kindof UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
CustomCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:CUSTOM_CELL_REUSE_IDENTIFIER forIndexPath:indexPath];
[cell setDisplayText:#"TODO"];
cell.backgroundColor = [UIColor blueColor];
return cell;
}
#pragma mark NSFetchedResultsControllerDelegate
//- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// // TODO
//}
//
//- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
// // TODO
//}
//
//- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// // TODO
//}
#end
Of course, I did some profiling - with controllerWillChangeContent uncommented above, I see this:
Which is not my code - it's internal Apple code...
Here's a github link to a project showing this issue:
Sample Core Data project
The lag seems to be related to the chosen Core Data stack:
[Coordinator] ← [Main Context] ← [Private Context]
With this architecture, each fetch/save operations on the private context will fall through the main context and then block the UI. A better choice could be to swap the contexts:
[Coordinator] ← [Private Context] ← [Main Context]
This time, private context operations will not block the UI.
Another option is to bind both contexts to the coordinator:
[Private Context] → [Coordinator] ← [Main Context]
With both solutions, you will need to merge back updated objects to the main context if needed, in order to "see" the changes from the UI.
I'm trying add data to CoreData.
This is my code.But I'm getting this error.What should I do in this case ?
That is my ViewController.h
#interface LoginViewController : UIViewController {
NSManagedObjectContext *managedObjectContext;
}
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
And This is my .m file
Person *person = [[Person alloc] initWithJSONString:string];
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObjectContext *object = [NSEntityDescription insertNewObjectForEntityForName:#"Users" inManagedObjectContext:context];
[object setValue:person.name forKey:#"name"];
[object setValue:person.id forKey:#"userId"];
[object setValue:person.statu forKey:#"statu"];
[object setValue:person.token forKey:#"token"];
[object setValue:person.sonuc forKey:#"sonuc"];
- (NSManagedObjectContext *)managedObjectContext
{
if (managedObjectContext != nil) return managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext;
}
This is error.
'+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Users''
Thanks for your help
The heart of your problem is that you have not thought about where persistentStoreCoordinator comes from, and this object is never created.
Your check, if (coordinator != nil), is hiding this problem. Instead, you should aim to set things up so coordinator is never nil. Then the check can be removed or, even better, replaced with an assertion that this is the case: NSAssert(coordinator != nil, #"There is no persistent store coordinator.").
If the persistent store coordinator comes from outside this view controller, I recommend passing it as part of the view controller’s initialisation. If the view controller can set up the persistent store coordinator itself, either do this as part of its initialisation or load it lazily.
It is better to use
NSManagedObjectContext *object = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([YourClass class]) inManagedObjectContext:context];
You don't need to use hardcoded string as it may have typing errors.
In your case it must be
NSManagedObjectContext *object = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([Users class]) inManagedObjectContext:context];
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
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.
I've been following this tutorial to a T, but when I run my app, it fails on launch every time with the following error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a
legal NSManagedObjectContext parameter searching for entity name
'ArticleInfo''
But I can't figure out what I'm doing wrong that would cause that. As a background for what I've done, I have the datamodel file with an entity called ArticleInfo with a bunch of attributes of different types (some transient, if that's of note). Following the advice of this article I subclassed NSManagedObject as ArticleInfo.
If it's worth noting, I made the preview, wordsInBody and progress transient in the datamodel (and I gave position a default value of 0 in the Data Model Inspector). So in the subclass I made custom getters as follows:
- (NSString *)preview {
[self willAccessValueForKey:#"preview"];
NSString *preview = [self primitiveValueForKey:#"preview"];
[self didAccessValueForKey:#"preview"];
if (self.body.length < 200) {
preview = self.body;
}
else {
preview = [self.body substringWithRange:NSMakeRange(0, 200)];
}
return preview;
}
- (NSNumber *)progress {
[self willAccessValueForKey:#"progress"];
NSNumber *progress = [self primitiveValueForKey:#"progress"];
[self didAccessValueForKey:#"progress"];
if (self.body.length == 0) {
progress = #100;
}
else {
progress = #(100 * [self.position intValue] / [self.wordsInBody intValue]);
}
return progress;
}
- (NSNumber *)wordsInBody {
[self willAccessValueForKey:#"wordsInBody"];
NSNumber *wordsInBody = [self primitiveValueForKey:#"wordsInBody"];
[self didAccessValueForKey:#"wordsInBody"];
if (!wordsInBody) {
__block int numberOfWordsInBody = 0;
NSRange range = {0, self.body.length};
[self.body enumerateSubstringsInRange:range options:NSStringEnumerationByWords usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
numberOfWordsInBody++;
}];
wordsInBody = #(numberOfWordsInBody);
}
return wordsInBody;
}
(Again, not sure if that's relevant.)
Now in my main viewcontroller class (the one that has the tableview I'm using NSFetchedResultsController for) I declared the property, and overrode its getter:
In .h:
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
In .m:
- (NSFetchedResultsController *)fetchedResultsController {
if (!_fetchedResultsController) {
NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ArticleInfo" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = entity;
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:descriptor];
request.fetchBatchSize = 20;
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:#"Root"];
_fetchedResultsController = fetchedResultsController;
_fetchedResultsController.delegate = self;
}
return _fetchedResultsController;
}
But again, it keeps giving me that error on app launch. What exactly am I doing wrong that's causing that error?
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ArticleInfo" inManagedObjectContext:context]
Something here is nil. Log context and entity to see which one. Maybe your entity name in your model isn't "ArticleInfo" (typo?) or your app delegate has a problem creating the context.