Create NSManagedObject in one view and save in another - iphone

I want to know what the best way to implement a certain functionality. I have a message composer view where the user creates a NSManagedObject MessageObject. I also have a class ObjectHelper which has a global instance initialized.
I have a background (private queue) NSManagedObjectContext create a MessageObject immediately when the user enters the compose view. The catch here is that the ObjectHelper (not the ComposerViewController) is the owner of this new object - it has a property variable with a strong reference:
ObjectHelper.h:
#property(nonatomic, strong) MessageObject *newObject;
Then, back in my ComposeViewController, I set a timer to save the object to disk every 30 seconds (this saves a draft, like auto-save, in case the user gets interrupted somehow or the application crashes, the data doesn't get wiped out).
Then, when the user hits the save button, I want to make sure I do as little work as possible on the main thread so that the dismiss modal view animation is smooth, and function returns to the main view controller quickly. So what I do is create an NSDictionary with all the values of the message object, call [globalObjectHelperInstance updateNewObjectInstanceWithDictionary:]
What this does is update the newObject instance that was already created in the beginning of the compose view with the values from the dictionary, and does it in the background thread.
Then I dismiss the modal.
I have a few questions here (please answer whatever you can):
Is there a better way to implement "draft" saving functionality rather than creating a property instance in the ObjectHelper? (the reason I create a property instance in an outside class other than the ComposeController is because the view controller dismisses while background work is being done on the object, so I'm afraid it will disappear from memory if I make it an instance variable.)
Should the property reference be a weak or strong? I know an NSManagedObjectContext is not guaranteed to retain its objects, unless (I think) these objects have pending, unsaved changes.
For some reason, calling [backgroundMOC obtainPermanentIDsForObjects:self.newObject error:&error]in the [globalObjectHelperInstance updateNewObjectInstanceWithDictionary:] before saving causes a EXC_BAD_ACCESS crash. I'm guessing this has something to do with the way I'm managing memory in my situation.

Your way to save draft seems very fine to me.
Another option is not to keep the property reference in any object and fetch the draft object by some key, update it and save it again. This might make sense in case you save something rarely or have something very big, but your current approach seems much more suited.
The reference should be strong. You want it to be present at all times while you want to update it, and you require its existence, so that qualifies for strong. In case of weak reference the object might get deleted. The object in the database on disk will remain, but your in-memory representation will be removed, you wouldn't want that—to update a nil reference.
I don't see any reason why this might cause any memory overuse or leaks, it's just one object and this isn't a case to be afraid of circular references.
As for your crash, it is hard for me to tell, but maybe you should obtain ID in the main thread's MOC at first, and then use it in the background MOC? Also, since it is easier to transfer NSDictionary between thread boundaries rather than an NSManagedObject, maybe you should keep your draft in the background MOC all the time?
Your code in the updateNewObjectInstanceWithDictionary: would then call a GCD block on the background queue and pass it the dictionary to save.

Related

Is setting a pointer from a singleton to a viewController and updating GUI a violation of MVC

I'd like to ask a theoretical question pertaining to good code practice and the MVC model, Here is the case:
The design contains a RootViewController and a singleton class. The singleton acts as a controller with a timer objects that should be available throughout the app. The timer object consists of a UISwitch and an NSTimer, they are both owned by the singleton controller so the UISwitch can be added to new viewControllers on demand and the timer object is accessible throughout the app.
In order to update the RootViewController's screen with the current timer's count i created a pointer in the singleton to the RootViewController and have the RootViewController set itself to that pointer, similar to [singeltonOBject setDelegate:self].
Using this design the UILabel of the RootViewController can be accessed and updated from the singleton when the timer ticks. I chose to do that because i didn't have time to implement a regular delegate.
Note that the RootViewController is owned by the AppDelegate and the the singleton class is obviously NOT owned by the RootViewController. Therefore there is no retain cycle.
Question:
Is the setting of a pointer from the singleton to the RootViewController and updating the UILable from the singleton controller a violation of good coding practice, are there any basic principles that are not fulfilled?
Thanks for your answer!
Problem
Generally when something doesn't feel quite right, thats because it's not.
While your code will work it is not going to be easy to maintain in the future and is liable to breaking. Even if you never plan on looking at this code again, it is always good to practice good coding conventions.
I recommend reading The Pragmatic Programmer which contains lots of tips for programmers on how to write better code. One of those tips is Minimize Coupling Between Modules. Right now your RootViewController knows about your Singleton and your Singleton knows about your RootViewController so they are both coupled to each other. In the future, when you change one you are likely to have to change the other one as well.
What if you want to add another label?
You will have to add the label in the RootViewController and then change your singleton to update that label as well.
What if you remove the label altogether? Lets say you go back to this in a years time and remove the label, suddenly there is another class that is not compiling and you might not remember why. You have broken code in a completely separate part of your application.
As for following MVC, this is in violation of that. Your view is being modified by something separate. If MVC is setup correctly you should be able to put on as many views as you want without having to change any code that is controlling data, in this case your timer.
Now as for memory management, your RootViewController is now being retained by this Singleton. Singleton's exist for the entire life of an application. You are right that you do not technically have a retain cycle however your RootViewController will now never be deallocated. In most applications this does not matter as the RootViewController always remains at the bottom of the stack but it is a coincidence and thus cannot be reliably programmed on. This is actually another tip from The Pragmatic Programmer, Don’t Program by Coincidence.
Solution
A better solution would be to use a notifications if you really need a global timer like you say (another story is that your global timer singleton does not sound like a good idea). Whenever you were updating your label from within your singleton you can fire a notification instead. Your RootViewController will receive this notification and can update its label. You can pass data in a notification if needs be. Now in the future if you make a change to the view and want to update something else you only need to change code in one location (The RootViewController).

What could cause mergeChangesFromContextDidSaveNotification not to merge/invalidate objects that have been updated?

[EDIT: simplified version of the question]
mainMOC is the primary managed object context
editorMOC is a managed object context created in editorViewController with an undo manager so the user can edit a single managed object
after editorMOC saves, mainMOC refreshes the updated managed object in the notification handler for NSManagedObjectContextDidSaveNotification
In the save handler, if I use [mainMOC refreshObject:obj mergeChanges:YES] the updates to the object are not reflected in mainMOC post-refresh. If I use [mainMOC refreshObject:obj mergeChanges:NO] the object is invalidated and at the next fault the changes are reflected in the data loaded from the store.
QUESTION: Why would the object not reflect the update when mergeChanges:YES is specified?
[ORIGINAL QUESTION]
I have a core data based app with multiple managed object contexts. The app is complicated and proprietary so I cannot simply share code directly from the app. I have created a simple test app in an attempt to reproduce my issue but the test app doesn't exhibit the problem. I have not been able to find a logical difference between the implementations. I apologize for not posting sample code, I believe I explained the implementation well below. If something is not clear, please ask in the comments and I will do my best to clarify.
Here's my situation. Everything described below is running on the main thread.
The app has a primary managed object context called mainMOC that is accessed on the main thread and used with NSFetchedResultsControllers to display data in various table views.
I have a view controller called EditorViewController that allows editing of an existing object of a particular entity. This view controller creates it's own managed object context called editorMOC using the same persistent store coordinator with an undo manager so changes can be rolled back or saved when dismissing the editor.
EditorViewController is observing the NSManagedObjectContextDidSaveNotification. When this notification occurs, the notification handler calls [_mainMOC mergeChangesFromContextDidSaveNotification:notification] to merge the changes from editorMOC into mainMOC.
The table view controller that uses an NSFetchedResultsController is handling the controller delegate messages.
I have added NSLog output to look at look at what happens in all of the above steps and I have verified the following:
I can see that the object is modified and saved in the editor.
I can see that the NSManagedObjectContextDidSaveNotification is called and that the updated object is included.
I can see that the fetched results controller is receiving the controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: protocol message.
I can see that mainMOC is not reflecting the updates and that the updated object has not been invalidated by mergeChangesFromContextDidSaveNotification:.
If I quit and relaunch the app, the updates were committed
For reference, both my main app and test app implement the above functionality but the test app shows the updates merged correctly and the main app does not.
I am looking for suggestions on what would cause mergeChangesFromContextDidSaveNotification: not to successfully merge and/or invalidate the updated object.
Thanks!
The fetched results controller does not receive the controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: delegate message. Instead it sends it to the delegate in response to a change in the context. If that delegate message is being sent and does contain the proper object, then the main context is aware of the changes.
If so, then your error is most likely in the the code interfacing the fetched results controller and the tableview. Something is preventing the object from appearing correctly.
The issue I had that caused mergeChangesFromContextDidSaveNotification not to work was I created a new NSPersistentStoreCoordinator for each new NSManagedObjectContext. When I shared NSPersistentStoreCoordinator between all MOCs, mergeChangesFromContextDidSaveNotification works perfectly. Also, make sure mergeChangesFromContextDidSaveNotification is called on the thread that owns the MOC.
From the research I did, it is safe to share NSPersistentStoreCoordinator between threads for use with NSManagedObjectContext. NSManagedObjectContext will lock the persistent store as necessary.
One possible answer: you have a third MOC you didn't know was there / forgot about. (This happened to me.)
I had
mainMOC
editorMOC
viewerMOC which came about by accidentally misguided subclassing - it was supposed to be looking at the main MOC, but instead was creating its own and looking at a frozen state. The "checking for edits" relationship was going the other direction, because it was expected to be the "editor" in this scenario.
the notification is correctly invoking the callback, and the data is being merged correctly into the main MOC (which i could tell because the data was correct on relaunch)
note: refreshObject:mergeChanges: is not needed. it's something i tried, too, when it wasn't working, but the merge of the notification should take care of all the objects for you.
- (void)twinStackUpdated:(NSNotification *)notification {
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
not sure that this was your problem, but it might be someones, so there it is.
In an effort to accept something even though I don't have a definitive solution, here's what I've done to address this and the problem seems to be resolved.
I believe this was a cache issue with NSFetchedResultsController. I've since simplified this code and made sure that each NSFetchedResultsController uses it's own cache. I've been able to remove the call to 'refreshObject' and things seem to be working correctly.

Bad-practice to retain 'self'?

I have a simple query that I'd like cleared up by someone... Is it bad-practice to retain self?
I have a server request object that I'd like to make. I'd like to be able to use it in the following fashion:
ARequest *request = [ARequest request: someParam];
request.delegate = self;
[request begin];
In order for the object not to self destruct as soon as the autorelease pool is drained, I imagine I need to call a retain in it's init method and then a release once the server response has been received, processed and delivered to it's delegate.
However, something is raising a warning bell in my head with this approach. Better ways to do it?
There is nothing wrong with retaining self, as long as you release it at some well-defined point in accordance with normal memory management protocol. If an object requires itself to exist until some condition is met, it should take responsibility for that, in the same way as it does for any other object it requires to continue existing.
Introducing otherwise extraneous manager objects or foisting the responsibility off on the object’s owner for superstitious reasons would be the real anti-pattern here.
(The equivalent approach in garbage-collected code would be for the object to exclude itself from garbage collection while results are pending, or root it through a collection of some sort if you dislike that idea.)
It's not unheard-of, but it is somewhat uncommon. The main way I've seen it used (and used it myself) is when you're dealing with some sort of semi-synchronous object (by semi-synchronous I mean that it does not block the main thread, but it also does not execute on a background thread; an NSURLConnection would fit this bill). For example, I wrote a subclass of NSWindowController that was specifically for displaying a window as a sheet and for invoking some certain delegate callbacks. Basically, you'd alloc/init a new sheet controller and invoke beginSheetForWindow:. This would run the sheet semi-synchronously, and then invoke an appropriate callback when the sheet was dismissed.
Since the invoking object doesn't necessarily "own" the sheet (think of it as a Mac version of a modal view controller on iOS), the sheet controller does [self retain] immediately before showing the sheet, and [self release] immediately after cleaning up and invoking callbacks. The purpose behind this was to ensure that the controller object would stick around until the sheet was done. (The sheet, IIRC, was retained by the runloop, but I also needed the controller to stick around)
Like I said, it's very rare to come across a situation where you would want to [self retain], but it's not impossible. However, as a general rule of thumb, if you think that you need to [self retain], you may want to think again.
Easiest way to do this would be to create an iVar for your request, retain the request when you start it and release it when the last delegate method is called.
Is ARequest a class you created? Does it create a new thread to asynchronously submit the request?
I once did the same thing as you. I wrote a Category-Method on NSString to send it it to a server, that will print it. In the Category-Method I had to call [self retain], so that the callback methods could be a NSString-Categroy-Method to.
I felt so bad about it, that I rewrote everything to use a Singleton, that is accessed by the Category-Method. So the Singleton will retain the string as long as necessary.

awakeFromNib opposite?

Is there a reverse of awakeFromNib, a method called when the nib is closed? I know an application delegates receive a notification the the application will terminate, but was wondering if there was to save some state information on a simple NSObject.
Not really, but mostly because it generally doesn't make sense. By the time an individual object is being deallocated, it is generally too late to do anything meaningful.
For saving state, you would generally want to do so periodically, often triggered by some user action (user just entered a bunch of data.... good time to save, user transitioned to a new part of the app.... save). Only saving as the app is terminated or as a window is closed (or, in your case, as a particular screen is exited) is a recipe for data loss.
For an NSObject instance its dealloc routine will get called as the object is going away -- you should have a chance there to save off any state you need to before destroying self and super.

What is the proper usage of NSManagedObjectContexts when editing/creating new objects (iPhone)?

I am trying to figure out the proper way to use NSManagedObjectContexts when you are viewing, editing, and creating NSManagedObjects. I feel that the documentation and examples have explained how to use them in the most basic cases, but I'm not sure what the proper methods are in a slightly more complex setup.
The setup:
3 main screens: a list of objects, an edit object screen, and a new object screen.
Another thread is downloading objects to add to the list in the background.
The requirements:
The list screen uses a MOC and an NSFetchedResultsController to get all it's objects.
The edit and new object screens use MOCs to save/delete objects AND use NSFetchedResultsControllers for relationships.
The downloaded objects need a MOC to save it's objects into Core Data (on the main thread).
The questions:
How many MOCs do I need?
How should I manipulate these MOCs?
Possible Answers:
Have one "View" MOC that is never edited and is used in the list screen. Use separate MOCs for the edit, new object screens, and the downloads. When these MOCs save, merge the changes back to the "View" MOC. This way any changes don't affect the "View" MOC until they are saved. This is what I have been doing; it doesn't seem to be working as smoothly as I hoped. There is a disconnect between the editing and the viewing and instead of being able to check on things when I know they might of changed I have to wait for NSFetchedResultsController delegate methods to finish and check on every possible thing that might have changed. It also makes it difficult if I need to change some data in the list view.
Have one MOC for everything. This is what I first tried but wasn't sure of how to deal with the editing and creating. Now that I understand a bit more, I guess I could just edit the object or create an object and rollBack on cancel. On cimgf, I saw a post that seemed similar which said to create an undoGrouping around the edit/create and undo on cancel. Then I guess I could use a separate MOC on the downloaded objects because it might finish and save while the user is editing in the main MOC.
Anyways, the point is that I don't know what the proper method is. Can you help me?
Example Disconnect for First Possible Answer
Created an object (1) in the edit moc. Saved. Merged with view moc by notification.
Created a new moc because I am downloading objects in the background. Updated some objects that are related to (1). Saved. Merged with view moc by notification.
Edit (1) in the edit moc. Saved. Merged with view moc by notification.
PROBLEM: Because the edit moc never got the new moc changes, when it saves, it deletes all the new moc changes affected by it.
SOLUTION: I realize that I could also merge the changes to the edit moc or always use a new moc to edit things. However, I keep running into little things like this and having to find solutions, so it leaves me to believe that this is not the best answer.
You should have at least one MOC per thread (they are not thread safe). So you could have a MOC for the downloader (in the background thread) and another in for the activity in the main thread list, edit and new.
When you say there is a disconnect, can you be more specific? Are you using notifications (NSManagedObjectContextDidSaveNotification) and doing mergeChangesFromContextDidSaveNotification when you receive that notification. Remember, that mergeChangesFromContextDidSaveNotification should be performed on the main thread.
In your view controller with NSFectchedResultsController are you handling all the cases of the NSFetchedResultsControllerDelegate correctly?