Say I get an object through a DbContext and then close that context. Later on I want to get some children of this object and I open a new context. Are there any problems with reattaching the object to the new context that I should be aware of?
If you detach the object from the first context before you dispose it you should have no trouble. If you don't do that you can in some circumstances receive error that object is already tracked by another context and in such case it is impossible to attach the object to the new context or detach it from the old context (because it is already disposed).
Beware that detaching breaks all relationships. If you want to avoid detaching at all don't use dynamic proxies created by EF (lazy loading and dynamic change tracking).
Related
I have a singleton class that performs a number of tasks:
Registers a listener to receive location updates.
Unregisters listener.
Triggers a API call if the listener method gets called.
I want to draw a state machine diagram for the class but was wondering whether it is correct to do so for a singleton.
Why should a singleton instance be any different from any other instance? The singleton pattern simply makes the constructor private so there can only be one instance, obtained through a getInstance() operation.
You should consider modeling the class in UML as an "active class" to declare that the class has autonomous behavior that "never" ends. As explained in the UML 2.5 spec:
An active object is an object that, as a direct consequence of its creation, commences to execute its classifierBehavior, and does not cease until either the complete Behavior is executed or the object is terminated by some external object. (This is sometimes referred to as “the object having its own thread of control.”) The points at which an active object responds to communications from other objects is determined solely by the Behavior of the active object and not by the invoking object. If the classifierBehavior of an active object completes, the object is terminated.
Sure you can do that. The one ain't got to do anything with the other. Singleton means, that there is just a single instance. Now the state machine can respect or ignore this fact depending on what you want to achieve.
My setup is one main moc with a persistent store coordinator and an SQLite persistent store.
I'm trying to asynchronously (and potentially concurrently) retrieve data from a server, parse it into CoreData objects and then save those new objects into the persistent store and have them available in the main moc.
So I tried 2 approaches:
Each time I go fetch from the server, I do so inside a GCD block (concurrent global queue with normal priority) where I create a new context with NSConfinementConcurrencyType which shares the presistent store coordinator with the main moc. When I'm done parsing the JSON and have the new managed objects, I save this "local" context which sends NSManagedObjectContextDidSaveNotification to the main context, which in turn does the merge.
Each time I go fetch from the server, I don't dispatch a GCD block but rather I create a child context with NSPrivateQueueConcurrencyType. This context has the main context as parent but no store coordinator. Then I call -performBlock: on the child context, where I parse the JSON into CoreData and tell the child context to save, which in turn triggers the main context to merge.
Now, what I noticed is that approach 1 triggers what seems to be an exception but otherwise works. I say this because if I set a generic exception breakpoint to break on any Objective-C throw, it always halts when a local-to-GCD-block context saves. It's always a thread other than the main one, and even though it looks like an exception, the save error out param is nil after the save. What's more, the objects in the main context seem consistent (since I know the data they are supposed to have). And calling -savedChanges: on any of these objects (after the main context merged) returns no values, which is what I'd expect.
For the second approach, I don't get the exception breakpoint halting anywhere (which seems good), but... while the right data is in the right objects after the main context merge, calling -changedValues returns all the values (attributes and/or relationships) that were populated in the child context. This I would not expect, since in theory, I did save and the save should have been pushed up to the main context and the main context did merge.
So I'm confused.
I need -changedValues: to only return values if these were changed after the master context saved, since I use these values to figure out that my app has changed a mo's state and the new state needs to be pushed back to the server.
I'd really appreciate any help / pointers with either approach 1 or 2.
A child context saves into its parent. That is, once the child has saved its changes, these changes appear in the parent, and within the parent they are flagged as changed because the parent still needs to change these.
I'd generally discourage use of parent-child context setups, because they have a lot of drawbacks. More info in the Working with Multiple Contexts chapter in our book.
I'm using performBlock on my NSManagedObjectContexts so that my changes happen on the right queue for the given context. My question is - if I'm making a lot of changes and calling methods from within performBlock - is there an easy way to ensure that I use objects from the proper context.
Example:
I have an activeAccount iVar ( created on the Main Queue ) that is a NSMangedObject for the current account in the application. I have some instance methods that use the activeAccount object to perform certain tasks - getting data, setting data. So my question is if I am doing something on a background NSManagedObjectContext and I call one of these shared methods - is there a pattern I can use so that in these methods I know to either use the current activeAccount iVar or get a new one. Also, if I needed to do something that requires a NSManagedObjectContext - how do I know which one to get/use.
One method I have for knowing which NSManagedObjectContext to use is I have a method that checks if it is running on the current thread - it then knows to return the main thread's context or the background thread's context. Also, if I'm on the background thread, am I allowed to read the Object ID of the activeAccount that lives on the main thread so that I can get a copy of it on the background thread? Thanks in advance.
Brian,
Thread confinement can be a tricky proposition to maintain. The key thing you need to maintain is using objects in their proper MOC. As every managed object maintains a link to both its host MOC and its object ID, this is really easy to ensure. For example:
NSManagedObjectContext *newMOC = NSManagedObjectContext.new;
newMOC.persistentStoreCoordinator = oldActiveAccount.managedObjectContext.persistentStoreCoordinator;
ActiveAccount *newActiveAccount = [newMOC objectWithID: oldActiveAccount.objectID];
Now every instance you access from newActiveAccount is created in the newMOC and is, hence, thread confined to that MOC. objectIDs are persistent. The -persistentStoreCoordinator is rarely, if ever, changed on the mainMOC. Hence, the above code is properly confined. There are issues with the above technique if the source MOC is transient. Hence, I cannot guarantee the above code works with respect to two background MOCs.
Andrew
I have to ask first, why are you having so many contexts in use at the same time?
I use one for background operations and one for main thread. If I need to create another one for discardable changes, I'll just create it and pass it on, so now my self.managedObjectContext points to the draft context. I will never let my managed objects to live in a scope where they could access a multitude of contexts.
It is not entirely clear if you are writing for iOS or OSX, but with iOS for example:
If I need to push a new view controller into navigation stack I will initialize my destination view controller's managedObjectContext ivar as well as any NSManagedObject subclass instances. Since in -prepareForSegue: I know whether I'll create a draft context or just pass on my current one, I also know whether I need to initialize those managed object instances by referencing them by their IDs from newly created context or I can just pass them on.
Now inside my view controller I can take it for granted that my managed objects are always tied to the self.managedObjectContext.
What is a good way to think about this? Are handles lost?
glCreateProgram()?
glCreateShader()?
glGenTextures()?
glGenBuffers()?
Im wondering if I am doing what's necessary (or doing too much and leaking memory)
How do you lose a context? The OpenGL context will exist until you destroy it (or the window/HDC).
However, all OpenGL objects are bound to the context(s) that they are created in. If you destroy the context, all objects are destroyed as well (unless you have shared objects with another context. In which case, only the sharable objects will remain). So you must reload them.
For example, do I call all 3 function calls: glCreateProgram() glAttachShader() glLinkProgram() or just the last two?
If the OpenGL context is destroyed, you must call whatever OpenGL functions you need to recreate your objects. Any OpenGL objects that you got from the old context are gone. They are invalid. They are deleted pointers, and using deleted pointers is always wrong.
A new OpenGL context is new. So you must create your objects as though it were a new context. Because it is.
It seems that all Guice's out-of-the-box Scope implementations are inherently Thread-based (or ignore Threads entirely):
Scopes.SINGLETON and Scopes.NO_SCOPE ignore Threads and are the edge cases: global scope and no scope.
ServletScopes.REQUEST and ServletScopes.SESSION ultimately depend on retrieving scoped objects from a ThreadLocal<Context>. The retrieved Context holds a reference to the HttpServletRequest that holds a reference to the scoped objects stored as named attributes (where name is derived from com.google.inject.Key).
Class SimpleScope from the custom scope Guice wiki also provides a per-Thread implementation using a ThreadLocal<Map<Key<?>, Object>> member variable.
With that preamble, my question is this: how does one go about creating a non-Thread-based Scope? It seems that something that I can use to look up a Map<Key<?>, Object> is missing, as the only things passed in to Scope.scope() are a Key<T> and a Provider<T>.
Thanks in advance for your time.
It's a bit unclear what you want - you don't want scopes that are based on threads, and you don't want scopes that ignore threads.
But yes, scopes are intended to manage the lifecycle of an object and say when an instance should be reused. So really you're asking "what are the other possibilities for re-using an instance beyond 'always use the same instance', 'never use the same instance', and 'use an instance depending on the execution environment of the current thread'?"
Here's what comes to mind:
Use the same instance for a fixed amount of time. The example here would be of a configuration file that's reloaded and reparsed every ten minutes.
Perform some network call to query whether a given object should be re-used (maybe it's a fast call to determine whether we need to reconstruct the object, but the call for reconstructing the object is slow)
Re-use the same object until some outside call comes in telling us to reload
Re-use the same object per thread, but not with a scope that's explicitly entered and left like the servlet scopes. (So one instance per thread)
A "this thread and child threads" scope that is based on an InheritableThreadLocal, not a plain ThreadLocal.
Related to that, a Scope and a threadpool-based ExecutorService that work togehter so that instances are shared between a thread and jobs it submits for background execution.
Pull instances out of a pool; this is tricky, since we'd need a good way to return objects to the pool when finished. (Maybe you could combine this idea with something like the request scope, so that objects can be returned to the pool when the request ends)
A scope that composes two or more other scopes, so for example we could get a configuration object that is re-read every 10 minutes except that the same instance is used through the lifetime of a given request.