iOS patterns for creating object before saving? - ios

I am pretty new to iOS and I am currently designing the "Create a new event" page for my app.
Some info:
A user can click on create a new event and then press back to cancel creating this new event. (I am using UINavigationController)
1 video can be attached to a particular event.
A user can create a new event, record a video, then decides not to go ahead with saving it (by pressing back)
Each event must generate a uuid. This uuid is required to prevent entity collision between different clients creating events and submitting them to the server.
Each video captured is named uuid.mov for storing into the file system before the event is uploaded to the server.
Coming from a rails background, I am used to doing the following:
When the user click on "Create new event page", an event is created but not saved to the db.
The user then enters attributes to the page and decides if he/she wants to commit
When commit take places, the event is attributed with the information provided. The event is then saved.
However, I don't believe Core Data has an API that allows the developer to create an entity without saving it. Currently, I am doing something like this:
When the user visits the "create new event page", an empty object is created and stored into the db. The reference to the event instance is passed to the Controller of the create a new event page.
When the user has inputted all the information and shot a video (the uuid is created at awakeFromInsert and is set during 1), saving is merely setting the entity with the required attribute.
If the user decides to cancel creating an event, I am checking whether cancel is pressed. if it is, both the event and the video file is deleted.
Code to check if Cancel is pressed.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (![[self.navigationController viewControllers] containsObject:self]) {
This is a bit complicated to be honest. Do you guys have a better suggestion?

It actually works as you described Rails working: new objects aren't saved to the persistent store until you commit them (via NSManagedObjectContext's save: method).
See the Creating and Deleting Managed Objects section of the Core Data Programming Guide. Excerpting...
Simply creating a managed object does not cause it to be saved to a
persistent store. The managed object context acts as a scratchpad. You
can create and register objects with it, make changes to the objects,
and undo and redo changes as you wish. If you make changes to managed
objects associated with a given context, those changes remain local to
that context until you commit the changes by sending the context a
save: message. At that point—provided that there are no validation
errors—the changes are committed to the store.

Related

When to Persist Object Graph

I have an object graph which represents the state of my (first) iOS app. I've implemented NSCoding for each of the objects so I can use a keyed archiver. I have the archiving and dearchiving working fine. But I'm left with a rather basic question: When should I archive things?
Is it safe to only call it when I get an applicationDidEnterBackground message from my app delegate? Or should I pesist things everytime the user does something "significant" in the interface (like dismiss some view where data was entered, etc.)? What are the best practices for this?
I found the answer to my own question in this document:
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html
Here is the relevant quote:
Important: Always save user data at appropriate checkpoints in your app. Although you can use app state transitions to force objects to write unsaved changes to disk, never wait for an app state transition to save data. For example, a view controller that manages user data should save its data when it is dismissed.

Detect deletion of Core Data

Extra info:
I have a messaging view in which I have a UITextView of which I save the text in the conversation's variable draft in the viewWillDisappear.
When the app tries to refresh the user's access code, they might get a "could not refresh" response, and the app logs the user out (only one device may be logged in at one time in this app).
In the logout method, I remove all app settings and empty out Core Data, then I set a new rootViewController and perform makeKeyAndVisible.
Question:
Now that you know all this, setting the rootViewController calls viewWillDisappear, which in turn tries to set the draft variable on a conversation that no longer exists in Core Data...
What can I do to solve this?
The simplest and fastest fix would be, when setting the draft:
if let context = conversation.managedObjectContext {
// you have a valid conversation, you can assign the draft
}
If the managedObjectContext is nil, this means the object has been deleted from Core Data.
EDIT
This answer provides a better way to detect if a managed object has been deleted from Core Data.
I would advise you to rethink the whole logout (clearing of resources) approach since yours is not going to scale in the future.

iOS fetching from managed object context before saved

