Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quirks with doing simple task of creating object and then using on main thread as soon as possible #2

Closed
Shuab opened this issue Apr 9, 2016 · 4 comments

Comments

@Shuab
Copy link

Shuab commented Apr 9, 2016

Either need to make an easier way to do this and/or a related example in the README or the example project. And my first solution of re-querying the object by ID is both inefficient and getting away from the design goals of the framework, I think.

The code from your comment in #1 was the first thing I had tried when I ran into it:

Cd.transact {
    let obj = try! Cd.create(MyObj.self)
    obj.prop = 3
    try! Cd.commit()
    dispatch_async(dispatch_get_main_queue()) {
        let myMainThreadObj = Cd.useInCurrentContext(obj)!
        // Do something with object
    }
}

But I run into this inside of useInCurrentContext():

        guard let originalContext = object.managedObjectContext else {
            Cd.raise("You cannot transfer an object without a existing context.  This object may be transient, or it's original context has been destroyed.")
        }

I assume because the temporary context for the transaction is gone and so the object has no MOC.

I got it to work using a synchronous dispatch to main - what do you think about potentially keeping that temporary context for the transaction around in the case of heavy-ish work done in the synchronous code on main? If that doesn't seem bad, then I think that's the best route to go. My first concern was with stuff like a race condition with the restoring of existingContext and existingNoCommit, but I guess those are protected because that thread is blocked until the newWriteContext.preformBlockAndWait is done. This is what I'm using now:

Cd.transact {
    let obj = try! Cd.create(MyObj.self)
    obj.prop = 3
    try! Cd.commit()
    dispatch_sync(dispatch_get_main_queue()) { // <-- SYNCHRONOUS
        let myMainThreadObj = Cd.useInCurrentContext(obj)!
        // Do something with object
    }
}
@jmfieldman
Copy link
Owner

I think I might be too heavy-handed with the guard against transferring w/o an existing context. If the NSManagedObject has a permanent objectID I should let it pass as well. I think this would make the async version work, but will test later.

In fact, I should probably be checking against temporary IDs, but I think the check on originalContext.hasChanges is doing that implicitly (since any context w/ an object that isn't saved will have changes..)

@jmfieldman
Copy link
Owner

Ok, 0.11.1 is up with the change to context-checking on useInCurrentContext. Now any object with a persistent ID should be useable; still relying on the hasChanges flag to catch transient objects though.

Also added some more content to the readme about this, as well as notes on the update handler.

@jmfieldman
Copy link
Owner

(btw, added code to the basic example's handleAdd function to show the object being dispatched and having an updateHandler assigned to it)

@Shuab
Copy link
Author

Shuab commented Apr 9, 2016

Great, looks good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants