Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Data not saved when using saveWithBlock: like methods #314

Closed
mac-cain13 opened this Issue · 11 comments

3 participants

@mac-cain13

When I save using saveWithBlock: or saveInBackgroundWithBlock:completion: I seems my data is not committed to disk. So when the App quits and starts again all my NSManagedObjects are gone. It feels like I'm missing something really basic, but I'm starting to pull my hair out by now.

Code that looses my objects after the App quits:

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *context) {
        for (NSDictionary *project in projects)
        {
            [WRPProject importFromObject:project inContext:context];
        }
}
completion:^{
        if (completion)
            completion();
}];

When these objects are fetched somewhat later on it seems that the objects still have temporary IDs:
(entity: WRPProject; id: 0x1d9982f0 <x-coredata:///WRPProject/t40288962-56B3-4287-A2B7-99D86866E3A0115> ; data: { [....] }

When I don't use the save blocks but perform everything on the main tread and save the context myself everything works fine. The objects are correctly persisted then.

My application:didFinishLaunchingWithOptions: uses [MagicalRecord setupAutoMigratingCoreDataStack]; to setup MagicalRecord and I'm using the latest version of MagicalRecord, also I'm nothing funky. Just this snipped in a clean project will reproduce the issue for me.

Hope someone can help hunt down this issue or point me in the right direction on how to fix this.

@tonyarnold
Owner

Hi @mac-cain13 — sorry to hear you're having trouble. What version of MagicalRecord are you using in your project?

@blackgold9
Collaborator
@mac-cain13

I'm using tag 2.0.8. I will try the develop branch to see if that fixes the issue an let you know if it works out!

@mac-cain13

Just updated MagicalRecord to the latest commit in de develop branch, but sadly it doesn't fix it. I'm using the exact same snippet from my first post to save new projects, at first everything seems to be okay. The default context is fetching a project list somewhere else in the App and everything is going great. But as soon as the App is terminated everything is gone, nothing is persisted to disk.

The output I get in the XCode debugging console:

Pigment[13614:907] +[NSManagedObjectContext(MagicalRecord) MR_contextWithStoreCoordinator:](0x3e166b04) -> Created <NSManagedObjectContext (0x1f546400): *** UNNAMED ***> on *** MAIN THREAD ***
Pigment[13614:907] +[NSManagedObjectContext(MagicalRecord) MR_setRootSavingContext:](0x3e166b04) Set Root Saving Context: <NSManagedObjectContext: 0x1f546400>
Pigment[13614:907] +[NSManagedObjectContext(MagicalRecord) MR_newMainQueueContext](0x3e166b04) Created Main Queue Context: <NSManagedObjectContext: 0x208429c0>
Pigment[13614:907] +[NSManagedObjectContext(MagicalRecord) MR_setDefaultContext:](0x3e166b04) Set Default Context: <NSManagedObjectContext: 0x208429c0>
Pigment[13614:4203] -[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:](0x20867520) -> Saving <NSManagedObjectContext (0x20867520): *** UNNAMED ***> on *** BACKGROUND THREAD ***
Pigment[13614:4203] -[NSManagedObjectContext(MagicalRecord) MR_contextWillSave:](0x20867520) Context UNNAMED is about to save. Obtaining permanent IDs for new 159 inserted objects
Pigment[13614:907] -[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:](0x208429c0) -> Saving <NSManagedObjectContext (0x208429c0): *** DEFAULT ***> on *** MAIN THREAD ***
Pigment[13614:907] -[NSManagedObjectContext(MagicalRecord) MR_contextWillSave:](0x208429c0) Context DEFAULT is about to save. Obtaining permanent IDs for new 159 inserted objects
Pigment[13614:4203] -[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:](0x1f546400) -> Saving <NSManagedObjectContext (0x1f546400): *** BACKGROUND SAVING (ROOT) ***> on *** BACKGROUND THREAD ***

I have really no idea where to look to solve this. No errors or warnings visible, everything seems working great. As far as I can see the only problem is that the data is not persisted to disk.

If I should share a example project with these issues please let me know, also any information I could give or tests I could run to verify everything is correct are very welcome. Also an example project of someone importing objects in a save block could be helpful to check if there is anything that I'm doing different, so if anyone can share something that would be awesome!

@blackgold9
Collaborator
@mac-cain13

So while prepping a demo project I couldn't reproduce the bug. That, and blackgold9's question about how I was querying, made me think maybe fetching did go wrong. Tests showed that findAll did find all projects! So everything is saved correctly, but fetching is going wrong.

I nailed it down to this:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (ANY timerentries.runningSince = NULL)"];
NSLog(@"%d", [WRPProject findAllWithPredicate:predicate].count);

timerentries is an optional to-many relationship on the WRPProject-entity. timerentries are not yet imported, so there are always 0 of them.

Now I can imagine that my predicate is invalid and will always evaluate to false when there are no timerentries, but that still doesn't explain my problem. Why are all the projects returned just after I run the import for the first time and after I terminate and launch the App again no projects are returned anymore?!

I'm very sorry for accusing the save methods incorrectly of my problems, I should have seen that the problem was in the fetching from the beginning, but I hope you can help me understand the inconsequent fetch results!

@mac-cain13

Okay, so I turns out my predicate was wrong and I was looking in the wrong place. I now changed the predicate to:
[NSPredicate predicateWithFormat:@"NOT (ANY timerentries.runningSince != nil)"];

This fixes the problem, the projects are now always fetched when the should be. I still don't understand why the predicate in my previous comment did return the (incorrect) results I wanted just after importing the objects, but was returning zero results after restarting the App. I would very much understand why this was happening.

Anyway, many thanks to blackgold9 and tonyarnold for the quick responses and good hints!

@mac-cain13 mac-cain13 closed this
@blackgold9
Collaborator

Well, lets look at the query.
To be clear, can you state, in english, what you're searching for?
"Find all projects that have at least one timeEntry with a null value for runningSince"?

@mac-cain13

To put it in context, a project has zero to many timerEntries. If the timerEntry has any date set at runningSince then "a timer is running" for that project. I want to fetch all projects except for the projects with "a running timer".

Formulated a but more formal: "Find all projects that have all their associated timerEntries with a null value for runningSince OR have no timerEntries at all"

I think that's what my last predicate does if I'm correct, the former version is wrong. That one will work more like your statement, but still, why is it first returning results and then returning nothing?

@mac-cain13

Ok, me again, same problem. Saving is not working, but now it's not the fetching that's going wrong. I have confirmed that a findAll doesn't return anything after terminating the App and that the objects are not in the SQLite database.
Note that as long as the App is not terminated everything seems fine and I do see the created entities appear in my fetches.

I'm creating a timerEntry that's associated with a project with this code:

[MagicalRecord saveWithBlock:^(NSManagedObjectContext *context) {
    WRPProject *project = [self inContext:context];
    WRPTimerEntry *timerentry = [WRPTimerEntry createInContext:context];
    timerentry.project = project;
}];

Is there anything wrong with the way I create/associate the entity?

The log when executing this code:

+[NSManagedObjectContext(MagicalRecord) MR_contextWithStoreCoordinator:](0x3e166b04) -> Created <NSManagedObjectContext (0x1c5a2550): *** UNNAMED ***> on *** MAIN THREAD ***
+[NSManagedObjectContext(MagicalRecord) MR_setRootSavingContext:](0x3e166b04) Set Root Saving Context: <NSManagedObjectContext: 0x1c5a2550>
+[NSManagedObjectContext(MagicalRecord) MR_newMainQueueContext](0x3e166b04) Created Main Queue Context: <NSManagedObjectContext: 0x1d076ac0>
+[NSManagedObjectContext(MagicalRecord) MR_setDefaultContext:](0x3e166b04) Set Default Context: <NSManagedObjectContext: 0x1d076ac0>
-[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:](0x1d0885c0) -> Saving <NSManagedObjectContext (0x1d0885c0): *** UNNAMED ***> on *** MAIN THREAD ***
-[NSManagedObjectContext(MagicalRecord) MR_contextWillSave:](0x1d0885c0) Context UNNAMED is about to save. Obtaining permanent IDs for new 1 inserted objects
-[NSManagedObjectContext(MagicalSaves) MR_saveWithErrorCallback:](0x1d0945e0) -> Saving <NSManagedObjectContext (0x1d0945e0): *** UNNAMED ***> on *** MAIN THREAD ***

When I create the timerEntry object without the save block everything is persisted correctly and I do see the objects after restarting the App:

WRPTimerEntry *timerentry = [WRPTimerEntry createEntity];
timerentry.project = self;
[[NSManagedObjectContext defaultContext] saveNestedContexts];

Hope anyone can point me in the right direction and/or point out anything that I do incorrectly. Let me know if a copy of the project would be handy, I'll check if I can perp a demo project with the same issue.

@mac-cain13 mac-cain13 reopened this
@mac-cain13 mac-cain13 referenced this issue from a commit
@mac-cain13 mac-cain13 Make saveWithBlock: save the nested contexts instead of just it's loc…
…alContext

This makes behavior consistent with the saveInBackground-methods and fixes issue #314
370e269
@mac-cain13

Ok, I spend some time hunting my issues down this weekend and I found that for now all my issues came down to the saveWithBlock: method not using the saveNestedContext method, where saveInBackgroundWithBlock: does. I made the above pull-request that makes the behavior consistent, I think it's a nice improvement and makes things easier to use!

Let me know what you think!

@mac-cain13 mac-cain13 closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.