I am using Core Data on iOS and am having problems with NSFetchRequest.
If I create an NSFetchRequest like so:
NSFetchRequest* request = [ NSFetchRequest fetchRequestWithEntityName:#"Recipe"];
and then create instances of my Recipe entity, they appear in the results of the fetch request as expected. But once I save the database, and try to reload them then my fetch request returns no results.
The database saves successfully, with no errors, and using SQLite database browser I can see that all my entities have been saved in the underlying SQLite database. But they won't load...
is there an easy way to diagnose what is happening under the hood in a NSFetchRequest so I can find out why it won't load my entities?
// load recipes unsorted
NSFetchRequest* request = [ NSFetchRequest fetchRequestWithEntityName:#"Recipe"];
request.sortDescriptors = [[NSArray alloc] init];
NSFetchedResultsController* frc = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:self.recipeDatabase.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
// fetch results empty
NSError* error = nil;
[frc performFetch:&error];
Sorry.... I found my problem. I was not opening the UIManagedDocument when the state was UIDocumentStateClosed. Strange that everything else seems to work when operating on the documents managedObjectContext, even though the document is closed.
Related
I'm using Core Data with MagicalRecord and NSFetchedResultsController to display data in a table view. Everything works fine, now I have to change the underlying sqlite-file underneath which leads to a crash.
I'm creating the FRC the following way:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"CDPerson"];
NSSortDescriptor *sortByNameDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"lastName" ascending:YES];
request.sortDescriptors = #[sortByNameDescriptor];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[NSManagedObjectContext MR_contextForCurrentThread] sectionNameKeyPath:nil cacheName:nil];
_fetchedResultsController.delegate = self;
[_fetchedResultsController performFetch:nil];
When changing the sqlite-file, I'm doing:
[MagicalRecord cleanup];
// delete old sqlite file
// copy new sqlite file
[MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:SQLITE_FILENAME];
What do I have to do with my FRC to have it take the new storage? Only create a new one seems not enough as I get a crash in
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[[self tableView] endUpdates];
}
How can I achieve this?
EDIT
#question from flexaddicted: The error I'm getting in endUpdates is Assertion failure in -[UITableView _endCellAnimationsWithContext:]
#question from Exploring: you can imagine that I've got two sqlite files which I'm exchanging - both with the same tables, but different content. The FRC shows the content of the first file, now I'd like cleanUp MagicalRecord, let it point to the other store and 'refresh' the FRC.
You basically need to tear everything down and restart. Once you have recreated the Core Data stack you need to recreate the FRC with the new context and reloadData on the table view (you can't just reload some rows because the backing data has completely changed).
I am making chat-app and I looking the way to save and load from core data.
I save and load to it all user's history and it works good.
I am looking the way how can I load and save roster list
I am not sure here. I load user's info from web at startup by getting user's ids from roster list and request web service for that user's info. I want to save it to core data with roster list.
How can I set for every jUser (loaded from core data) his web server info? There are 2 problems here:
I can not get JUser from core data for its id
If I do 1. I can set to that user his web image and data to his core data's storied account. - I think it is not a good idea. How can I manage users here?
Some code:
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController == nil)
{
NSManagedObjectContext *moc = [[self appDelegate] managedObjectContext_roster];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"XMPPUserCoreDataStorageObject"
inManagedObjectContext: moc];
NSSortDescriptor *sd1 = [[NSSortDescriptor alloc] initWithKey:#"sectionNum" ascending:YES];
NSSortDescriptor *sd2 = [[NSSortDescriptor alloc] initWithKey:#"displayName" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects: sd1, sd2, nil];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:10];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:moc
sectionNameKeyPath:#"sectionNum"
cacheName:nil];
[_fetchedResultsController setDelegate:self];
NSError *error = nil;
if (![_fetchedResultsController performFetch:&error])
{
//DDLogError(#"Error performing fetch: %#", error);
}
}
return _fetchedResultsController;
}
What you are showing above is for keeping track/getting the info that is populated with a request to the XMPP server for it's roster (be it an autoFetch or a manual fetch using the XMPPRoster 'fetchRoster' method (assuming you have set the CoreData way of storing your roster data, not memory).
Once the response to the roster fetch is returned (iq result), the delegates within the XMPPRoster instance will capture and put in place with the given storage option. If the server you are using conforms to the XMPP rfc, then this should happen pretty automatically on the return.
For example - in XMPPRoster.didReceiveIQ() - you can see the call to '[xmppStorage handleRosterItem:item xmppStream:xmppStream]'. This is where the processed
You can extend the storage here (XMPPRosterCoreDataStorage and XMPPUserCoreDataStorage for example) and set in place to add additional information to the entity. For example here - XMPPUserCoreDataStorage has an over-ride '(void)didUpdateWithItem:(NSXMLElement *)item' that you can define attributes in to point to another entity. Here you would copy the existing data model and add your own attributes to it - using the over-ride above to enter them.
As for the messages, depends on if a MUC or a 1:1 - but they use different managed objects as well. XEP-0045 is what is storing the MUC messages that you can try to attach to for the users last message in there - as well as XMPPMessageArchiving for the 1:1 storage, but you would still need support from the server on this if you need to persist the capturing of another users last message - unless you are only talking about per session (which you could then store locally for display).
Now I have a Core Data entity "AAA", and I use a method to fetch its result:
- (AAA *)result{
NSEntityDescription *Entity = [NSEntityDescription entityForName:#"AAA" inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
[fetchRequest setEntity:aaaEntity];
NSError *error = nil;
NSArray *fetchRequestResult = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
AAA *aaa = fetchRequestResult.lastObject;
return aaa;
}
Then I use Xcode Instruments to check the memory status, it shows:
VM:Core Data Object IDs 4.02MB(Live Bytes)
Is the entity still live in the memory?
First of all I would start to say that you should not be worried about memory when you deal with Core Data. Under the hood the framework manages stuff for you. When you retrieve an object, Core Data populate a cache where data are stored in. In this way, further fetches will not hit the disk but the cache only.
Anyway, you could rely on two different APIs to control memory footprint. The first one is [context reset]. This will clear the entire object graph (that belongs to a specific context) as if you had just created it.
The second one is [context refreshObject:yourManagedObject mergeChanges:NO]. It allows releasing an object, or turning it into a fault.
Hope it helps.
The code below does not delete the entity. The "delete was successful" message appears on the console so the entity is found. All other operations I use succeed.
I am using RestKit 0.20.
NSManagedObjectContext *context = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext;
NSError *error = nil;
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity: [NSEntityDescription entityForName:#"Auction" inManagedObjectContext:context]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"AuctionID = %d", auctionID];
[fetchRequest setPredicate:predicate];
NSArray *result = [context executeFetchRequest:fetchRequest error:&error];
if(result.count) {
Auction *block = result[0];
[context deleteObject:block];
BOOL status = [context save:&error];
if (status == NO) {
NSLog(#"delete falied for AuctionID:%d, error: %#", auctionID, error);
}
else {
[context processPendingChanges];
NSLog(#"delete was successful for AuctionID:%d", auctionID);
}
}
Why might this delete operation not succeed and what is the solution to making it work.
I found this solution :
In fact, you have to fetch datas from the persistentstore and not the current created managed context :
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"MyModel"];
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"id" ascending:NO];
fetchRequest.sortDescriptors = #[descriptor];
// Setup fetched results
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
// AND TO DELETE A MODEL :
[[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext deleteObject:myobject];
i am doing the same thing and have nearly same code.
In my code also, i get delete done and saved....
But, its not deleted when i am checking DB.
the problem is not with simulator... SURE bcz i am getting same problem on device also.
there is something called child context, it might be the cause...Check these links http://restkit.org/api/0.20.0-dev/Classes/RKManagedObjectRequestOperation.html#//api/name/managedObjectContext
RestKit 0.20 — What is the preferred way to create a new NSManagedObject?
. If you found solution pls share here
#Sumitiscreative I ran into the same issue today. What if found was that normally using Core Data you have to use
[NSManagedObject save:]
for it to store the changes. I dug through Restkit a bit and found this
[[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext deleteObject:(NSManagedObject *)];
[[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext saveToPersistantStore:(NSError *)];
Calling this after the above delete method is working to remove the object out of the DB.
**Edit - Also I would have just made this a comment but i don't have the option
#Lance
Hey, pls update your restkit with the latest version.
As now, this works in the latest version , if your server related configuration is correct. and if you get success codes for your delete request from server. Then, restkit automatically deletes the data.
If you need to delete any data externally then, you can use persistentStoreManagedObjectContext and after deleting, save it.
Also, if you want to check at your end that whether its correctly deleting via restkit or not. what you can do is ...
make delete request, after success
check with same id, if item exists. (just for help)
I am having a strange issue with MagicalRecord. Deletes will not persist. When I delete, NSFetchedResultsControllerDelegate correctly sees that the object has been deleted. However, if I close and reopen the app, the entity reappears.
The code I am using to delete the entity is:
ActivityType *activityType = [_fetchedResultsController objectAtIndexPath:indexPath];
[activityType deleteInContext:[NSManagedObjectContext MR_defaultContext]];
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
The code I am using for setting up the NSFetchedResultsController is:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"ActivityType" inManagedObjectContext:[NSManagedObjectContext defaultContext]];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:#"name" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[NSManagedObjectContext defaultContext] sectionNameKeyPath:nil
cacheName:#"activityTypes"];
_fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
Based on other SO posts, I also tried to use [NSManagedObjectContext rootSavingContext] in both the setup and deletion (but to no avail).
I've been through hell and back with core data, and I learned a few things. I'm tired so I'll just write a quick summary.
When you delete an entity, core data may reject it due to your deletion rules. The reason why my deletes didn't go through is because it needed to be cascade but it was nullify. I think it has to do with somehow leaving entities abandoned. I don't know why that would be cause to prevent deletion, but that's what fixed it in my case. The way I discovered it was through log, I saw some statement about a referenced dependent entity, and I realized that delete rules will apply.
When the log says something about a serious error and a listener, check the FRC code. Since this is the listener, your culprit code will be here somewhere. In my case, I disabled [tableview beginUpdates] and [tableview endupdates]. The FRC actually needs this (I thought it was optional). Otherwise, you get some error about inconsistency and managedobjectcontextlistener and how rows need to be added or deleted etc. etc.
when you delete, it may actually get saved into the memory local context, but may not get saved to the persistent store. this means that the FRC delegate code will see the changes, but it may not get saved. also, the memory store may not do the deletion rules checks as it passed mine. but the persistent store will do the checks. gotta look into this more.