Background thread method not solving freezing issue - ios

I have my app freezing issue, So i used Instruments to find the issue and found that issues are related to CoreData save and fetch. I have tried background coredata method (parent-child, Notification) but my issue has been not resolved. Also I referred http://martiancraft.com/blog/2015/03/core-data-stack/ but dont know how this method implemeted in my app.
instrument log:
https://www.dropbox.com/s/agjtw1wqubsgwew/Instruments9.trace.zip?dl=0
SAVE to DB
-(void)updateThreadEntityWithSyncDetails:(NSMutableDictionary *)inDictionary
{
NSString *loginUser=[[NSUserDefaults standardUserDefaults] valueForKey:#"currentUser"];
AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
// NSManagedObjectContext *writerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// [writerContext setPersistentStoreCoordinator:[sharedDelegate persistentStoreCoordinator]];
// create main thread MOC
// context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
// context.parentContext = writerContext;
// NSManagedObjectContext *contextforThread = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// contextforThread.parentContext = context;
// [contextforThread performBlock:^{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ThreadInfo"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *userPredicate = [NSPredicate predicateWithFormat:#"userEmail == %#",loginUser];
NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:#"threadID == %#",[inDictionary valueForKey:#"thread"]];
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates: #[userPredicate, threadPredicate]];
[fetchRequest setPredicate:compoundPredicate];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];
for (ThreadInfo *threadInfo in fetchedObjects)
{
if([[inDictionary allKeys] containsObject:#"userEmail"])
{
if([inDictionary valueForKey:#"userEmail"]!=[NSNull null])
{
threadInfo.userEmail=[inDictionary valueForKey:#"userEmail"];
}
}
if([[inDictionary allKeys] containsObject:#"badgeValue"])
{
if([inDictionary valueForKey:#"badgeValue"]!=[NSNull null])
{
threadInfo.badgeValue=[inDictionary valueForKey:#"badgeValue"];
}
}
if([[inDictionary allKeys] containsObject:#"choice4Percentage"])
{
if([inDictionary valueForKey:#"choice4Percentage"]!=[NSNull null])
{
threadInfo.choice4Percentage=[inDictionary valueForKey:#"choice4Percentage"];
}
}
if([[inDictionary allKeys] containsObject:#"choice5Percentage"])
{
if([inDictionary valueForKey:#"choice5Percentage"]!=[NSNull null])
{
threadInfo.choice5Percentage=[inDictionary valueForKey:#"choice5Percentage"];
}
}
}
NSError *error;
if(![context save:&error]) {
NSLog(#"Child error : %#",error);
}
// [context performBlock:^{
// NSError *error;
// if(![context save:&error]) {
// NSLog(#"%#",error);
// }
// }];
// }];
}
FETCH
-(ThreadInfo *)retrieveSolicitationInfoForThreadID:(NSString*)inThreadID;
{
NSString *loginUser=[[NSUserDefaults standardUserDefaults] valueForKey:#"currentUser"];
AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ThreadInfo"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *userPredicate = [NSPredicate predicateWithFormat:#"userEmail == %#",loginUser];
NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:#"threadID == %#",inThreadID];
\
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates: #[userPredicate, threadPredicate]];
[fetchRequest setPredicate:compoundPredicate];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];
if(fetchedObjects.count!=0)
{
ThreadInfo *threadInfo=[fetchedObjects objectAtIndex:0];
return threadInfo;
}
return nil;
}
SYNC
-(void)updateSolicitationWithSyncDetails:(NSDictionary *)inDictionary
{
NSMutableDictionary *paramDict=[NSMutableDictionary dictionaryWithDictionary:inDictionary];
NSString *userEmail=[[NSUserDefaults standardUserDefaults] valueForKey:#"currentUser"];
[paramDict setObject:[NSNumber numberWithBool:NO] forKey:#"isSystemMessage"];
[paramDict setObject:userEmail forKey:#"userEmail"];
if([[inDictionary allKeys] containsObject:#"owned"])
{
BOOL isDuplicate=[[IXDataBaseManager sharedNetworkDataManager] checkForExistenceOfThreadDetailsForSolicitationID:[inDictionary objectForKey:#"solicitation"]];// FETCH
if(!isDuplicate)
{
int randomIndex=[[IXNetworkDataManager sharedNetworkDataManager] getIndexForColorImageForTab:#"OUT"];
[paramDict setObject:message forKey:#"threadDescription"];
[paramDict setObject:[NSNumber numberWithInt:randomIndex] forKey:#"colorCode"];
BOOL isDuplicateVal=[[IXDataBaseManager sharedNetworkDataManager] checkForExistenceOfSolicitationID:[inDictionary objectForKey:#"solicitation"]];// FETCH
[paramDict setObject:message forKey:#"threadDescription"];
ThreadInfo *threadInfo=[[IXDataBaseManager sharedNetworkDataManager] retrieveSolicitationInfoForThreadID:[inDictionary objectForKey:#"solicitation"]];
[paramDict setObject:threadInfo.threadID forKey:#"thread"];
[[IXDataBaseManager sharedNetworkDataManager] updateThreadEntityWithSyncDetails:paramDict];
}
}
}

First, thank you for making the code snippets and the trace available right away. That is very helpful.
So, looking at the trace and the code.
-updateThreadEntityWithSyncDetails: is being called on the main thread and is 33% of the time spent there. Not good.
You are passing nil for error: NEVER do that. Always pass an error pointer and check the results of your call to see if there is an error.
This conditional can be a lot cleaner:
if([[inDictionary allKeys] containsObject:#"userEmail"])
{
if([inDictionary valueForKey:#"userEmail"]!=[NSNull null])
{
threadInfo.userEmail=[inDictionary valueForKey:#"userEmail"];
}
}
Consider:
if (inDictionary[#"userEmail"] != nil && inDictionary[#"userEmail"] != [NSNull null]) {
threadInfo.userEmail = inDictionary[#"userEmail"];
}
Much easier to read.
This re-write of the method will get the work off the main thread:
- (void)updateThreadEntityWithSyncDetails:(NSMutableDictionary*)inDictionary
{
NSString *loginUser = [[NSUserDefaults standardUserDefaults] valueForKey:#"currentUser"];
AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:[sharedDelegate managedObjectContext]];
[context performBlock:^{
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"ThreadInfo"];
[fetchRequest setReturnsObjectsAsFaults:NO];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"userEmail == %# && threadID == %#",loginUser, inDictionary[#"thread"]];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];
for (ThreadInfo *threadInfo in fetchedObjects) {
if (inDictionary[#"userEmail"] != nil && inDictionary[#"userEmail"] != [NSNull null]) {
threadInfo.userEmail = inDictionary[#"userEmail"];
}
if (inDictionary[#"badgeValue"] != nil && inDictionary[#"badgeValue"] != [NSNull null]) {
threadInfo.badgeValue = inDictionary[#"badgeValue"];
}
if (inDictionary[#"choice4Percentage"] != nil && inDictionary[#"choice4Percentage"] != [NSNull null]) {
threadInfo.choice4Percentage = inDictionary[#"choice4Percentage"];
}
if (inDictionary[#"choice5Percentage"] != nil && inDictionary[#"choice5Percentage"] != [NSNull null]) {
threadInfo.choice5Percentage = inDictionary[#"choice5Percentage"];
}
}
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Child error : %#",error);
}
}];
}
BUT it may still block the main thread as I am guessing the bulk of the CPU time is in executing this fetch. The fetch is slow. You have TWO string compares in that fetch. That is bad and should be corrected. If the ThreadID is not a string then reverse the fetch. Otherwise this is just poor data model design and there isn't going to be much help other than fixing that fetch.
Your other really slow point is in -checkForExistenceOfThreadDetailsForThreadID:. You did not post that method but I suspect it is the same issue, your fetch is costing you a tremendous amount of time AND it is on the main queue.
Overall the design of this is poor and needs to be reworked. You are comparing strings in the data store which is one of the slowest ways to retrieve data. You are also on the main thread for things that do not appear to NEED to be on the main thread.
Remember the golden rule, if the data is NOT being manipulated BY the user then the manipulation MUST NOT be on the main queue. No exceptions.

Have you tried to use an separate Context for the operation and merge it with the mainContext after the the save?
E.g.
NSManagedObjectContext * localContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[localContext setPersistentStoreCoordinator:[[self managedObjectContext] persistentStoreCoordinator]];
after your import is done you save your localContext
NSError * error = nil;
if (![[self localContext] save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
This will write your data to the PersistentStore.
Now your mainContext needs to be informed about the changes in the PersistentStore. This is done by observing for a notification.
e.g.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didSaveNotification:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
and this is the method which reacts to the notification:
- (void)didSaveNotification:(NSNotification *)notification
{
// NSLog(#"%s %#\n",__PRETTY_FUNCTION__,[notification userInfo]);
NSManagedObjectContext * mainContext = [self managedObjectContext];
void (^mergeChanges)(void)=^{
[mainContext mergeChangesFromContextDidSaveNotification:notification];
};
if([NSThread isMainThread]) {
mergeChanges();
} else {
dispatch_sync(dispatch_get_main_queue(), mergeChanges);
}
}
Using different NSManagedContext to work on the same PersistentStore is more threadsafe than working with a single NSManagedContext.

//Your Parent context init
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
[_managedObjectContext setUndoManager:nil];
}
return _managedObjectContext;
}
- (NSManagedObjectContext *)childManagedObjectContext
{
if (_childManagedObjectContext != nil) {
return _childManagedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_childManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_childManagedObjectContext setPersistentStoreCoordinator:coordinator];
[_childManagedObjectContext setUndoManager:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_mocDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:nil];
}
return _childManagedObjectContext;
}
- (void)_mocDidSaveNotification:(NSNotification *)notification
{
NSManagedObjectContext *savedContext = [notification object];
// ignore change notifications for the main MOC
if (_managedObjectContext == savedContext)
{
return;
}
if (_managedObjectContext.persistentStoreCoordinator != savedContext.persistentStoreCoordinator)
{
// that's another database
return;
}
dispatch_sync(dispatch_get_main_queue(), ^{
[_managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
});
}
//Way to use the Parent- child context
[UIAppDelegate.childManagedObjectContext performBlock:^{
for (int i=0; i<count; i++) {
//Fill Database and save it in child context first for each entry and save it in child context
[UIAppDelegate.childManagedObjectContext save:nil];
}
dispatch_sync(dispatch_get_main_queue(), ^{
//Finally when u have inserted all entries save in the parent context
[UIAppDelegate.managedObjectContext save:nil];
});
}]
//Your code is huge to understand the logic but if you haven't tried in this way, just give it shot

Related

How to delete entries in core data

i am new to core data..
I know how to store and item.
- (void)dbSave:(NSString *)uri withContent:(NSDictionary *)content withExpiry:(double)date {
Cache *cache = [self dbLoad:uri];
if (cache == nil) {
cache = [NSEntityDescription insertNewObjectForEntityForName:#"Cache" inManagedObjectContext:[self managedObjectContext]];
}
double time = (double) [[NSDate date] timeIntervalSince1970] + date;
[cache setLocal:uri];
[cache setTime:#(time)];
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:content forKey:#"data"];
[archiver finishEncoding];
[cache setData:data];
NSError *error;
if (![[self managedObjectContext] save:&error]) {
}
}
But i am stuck with creating a method to clear this core data data base.. Does anyone know how?
NSManagedObjectContext *managedObjectContext=[appDelegate managedObjectContext];
NSFetchRequest *fetchRequest=[NSFetchRequest fetchRequestWithEntityName:#"entity"];
NSArray* currentRecord = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
if (currentRecord.count)
{
for (NSManagedObject *obj in currentRecord)
{
[managedObjectContext deleteObject:obj];
}
NSError * error = nil;
if (![managedObjectContext save:&error])
NSLog(#"Can't save ! %# %#",error,[error localizedDescription]);
else
NSLog(#"Data deleted");
}
use this
NSManagedObjectContext *managedContext = [[APP_DELEGATE dbManagerObj] newPrivateContext];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Cache"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"isUserData = %#",[NSNumber numberWithBool:true]];
[fetchRequest setPredicate:predicate];
if (IS_IOS9_ANDABOVE) {
NSBatchDeleteRequest *batchDeleteRequest = [[NSBatchDeleteRequest alloc]initWithFetchRequest:fetchRequest];
[[[APP_DELEGATE dbManagerObj]persistentStoreCoordinator]executeRequest:batchDeleteRequest withContext:managedContext error:nil];
}
else
{
NSArray *userRelatedDay = [managedContext executeFetchRequest:fetchRequest error:nil];
for (NSManagedObject *object in userRelatedDay) {
[managedContext deleteObject:object];
}
}

Getting Null Value From Database NSManagedObject

I am developing iOS app, which fetch data from Web Services and save it to local database and uses it various views as needed. The data is fetch from Web Service and save to database correctly. But while accessing data from NSManagedObject it show FAULT and the consequent NSDictionary shows null Values
The code follows:-
-(void)SaveData:(NSInteger)menuId categoryID:(NSInteger)catID caption:(NSString *)title parentID:(NSInteger)parentID
{
BBAppDelegate *appDelegate = [[BBAppDelegate alloc]init];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *userobj = [NSEntityDescription insertNewObjectForEntityForName:tableName
inManagedObjectContext:context];
[userobj setValue:[NSNumber numberWithInt:menuId] forKey:#"id"];
[userobj setValue:[NSNumber numberWithInt:catID] forKey:#"catid"];
[userobj setValue:[NSNumber numberWithInt:parentID] forKey:#"parentid"];
[userobj setValue:title forKey:#"caption"];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
NSLog(#"app dir: %#",[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]);
}
-(NSArray *)fetchedData{
BBAppDelegate *appdelegate = [[BBAppDelegate alloc]init];
NSManagedObjectContext *context = [appdelegate managedObjectContext];
NSFetchRequest *readData = [[NSFetchRequest alloc] init];
[readData setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription
entityForName:tableName inManagedObjectContext:context];
[readData setEntity:entity];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:readData error:&error];
// for (Test *test in array)
// {
// NSLog(#"Test: %# ", test.text);
// }
NSLog(#"%#",results);
return results;
}
-(void)removeData{
BBAppDelegate *appdelegate = [[BBAppDelegate alloc]init];
NSManagedObjectContext *context = [appdelegate managedObjectContext];
NSFetchRequest *delData = [[NSFetchRequest alloc]init];
[delData setEntity:[NSEntityDescription entityForName:tableName inManagedObjectContext:context]];
[delData setIncludesPropertyValues:NO];
NSError *error = nil;
NSArray *result = [context executeFetchRequest:delData error:&error];
for (NSManagedObject *value in result) {
[context deleteObject:value];
}
NSError *saveError = nil;
[context save:&saveError];
}
-(void)table:(NSString *)nameTable{
tableName =nameTable;
}
- (instancetype)initWithTableName:(NSString *)tablename
{
[self table:tablename];
return self;
}
-(NSMutableArray *)buldMenu{
NSArray *array = [self fetchedData];
return [self getmenus:0 arr:array];
}
-(NSMutableArray *)getmenus:(NSInteger)parentID arr: (NSArray *)array
{
NSMutableArray *aray = [[NSMutableArray alloc]init];
for (NSManagedObject *dic in array) {
if (dic.faultingState != 0) {
NSLog(#"%lu",(unsigned long)dic.faultingState);
//return nil;
}
NSArray *keys = [[[dic entity] attributesByName] allKeys];
NSLog(#"%#",keys);
NSDictionary *dict = [dic dictionaryWithValuesForKeys:keys];
NSLog(#"%#",dic);
NSLog(#"%#",dict);
NSInteger pID = [[dict objectForKey:#"parentid"]integerValue];
if (pID == parentID) {
BBMenuEntry *entryMenu = [[BBMenuEntry alloc]init];
entryMenu.menuID = [[dict objectForKey:#"id"]integerValue];
entryMenu.catID = [[dict objectForKey:#"catid"]integerValue];
entryMenu.caption = [dict objectForKey:#"caption"];
entryMenu.subMenus = [self getmenus:entryMenu.menuID arr:array];
[aray addObject:entryMenu];
}
}
return aray;
}

Getting app crash by iOS Persistent store issue and data not loading from Coredata

I'am getting
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject persistentStore]: unrecognized selector sent to instance 0x3bebf50'
and
while loading data from core data.I have referred links iOS Persistent store issue but it didnt solved my issue. Also data not saving to tableview.
Earlier it was loading but due to large data I've used background core data saving. but for now No data loading from DB. I'm using NSFetchResultController for fetching data.
-(void)updateThreadEntityWithSyncDetails:(NSMutableDictionary *)inDictionary
{
dispatch_queue_t backgroundQueue = dispatch_queue_create("backgroundQueueName", NULL);
NSString *loginUser=[[NSUserDefaults standardUserDefaults] valueForKey:#"currentUser"];
AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
NSManagedObjectContext *contextforThread = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
contextforThread.parentContext = context;
[contextforThread performBlock:^{
// AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ThreadInfo"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *userPredicate = [NSPredicate predicateWithFormat:#"userEmail == %#",loginUser];
NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:#"threadID == %#",[inDictionary valueForKey:#"thread"]];
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates: #[userPredicate, threadPredicate]];
[fetchRequest setPredicate:compoundPredicate];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:nil];
for (ThreadInfo *threadInfo in fetchedObjects)
{
if([[inDictionary allKeys] containsObject:#"userEmail"])
{
if([inDictionary valueForKey:#"userEmail"]!=[NSNull null])
{
threadInfo.userEmail=[inDictionary valueForKey:#"userEmail"];
}
}
if([[inDictionary allKeys] containsObject:#"secret_seed"])
{
if([inDictionary valueForKey:#"secret_seed"]!=[NSNull null])
{
threadInfo.threadSecret=[NSString stringWithFormat:#"%#",[inDictionary valueForKey:#"secret_seed"]];
}
}
if([[inDictionary allKeys] containsObject:#"r_key"])
{
if([inDictionary valueForKey:#"r_key"]!=[NSNull null])
{
threadInfo.remoteKey=[inDictionary valueForKey:#"r_key"];
}
}
if([[inDictionary allKeys] containsObject:#"solicitation"])
{
if([inDictionary valueForKey:#"solicitation"]!=[NSNull null])
{
threadInfo.solicitationID=[inDictionary valueForKey:#"solicitation"];
}
}
if([[inDictionary allKeys] containsObject:#"r_secret"])
{
if([inDictionary valueForKey:#"r_secret"]!=[NSNull null])
{
threadInfo.remoteSecret=[inDictionary valueForKey:#"r_secret"];
}
}
NSError *error;
if (![contextforThread save:&error]) {
NSLog(#"Could not insert to userInfo: %#", [error localizedDescription]);
}
[context performBlock:^{
NSError *error;
if (![context save:&error]) {
NSLog(#"Could not insert to userInfo: %#", [error localizedDescription]);
}
}];
}];
// if (![context save:&error]) {
// NSLog(#"Could not update to threadInfo: %#", [error localizedDescription]);
// }
}
Appdelegate
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#pragma mark - Core Data stack
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
// _managedObjectContext = [[NSManagedObjectContext alloc] init];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_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:#"IXCoreDataModel" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Inxed.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];
}
FetchedResultsController
-(NSFetchedResultsController*)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSString *loginUser=[[NSUserDefaults standardUserDefaults] valueForKey:#"currentUser"];
AppDelegate *sharedDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [sharedDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ThreadInfo"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:#"threadDate" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
NSPredicate *threadPredicate = [NSPredicate predicateWithFormat:#"userEmail == %#",loginUser];
// NSPredicate *providerPredicate = [NSPredicate predicateWithFormat:#"isReceiver == YES"];
// NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates: #[threadPredicate, providerPredicate]];
[fetchRequest setPredicate:threadPredicate];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:context sectionNameKeyPath:nil
cacheName:nil];
_fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
CRASH CODE
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
ThreadInfo *info=[_fetchedResultsController objectAtIndexPath:indexPath];
if([info.isSystemMessage boolValue])// CRASH CoreData: error: NULL _cd_rawData but the object is not being turned into a fault
{
return 178+90+25;
} else {
return 178;
}
getting
CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Only run on the main thread! with userInfo (null)
When scrolling to last cell, I'm getting this crash too with nothing in the cell.
Make sure you save your contexts in performBlock method like
[mainContext performBlock^{
[mainContext save:&error];
}];
Also refer this thread

Ios core data not saved

I'm using core data and i have a problem. When i save the data and the app is still running i can see and get the data that was saved.
Once the application is close, all the fields deleted and just the object is saved. I can see that in the saveContext method.
On first launch when the app is closing the saveContext method is activated. I can see that the managedObjectContext object is inserting new object.
The next times that the app is opening , the managedObjectContext is updating the object so i know it save the objects but when i try to retrive the object it can find .
here is how i insert objects:
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
self.managedObjectContext = appDelegate.managedObjectContext;
#try {
UserData *userData =[NSEntityDescription insertNewObjectForEntityForName:[UserTable tableName] inManagedObjectContext:self.managedObjectContext];
//Insert Values
userData.facebookId=user.id;
userData.name=user.name;
userData.picoAccessToken=[PicoApiManager sharedInstance].accessToken;
userData.picoExpire=[PicoApiManager sharedInstance].expires;
userData.latitude=[NSNumber numberWithDouble:user.latitude];
userData.longitude=[NSNumber numberWithDouble:user.longitude];
userData.pushId=user.pushId;
userData.isActive=[NSNumber numberWithBool:activeStatus];
}
#catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
}
or
-(void)addPictures:(NSMutableArray *)Pictures;
{
//Setting the isNew field to NO to all the pictures already in the db
[self updateIsNewOfPicture];
for (Picture *picture in Pictures) {
//Checks if inserted picture is already inside the table
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
self.managedObjectContext = appDelegate.managedObjectContext;
#try {
PictureData *pictureData=[NSEntityDescription insertNewObjectForEntityForName:[PicturesTable tableName]inManagedObjectContext:self.managedObjectContext];
//Insert Values
pictureData.url=picture.source;
pictureData.isNew=[NSNumber numberWithBool:YES];
pictureData.isPick=[NSNumber numberWithBool:NO];
pictureData.timeTaken=picture.time_taken;
pictureData.albumData=[self getActiveAlbum];
}
#catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
}
}
This is app delegate functions:
- (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]);
}
}
}
#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:#"Pico-Db" 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:#"Pico.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;
}
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
This is how i'm trying to get the data :
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
//2
// initializing NSFetchRequest
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
//Setting Entity to be Queried
NSEntityDescription *entity = [NSEntityDescription entityForName:[UserTable tableName] inManagedObjectContext:appDelegate.managedObjectContext];
[fetchRequest setEntity:entity];
NSError* error;
// Query on managedObjectContext With Generated fetchRequest
NSArray *fetchedRecords = [appDelegate.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (fetchedRecords.count >0) {
return YES;
}
return NO;
You must call -[AppDelegate saveContext] after inserting your data in order for CoreData to persist changes to disk. The NSManagedObjectContext will store changes in memory so while your application is still active, you will have access to the data. As soon as the app terminates, however, unless you call -[AppDelegate saveContext] those changes will not be persisted.
Try this in the first example:
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
self.managedObjectContext = appDelegate.managedObjectContext;
#try {
UserData *userData = [NSEntityDescription insertNewObjectForEntityForName:[UserTable tableName] inManagedObjectContext:self.managedObjectContext];
//Insert Values
userData.facebookId=user.id;
userData.name=user.name;
userData.picoAccessToken=[PicoApiManager sharedInstance].accessToken;
userData.picoExpire=[PicoApiManager sharedInstance].expires;
userData.latitude=[NSNumber numberWithDouble:user.latitude];
userData.longitude=[NSNumber numberWithDouble:user.longitude];
userData.pushId=user.pushId;
userData.isActive=[NSNumber numberWithBool:activeStatus];
} #catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
}
// SAVE CONTEXT:
[appDelegate saveContext];
Try this in the second example:
for (Picture *picture in Pictures) {
// Checks if inserted picture is already inside the table
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
self.managedObjectContext = appDelegate.managedObjectContext;
#try {
PictureData *pictureData = [NSEntityDescription insertNewObjectForEntityForName:[PicturesTable tableName]inManagedObjectContext:self.managedObjectContext];
//Insert Values
pictureData.url=picture.source;
pictureData.isNew=[NSNumber numberWithBool:YES];
pictureData.isPick=[NSNumber numberWithBool:NO];
pictureData.timeTaken=picture.time_taken;
pictureData.albumData=[self getActiveAlbum];
} #catch (NSException *exception) {
NSLog(#"Insert exception - %#", exception.description);
}
}
// SAVE CONTEXT:
[appDelegate saveContext];
To create a fetch request:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"YourEntityName"];
request.sortDescriptors = [NSSortDescriptor sortDescriptorWithKey:#"attributeName" ascending:YES];
request.predicate = [NSPredicate predicateWithFormat:#"attribute == %#", 13];
NSError *error = nil; //
NSArray *results = [appDelegate.managedObjectContext executeFetchRequest:request error:&error];
if (!results) {
NSLog(#"Error performing fetch request: %#", error.localizedDescription);
}
return ([results count] > 0); // There are more efficient ways of getting count from CoreData

Strange behavior in deleting core data contents

I use the following code to delete the coredata DB contents... I get the notification properly..But it seems the data are not deleted... I can't figure it out...
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityDescription inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *errors;
NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&errors];
NSLog(#"FinalArray:%#",[finalArray objectAtIndex:currentImageIndex]);
NSManagedObject *managedObject=[finalArray objectAtIndex:currentImageIndex];
NSLog(#"NSManagedObject:%#",managedObject);
for (int i=0;i<[items count];i++)
{
if ([managedObject isEqual:[items objectAtIndex:i]])
{
[self.managedObjectContext deleteObject:managedObject];
NSLog(#"gone");
}
}
NSNotificationCenter *nc=[NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(deleteCheck:) name:NSManagedObjectContextObjectsDidChangeNotification object:self.managedObjectContext];
NSLog(#"dffsdf%#",[errors description]);
if (self.managedObjectContext==nil)
{
NSLog(#"deleted");
}
Notification Func call
- (void)deleteCheck:(NSNotification *)notification
{
NSLog(#"CoreData got Deleted");
NSDictionary *userInfoDictionary = [notification userInfo];
NSSet *deletedObjects = [userInfoDictionary objectForKey:NSDeletedObjectsKey];
NSLog(#"DeletedObjects%#",deletedObjects);
}
Since NSManagedObjectContextObjectsDidChangeNotification notification called for each time when I tap the delete button... But no effects in DB... Suggestions Please
You need to save at the end.
NSError *error = nil;
[self.managedObjectContext save:&error];
You can use this simple delete method that i use, its work perfect :
-(void)deleteRecords{
NSFetchRequest * deleteRequest = [[[NSFetchRequest alloc] init] autorelease];
[deleteRequest setEntity:[NSEntityDescription entityForName:#"yourTabelName" inManagedObjectContext:context]];
[deleteRequest setIncludesPropertyValues:NO]; //only fetch the managedObjectID
NSError * error = nil;
NSArray * cars = [context executeFetchRequest:deleteRequest error:&error];
if ([cars count] !=0) {
//error handling goes here
for (NSManagedObject * car in cars) {
[context deleteObject:car];
}
NSError *saveError = nil;
[context save:&saveError];
// [tableView reloadData];
}
else {
NSLog(#"No Data To delete");
} }

Resources