1

I'm making an app that uses a UITableViewController, and fills that table view with data from a webserver.

Inside my viewDidLoad I have a method that loads data from said webserver, stores it in an array as custom objects, and then loads that into cells. This is working fine.

Problem:

However, every time I navigate away from that UITableViewController, and then back, it loads everything again. This is very unnecessary, so what I did was store a boolean in the NSUserDefaults, which keeps track of whether or not this is the first time starting the app. If it is (you just logged in), load the data from the server. If not, don't.

However, as I noticed, the tableView resets every time I navigate away from (or back to) the Controller. Also, all the arrays I stored the custom objects in are now empty, so I can't load it back from the arrays either. (Every time I navigate back to the TableViewController, it's empty)

I tried storing the arrays in the NSUserDefaults, and then just populate the tableView with that data every time, but it turns out I can't store custom objects in the NSUserDefaults.

What I want to achieve is this:

Whenever I navigate away from and back to said TableViewController (I use the SWRevealViewController), I don't want the tableView to empty out. I want all the cells to stay, that way there is no wait time between when the view is loaded and the tableview is filled.

If this is impossible, I want the second best. To store the array somewhere in the app, and then reload that data into the tableview as soon as the user navigates back to the TableViewController. This is slower than my preferred solution, but still quicker and less data-consuming than loading everything from my server.

Any help is appreciated!

Thanks.

Aleksander
  • 2,735
  • 5
  • 34
  • 57
  • You could just make your 'UITableViewController' as singleton instance or just create it once and hold pointer to it. And then you need your controller just work with pointer on created one. But as i get you just wan't to cache data from server? There is a lot of ways to do it. 'NSUrlCache', 'NSUserDefaults', 'CoreData', 'plist'. – Evgeniy S Mar 31 '14 at 03:26
  • Here's what I have/ want: 1. When someone launches the app, they have to log in. When they do, I want to load data from the `server` and populate the `tableview`. 2. When someone pulls down on the `tableview`, I want it to reload with data from the server. That is working fine. However: 3. When someone navigates away from the view, and then back, I want the `tableView` to persist. I don't want to have to reload all the data. Is that possible? – Aleksander Mar 31 '14 at 03:32
  • instead of your viewDidLoad, try doing it in viewDidAppear since that is called as the view is added, and it will be ready before the view is shown, simulating the data to be "persisting" – user2277872 Mar 31 '14 at 03:34
  • Thanks, I'll try it! But where will I store that data? I can't load it back from the server each time as that generates a lot of unnecessary data-traffic. – Aleksander Mar 31 '14 at 03:38

2 Answers2

1

You should create a separate object that manages fetching the data from the web service and then stores it locally. This object can be created in the app delegate or wherever appropriate and passed to the table view controller. The data object should provide an array that the view controller can then use to populate the table. You can even have that data object start pulling from the web service as soon as the app opens instead of waiting for the table view controller to be displayed.

I do not recommend keeping the view in memory just to save the very minimal amount of time it takes to load up a table view (using locally stored data). Unless you are talking about thousands and thousands of entries, you will not notice a lag time in the loading of the view. If you are talking about thousands and thousands of entries, I recommend you load a few hundred at a time into the table.

As far as storing the data, the simplest might be just writing the raw response of the web request to a file. A more elegant solution would probably include creating some objects to represent the data and using NSKeyedArchiver. Keeping data stored locally is a huge topic with countless options so I recommend doing some googling on your own to find the best solution for you. You might start at these places:

If you go with the NSKeyedArchiver option, you can generate a file path by doing the following:

+ (NSString *)dataFilePath
{
    NSURL *directory = [[NSFileManager defaultManager]
        URLForDirectory:NSLibraryDirectory
        inDomain:NSUserDomainMask
        appropriateForURL:nil
        create:YES
        error:nil
    ];
    NSURL *fullURL = [cachesDirectory URLByAppendingPathComponent:@"a_file_name"];
    return [fullURL relativePath];
}
drewag
  • 93,393
  • 28
  • 139
  • 128
  • Thank you! I followed the guide for encode/decode and then stored it in the NSUserDefaults. – Aleksander Apr 01 '14 at 03:06
  • Glad to help. However, NSUserDefaults is really only meant for storing preferences, not actual data. It would be preferable to write the data to a file: `[NSKeyedArchiver archiveRootObject:rootObject toFile:pathToFile]` – drewag Apr 01 '14 at 03:15
  • Oh, ok. Thanks for that. I'll make that change immediately! – Aleksander Apr 01 '14 at 03:20
  • Ok, you will need to make sure you generate a file path that is in one of the user directories. I recommend storing data in the "Library" directory but you can read about them [here](http://care2achieve.wordpress.com/tag/nslibrarydirectory/). I added an example of it to my answer. – drewag Apr 01 '14 at 03:25
0

You need to store all the data in cache at first time when user is calling data from server. And after that whenever user navigate and comeback to the page load data from cache.

Chomu
  • 214
  • 1
  • 10
  • How do I cache data in iOS? – Aleksander Mar 31 '14 at 05:09
  • There are so many example. Try to google yourself. Here is the reference: http://stackoverflow.com/questions/19326284/what-is-the-proper-way-to-use-nscache-with-dispatch-async-in-a-reusable-table-ce – Chomu Mar 31 '14 at 08:49
  • try with this Code example:- in .h Class:- @property (nonatomic, strong) NSCache *imageCache; in .m class viewDidload function initialize this. self.imageCache = [[NSCache alloc] init]; And finally in UITableViewCell function use this. NewsItem *item = [newsItemsArray objectAtIndex:indexPath.row]; cell.newsTitle.text = item.title; UIImage *cachedImage = [self.imageCache objectForKey:item.image];; if (cachedImage) { cell.imageView.image = cachedImage; } return cell; – Chomu Mar 31 '14 at 08:53