I have a subclass of an NSArrayController linked to a core data model. In one of the methods I call
[self performSelectorInBackground:#selector(someLongExpensiveOperation:) withObject:obj];
which imports a ton of core data objects in the background.
The problem is, unless I manually add a fetch button on the interface and click it after the import operation completes, the array controller doesn't update itself to reflect the new data model. Any ideas on how to force array controller to update?
EDIT:
Turned out I also had some concurrency issues as NSManagedObjectContext is not suppose to be thread-safe. Had to account for that as well and then it started working.
Call prepareContent at the end of your someLongExpensiveOperation: method.
Related
What I want in short is:
Core Data that runs without blocking the main thread
entities with relationships
bindings in InterfaceBuilder
I have tried 'everything', but it turned out that there are too many difficulties with Core Data on two or more threads and two NSManagedObjectContexts and bindings and entities with relationships and so on. These threads can make CoreData very complicated.
Nevertheless I want to use Core Data and I want it to run in the background for good UI response.
So I wonder, is it possible to completely run everything related to Core Data in one separate thread, which is not the main thread?
I will send everyone 50 bucks, if I finally find a solution that works...
I used two NSManagedObjectContext instances to push some longer lasting data tasks onto another thread with Grand Central Dispatch.
As long as you be careful to merge this context with the one on the main thread used to fetch data then you should be able to get some performance that way.
I am not sure if this can help you, but perhaps you can create a new NSOperationQueue and add whatever core data functions you need to in the background. So in your class have a property that is NSOperationQueue, then in the -viewDidLoad methods, you create new one:
myOperationQueue = [NSOperationQueue new]; Whenever you want to do an operation you can add it to the queue and I believe that it will execute on a separate thread (self.myOperationQueue addOperation: someFunction) and if you want to interact with the main thread, then call assert([NSThread isMainThread]) in the beginning of your method call. I am using Core Data and threading in a different way, but from the second thread I am able to create a temp object that the NSManagedObject is created from.
Hey guys, I've got a subclass of an NSManagedObject. In awakeFromInsert and awakeFromFetch I'm calling an initialization method which, among other things, starts an NSTimer.
Now i need a place to invalidate the timer. However, dealloc, finalize, didTurnIntoFault, prepareForDeletion and willTurnIntoFault aren't getting called.
According to the documentation, these methods should all get called when the object is cleared from memory. None of them are, however all the data is saved in the persistent store. I'm puzzled as to why or how.
Is there anything i could be doing that could cause these methods to not get called during the objects life cycle?
Core data controls the lifetime of NSManagedObjects. It's not going to flush an object from memory by itself unless you ask it to. Looking at the documentation, there appear to be two ways:
sending refresh:mergeChanges: to the MOC causes the object to turn into a fault.
sending reset to the MOC causes it to reset itself as if it has just been created.
However, any of the above requires explicit action on your part, so you might as well add a method to the object to invalidate its timer and invoke that.
In fact, your problem probably indicates a design issue. An NSTimer is essentially a user interface event. It should probably be controlled by your MVC controller which sends a message to the model object (the NSManagedObject) to do the action.
So I've got an .xcdatamodel with about a dozen Entities defined and related to each other, with attributes and so on. So far I've been trying this in to a GUI using NSTableViews to display/enter data, and NSArrayControllers that I instantiate for each entity. This is all working great. They all tie in to the App Delegate's Managed Object Context (MOC)
But now I'm trying to programmatically access the data in these arrays, and I'm finding it obtuse to do so. After a lot of reading it looks like what I should REALLY do is go to the MOC to fetch data for a given Entity. I haven't worked through this yet, but ok.
What I don't understand though, is how to use Core Data when I'm NOT entering via NSTableView etc, and NOT using NSArrayControllers. Like if I wanted to totally handle some of my .xcdatamodel Entities in my project's Model packages (that don't touch a GUI). Do I need to still instantiate an NSArrayController so that I can "prepare content" of an Entity and have it be managed and initialized and all that? Or is there another way I can tie in with the MOC directly and add/remove/get the data for a given Entity?
What I'm saying is that I'm really unclear as to how to work with things unless I'm doing simple case View <-> NSArrayController and then Model <-> MOC
You should take a look at NSFetchRequest and the executeFetchRequest:error: method on NSManagedObjectContext.
Accessing the data via the array controller can be tricky. I've found that array controllers are generally designed to be used with UI elements. There are some tricks that the array controller will use to keep the UI snappy. It will fetch items on a background thread, for instance. Much of this can be configured, but you'll be better off accessing the info doing your own fetch.
The NSArrayController and related classes are intended to serve as off the shelf MVC design controllers. As such their only real function is to link the UI to the data model. If you need to deal with the model otherwise, you usually do so programmatically.
To access the model programmatically, you usually start with a fetch request (NSFetchRequest) to find the appropriate instances of certain entities. Then you would walk the entity relationships to find all other instances of the entities related to the fetched entities.
For example: Suppose you had a schedule type app. You entities are days and events. Each day has several events but each event has only one day.
If you want to check the events for a week, you would fetch the day objects whose date attribute feel in the 7 day range. Then you would ask each day object in turn for its related events.
The iOS does not yet support binding so check out the resources for using Core Data there to see how to manage all this manually.
I have a Core Data entity, which contains a relationship to another entity. Under certain circumstances, I need to delete the managed objects in the relationship, and at other times no action needs to be taken.
I have the Delete Rule on the entity is No Action because of this manual management.
The problem I have is, where is the best place to enforce these rules? I cannot see any suitable messages to override on NSManagedObject (something that might notify the object it has been deleted and should clear up its relationships).
I would rather not do it higher up in the application logic, because the entity objects can get deleted from array controllers and at different points in the applications, making it necessary to stuff relationship update code at all those levels.
In your NSManagedObject subclass, override the -prepareForDeletion method and handle the logic there.
UPDATE
You did not specify that you need a solution for retired versions. In that case you can handle it in the -save: call. Just before the save, grab the array of objects to be deleted, iterate over them and then call -prepareForDeletionon each object if it responds to it (using-respondsToSelector:`) and that gives you a future proof way to handle the deletions. You will of course need to check to see if you are running 10.6 or an earlier OS before running this code but that is fairly trivial to write up.
I have a ContactsViewController which -whenever a row is selected- MessageViewController is opened (using pushViewController). Both the ContactsViewController and the MessageViewController 'register' to receive DatastoreDelegate messages. The weird thing is it all works fine upon loading of my application, but once I navigate to the MessageViewController the delegate methods on my ContactsViewController don't get called anymore. Both these controllers should handle the [messageAdded:(Message *)message] method, but only the MessageViewController keeps receiving the messages after it's been opened once.
Does anyone have any idea on how to make this work?
In Cocoa, every object with a delegate has only one delegate (at any given time). That delegate is the only object that gets the delegate messages. There's no real concept of having "both objects registered to receive delegate messages." My suspicion here is that when you push the MessageViewController, it sets itself as the Datastore's delegate, and then the ContactsViewController never sees those messages again, because it doesn't set itself back.
I don't know how your code is structured, but you could simply hand-off the delegate every time the controllers change view so whichever is active is the current delegate.
In Cocoa, the Notification pattern (see NSNotificationCenter) is used when an object needs to "broadcast" information to multiple other objects. Delegates are really what they sound like: an object that another object optionally relies on to "partner with" it and provide key functionality. It's a more intimate relationship than a notification observer.