If I add entities to a moc and I execute a fetch request on that moc before its document gets a chance to save, will my fetch contain the newly added entities? (I'm unsure how to test this out because of the auto-save feature)
I guess you're using UIDocument when you say 'auto-saving'. If you aren't, then there is no 'auto-saving' (except when using Apple template code and the app delegate saves before termination).
When you create the fetch request, you can choose whether it should include unsaved items using the includesPendingChanges property. It defaults to YES so by default you will see unsaved items in the results.

Concurrent changes to NSManagedObjectContext - how and when to save

My app sometimes inserts objects into the managed object context that are not meant to necessarily be saved. For example, when I launch an 'add entity' modal, I create a managed object and assign it to the modal. If the user saves from that modal, I save the context. If he cancels, I delete the object and no save is necessary.
I have now introduced an 'import' feature that switches to my app (using a URL scheme) and adds an entity. Because one of these modals might be open, it is not safe to save the context at this point. The transient object created for the modal will be saved, even if the user cancels, and there is no guarantee that the deletion (from the cancel operation) will be saved later - the user might quit the app.
Similarly, I can't simply save whenever my app quits. If the modal is open at that point, the temporary object will be incorrectly saved.
I am looking for a strategy to handle this architecture. I am considering some 'flagging' solution that allows me to identify the imported entities. When the user user quits the app, I will check if there are any unsaved changes to the context. If so, I will filter out everything except the imported entities, and then save. I have no idea if this is possible (selective saving) or a good idea.
Kevin and Andrew's comments (and the linked article) were enough to get me going. I got some follow-up advice in this question.
In summary, I am using a child context to create the transient object, and then merging it into the main context. In effect, I only need the temporary context as place to insert the object - if it was possible, for example, to create it outside of an insert message, I could do so and then insert it straight into the main context on confirmation.

How can I persist objects between requests with ASP.NET MVC?

I'm just starting to learn ASP.NET MVC and I'd like to know how I can retain model objects between subsequent requests to controller action methods?
For example say I'm creating a contact list web app. Users can create, update, rename, and delete contacts in their list. However, I also want users to be able to upload a contact list exported from other programs. Yet I don't want to just automatically add all the contacts in the uploaded file I want to give the user a secondary form where they can pick which uploaded contacts should be actualy added to their list.
So first I have a ContactController.Upload() method which shows an upload form. This submits to ContactController.Upload(HttpPostedFileBase file) which reads the file that was posted into a set of Contact model objects. Then I want to display a list of all the names of the contacts in the list and allow the user to select those that should be added to their contact list. This might be a long list that needs to be split up into multiple pages, and I might also want to allow the user to edit the details of the contacts before they are actually added to their contact list.
Where should I save the model objects between when a user uploads a file and when they finally submit the specific contacts they want? I'd rather not immediately load all the uploaded contacts into the back end database, as the user may end up only selecting a handful to actually add. Then the rest would need to be deleted. Also I would have to account for the case when a user uploads a file, but never actually completes the upload.
From what I understand an instance of a controller only lasts for one request. So should I create a static property on my Contact controller that contains all the latest uploaded contact model object collections? And then have some process that periodically checks the age of these collections and clears out any that are older then some specified expiration time?
A static property on the controller is trouble. First off, it won't work in a web farm and second it you'd have to deal with multiple requests from different users. If you really don't want to use your database you could use the ASP.NET Session.
No, you don't want a static property, as that would be static to all instances of the controller, even for other users.
Instead, you should create a table used to upload the data to. This table would be used as an intermediary between when the user uploads the data, and completes the process. Upon completion, you copy the contacts you want to keep into your permanent table, then delete the temporary data. You can then run a process every so often that purges incomplete data that is older than a specified time limit.
You could also use the HttpContext.Cache, which supports expiration (and sliding expiration) out-of-the box.
Alternatively, and perhaps even better (but more work) you could use cookies and have the user modify the data using javascript in her browser before finally posting it to you.
However, I'd strongly recommend to store the uploaded information in the database instead.
As you pointed out, it might be a lot of data and the user might want to edit it before clicking 'confirm'. What happens if the user's machine (or browser) crashes or she has to leave urgently?
Depending on the way you store the data the data in this scenario will probably be lost. Even if you used the user id as a cache key, a server restart, cache expiration or cache overflow would cause data loss.
The best solution is probably a combination of database and cookie storage where the DB keeps the information in a temporary collection. Every n minutes, or upon pagination, the modified data is sent to the server and updated in the DB.
The problem with storing the data in session or memory is what happens if the user uploads 50k contacts or more. You then have a very large data set in memory to deal with which depending on your platform may effect application performance.
If this is never going to be an issue and the size of the imported contacts list is manageable you can use either the session or cache to store the dataset for further modifications. Just remember to clear it when the user has committed the changes, you don't want a few heavy datasets hanging around in session.
If you store the dataset in session using your application controller then it will be available to all controllers while it is needed.

Resources