I am writing an app that has a form spread across multiple ViewControllers and a main menu with the submit button on it that opens an e-Mail with the text fields data displayed in it, the only problem i have is that the text boxes don't 'remember' what's been written in them when switching between sections of the form. I have had a look through threads regarding persistent data but have found nothing. I want my application to remember what's been entered in the text fields when switching between views so it can populate the e-Mail with the data but then 'forget' the data again when the user minimises the app. Any advice or pieces of code would be much appreciated.
So create a data model singleton and have your view controllers read/write their values from properties of that singleton.
(In viewWillAppear, fetch a pointer to the model singleton and install values from properties of the singleton into your VC's fields. When the user changes a value in a field, have your VC modify the corresponding property of the singleton.
You can write your singleton to listen for the "will enter background" notification and archive it's settings to disk, and make it's init method try to read saved values from disk (or set the values to a defined starting state if they have never been set). You can use NSUserDefaults, NSCoding, or a variety of other approaches for archiving your data.
There are lots of options to persist data. I currently favoring Realm, but previously I've used Core Data, YapDatabase, and even simply serializing objects to disk. Note that if this is your first foray into saving data on iOS, I strongly advise AVOIDING Core Data, as it is very complex and Feature Rich (also, difficult to use correctly until you know it fluently). I recommend you start with serializing objects yourself, then either Realm or YapDatabase.
You should create a singleton NSObject class and keep data in that class ... As singleton objects hold data until the application is terminated.
Related
I just started working with core data in iOS app dev using swift. The first two things that I encountered are: 1. AppDelegate 2. NSManagedObjectContext.
I understand that 'AppDelegate.swift' file is a source file just like the 'ViewController.swift'. But in all the tutorials it was referred as 'something which will be used later'. Perhaps, now is the time to get familiar with it. Could you kindly tell me what exactly it does?
What does an object of type 'NSManagedObjectContext' do? What is its function? Could you please put its function in simpler words?
Thanks in advance.
Have a look at the following figure for visual understanding of Key objects in an iOS app:
Role of AppDelegate:
The app delegate is the heart of your app code. It handles app initialization, state transitions, and many high-level app events. This object is also the only one guaranteed to be present in every app, so it is often used to set up the app’s initial data structures.
AppDelegate is used for the whole app, you can use it to manage the app life cycle, on the other hand, ViewController is used for a single view. you can use it to manage life cycle of a view. One app can have multiple views. but only one AppDelegate.
Role of NSManagedObjectContext:
The NSManagedObjectContext is a fundamental concept of Core Data.It is like transaction in a relational data. You can fetch objects, you can create objects , update and delete them, save them back to the persistent store, etc. Basically for all the core data operations, you will need to interact with NSManagedObjectContext.
UIApplicationDelegate is an interface between device (the iOS system) and your application. You will i.e. handle push notifications in this class
Context is more complicated. Generally all object that comes from CoreData has some context which is responsible for sync all object in this context. So if you fetch object A and in some other point of code you will fetch again this object (lets call it A2) and both are fetched in the same context then A == A2 is always true. But that's just the tip of the iceberg.
I have an app where the users enters certain information. Each time the user wants to, he adds a new item to a table list. When the user is done, they click the finalize button to finish the list and they can start another list.
In the AppDelegate.swift file, I see a few preexisting functions. applicationDidEnterBackground says to save information before the application enters the background (I'm assuming it's when the user presses the home button while using the app...).
In my app, each time the user adds items to the list, then goes to home screen and locks the phone, after a while the items are gone. So the information they added don't save. I'm thinking to use the functions in AppDelegate.swift to save information and load information each time the app is minimized or maximized. My question is, what is the best way to save this information? Would I just write to a file and read from a file or is there a way to automatically save and load this information? I've read something about saving objects to a .plist but I don't necessarily know how it works since when I click the info.plist it just takes me to table of settings and no code.
Thank you in advance for the help!
Disclaimer: I am an experienced Objective-C developer, but quite new with Swift. My answers are going to be Objective-C oriented.
You have lots of options. The other poster suggested Core Data, but that is likely overkill unless you have complex information to save. Core Data is a big, complex framework with a steep learning curve. It's very powerful, but expect to spend a week or two of intense study before you're able to use it with any fluency.
The easiest and cleanest way is often to use NSUserDefaults. It's a Cocoa class that reads/writes key/value pairs to a system-maintained file in your app's sandbox. (Essentially a dictionary that is automatically read/written to a system file.) You don't need to know about the details of how it works - it just works. See the Xcode docs on NSUserDefaults for more information.
Another option is indeed to use a property list. Cocoa container objects like NSArray and NSDictionary include methods to save and read themselves to/from property lists. Look for methods like writeToFile:atomically:.
For saving to both NSUserDefaults and property lists, the object you save, and any object(s) it contains (if it's a container object) must be members of a very short list of "property list" objects (dictionaries, arrays, strings, numbers (integer and float), dates, binary data, and Boolean values.) Do a search in the Xcode docs on "Property List Types and Objects" for more information on property lists and the supported data types.
A third option is to implement the NSCoding protocol in all the objects that you want to save (your entire "object graph") and then to save the root object (often a container object) to disk using the NSKeyedArchiver method archiveRootObject:toFile:
With all of these options, you can implement the app delegate method applicationDidEnterBackground, and save your state data when it's called. You'd then load the data back in in your applicationDidFinishLaunching method. (You don't need to load your saved state data back when you return to the foreground, because if you are returning to the foreground, your app is still running and it's state data is still in memory.)
Various of the Cocoa touch classes also include support for automatic state restoration, but that's more than I have time to cover here.
I will suggest use core data for data persistance
Please go through ray wenderlich tutorial for core data
Within my Swift application, there are two classes that I interact with in almost 75% of the app. One is a set of settings called UserSettings, and the other is called Job. These both are stored in sqllite.
Most of the time it's just reading values already set, and on one areas it also writes. It seems strange to have to keep reinstantiating my settings and job services to communicate with my database to get back to me the same object i'm accessing across the board.
In a case like this, the options to me see to be either
constantly reading/writing to the database, or
do some sort of singleton accessed throughout the entire app.
I'm not sure how much Swift changes anything in terms of arriving at an answer to this question, but I wanted to seek the help of Stack Overflow. How do I set an object that I can access throughout the entire app? Or is it not ideal and instead I need to get it from my db every time?
Thanks so much.
I recommend you to read how core data works, I know you are managing your own store, but the architecture works fine. As a summary you can create a "context object"(this could be your singleton) who interacts with your store (sqlite) creating managed objects, you will work with this objects who are associated with the "context object", and when ever you need to save the changes, you ask the "context object" to write all the managed objects in the store.
Your managed objects need to be only a copy of the "context object" objects, so when you ask to "save" data to the "context object" you only copy back this managed objects. This will help with save multithread coding. (Your context object should work on a serialized queue).
Again this is just a summary, you should read how core data works to get a better picture.
Edit:
Read this blog: http://www.objc.io/issue-4/core-data-overview.html
The difference is that you only need one store and one context object.
I am currently using singleton instances to access and maintain various NSObject in the app.
For instance, I have :
VariableStores, that maintain several objects such as currentUser (custom NSObject), lastLocation (CLLocation), etc.
TaskManager, containing a NSMutableArray of NSOperations that have failed in order to be re-executed later (such as Instagram with failed upload).
If I kill the app, singleton instances are destroyed and :
- some data must be retrieved from the server side (for instance, the currentUser) which increase the length duration
- some data cant be retrieved from the server-side, such as the NSOperation in the TaskManager (as they are only managed locally)
Thus, I would like to go further and maintain that kind of objects even if the app is totally killed.
What should I consider as a good practice? Serializing object into NSUserDefaults and deserialize ? Is there other best practices?
In case of serializion, serializing objects in -applicationWillTerminate delegate and deserializing them in appropriate -init methods of singleton (that are instantiated in the appDidFinishLaunching) can be considered as acceptable ?
the idea of singleton pattern is just to transfer data between controllers without worrying about details ..
what you need to do is a persisting data of your App ..
you can use core data if you see that the data that you need to store is a little big for plists.. or you can use sqlite but that will give you a little pain for writing a lot of sql statements..
or you can use regular plist or nsUserDefaults (i don't like that option) but it's a little slow if the data is too much ..
you can save this data when app go to background or terminated..
How do I load a table downloaded from the web and put it into core-data?
If I have a CSV file (could be SQLite) of about 2000 rows, that's been updated, and put onto the web like Amazon Web Service, how can that be loaded into core-data while the user is using the app? I would like to completely replace the previous file, and reload the table. I imagine I save it to the documents directory, but then how to load it into core-data and it load quickly so the user does not have to wait too long?
I won't know what data the user needs, what was added or deleted since the last time it was used, so I can't make a query for just the changes. The table is made up of text, integers, and geocodes, that I will update twice a month.
Can core-data read from an external file to populate a tableView, or must it read only from what's inside itself? I don't absolutely need a relationship between tables, so if that gets in the way, I could remove it. There may or may not be a second table loaded. Would it be better to use SQLite table instead? I've not done this part of core data before. What are best practices? Code samples would be helpful.
I assume you are well versed in using Core Data and you are deploying to iOS 5 and higher. I also assume you understand the CSV format very well. Then this would be a design to start out with:
Create a parser object. This object is responsible for understanding the csv-file (this is logic that you need to write yourself, there is no native csv-parser clas). You give this object the NSString, or local URL to the file and read it line by line. Let's say every row contains the data for one Core Data entity: this parser then extracts the values from the string's first line and creates/updates an existing Core Data entity. See this link for an efficient way of updating/creating Core Data entities.
Make sure all this parsing is done on a backgroundThread, with an NSManagedObjectContext that has a private queue type.
Create a UITableViewController that utilizes an NSFetchedResultsController that you initialize with an NSManagedObjectContext that is the parent of the NSManagedObejctContext used in the parser-object. Make sure you give it the main queue concurrencytype on initialization. This way, every time the parser creates/updates an entity, it will save this up to the parent context. This context in turn notifies the NSFetchedResutsController and you can update your UI for each updated/created entity separately through the NSFetchedResultsController delegate methods, showing changes to the user as fast as you can.
Make sure some overseeing object (might be a Data-manager, or maybe a networking class, or maybe event the viewController, although I would go for a Data-manager) gets told that the complete parsing process is over, so that the managedObject in the UITableViewController can be saved (which will actually persist the data).