swift iOS what ways can I cache network calls - ios

The first thing a user has to do when he/she is launching my app is to select a category and a sub-category from two table views. (relational)
I populate the table views by calling my remote API/Server and the output the data.
But is there a way to cache the data so that I don't have to make a API network call every time?

You can serialize the data returned from the API calls and manually save them on the disk Explanation here
Also you can use core data this is a bit more troubling in the beginning but after the initial setup it is pretty easy to use.

Related

Best design pattern to handle iOS Application State/Data

I am starting a new project (learning purposes) and I am trying to figure out what is the best software design pattern to use in the following scenario.
I have several data that need to be downloaded from multiple webservices and store somewhere in my app, to display it later. However each piece of data (e.g. list of teachers, students) will only be used in one or more specific view controllers (e.g. teachersViewController and studentsViewController).
I read that the Singleton pattern or use the AppDelegate to store a variable (an object like ApplicationData) is a bad practise, even more in this example which I want to restrict the data access.
So, which design pattern should I choose? I have read something about dependency injection, but I don't have any clue about it or if it even helps me in this question. If it helps, some examples with explanation would be nice.
You need some sort of database to store downloaded data. Good choices are Realm and Core Data. The right way to process data is:
Check if data is already in DB and show it if available.
Download or update data from server and parse it to objects.
Save objects to DB.
Show data taken from DB to user.
Download data as needed. When you open VC with students then download only students data and so on.
EDITED: If you need all the data on app open then load it and put in a DB before first screen opens. Then just use DB to show data to user.

How to ensure data consistency and truly take advantage of Core Data?

I've worked on several iOS apps, some of them utilize Core Data, and some of them don't. While I consider myself having a basic to somewhat good understanding of Core Data, there's always something that makes me doubt the usefulness of it. I've done a lot of reading on the subject, and the general consensus seems to be the advantages of using it outweighs the disadvantages. I recently submitted an app without using Core Data, and always planned on going back to update the project to utilize it when I have the time for some optimization work. Now's the time, but I wonder if it makes sense for the app I'm working on, and maybe I am not using it correctly all along. Please advise and point out what I am missing.
The project I am working on is a social networking app, which also has a front-end site. We have standard features like a newsfeed, event listing, the ability to follow/unfollow someone, and a map with POIs at user's location. Currently, we're using pagination whenever needed when requesting data from server.
My understanding of why Core Data is great:
Easier to manage data with complicated relationship
Easier to access data without having to pass them around
Easier to manipulate, fetch, and sort your data
Better memory utilization
Improve perceived performance by preloading data stored locally until latest data's received
The problem I am having is, since I am using pagination when requesting for data instead of requesting for all at once. The data stored locally is only a subset of the current state in the database. Let's use newsfeed as an example. If I do the following, it will cause some problems:
User manually refresh the newsfeed -> Controller notifies model that it needs the latest 20 items -> Model requests for the latest 20 items in the newsfeed and save them as NSManagedObject -> Model notifies controller that data is ready -> Fetch the latest 20 items to show in UITableView
If user A refreshes the newsfeed, background the app, and then user B deletes his post in the newsfeed (let's say it was 10th item) before user A foregrounds the app again to refresh the newsfeed. In user A's newsfeed, B's post will still be up there because according to the createdAt attribute, it's indeed one of the latest 20 items.
To fix this problem, I can think of a few solutions:
Add a flag to the item to indicate it's removed
Always discard local data when new data arrives
Disable pagination
Instead of using the workflow described above, always present the requested data only instead of fetching the latest
Solution 1 means custom code is required to deal with different clients since browser doesn't need deleted items but iOS client does. However, even though it can work, it can potentially mess up the pagination mechanism and can cause weird behaviours in the client. For example, if a large amount of items gets removed, the latest 20 items will contain only a few items that will actually show up in the newsfeed on the client when user refreshes it. As user follows more people, more stories will be inserted in his newsfeed as well. This solution won't work very well in this situation.
Solution 2 totally defeats the purpose of using Core Data in the first place unless I am missing something.
Solution 3 means the client always needs to request for all data. This is nearly impossible to do because as you get more data, the time to retrieve and process them will make the app slow and unresponsive. It also doesn't make sense from technical and UX point of view.
Solution 4 also kinda defeats the purpose of using Core Data because it's the same workflow when we only store data in memory. You can still fetch and find objects but they might be invalid on the server already at the time of access.
Am I missing something? How is Core Data supposed to be used in this scenario? How do you ensure data consistency when the client doesn't have all the data? Thanks you in advance.

ios App improve network performance by requesting data up front

I have an application that I'm writing that pulls data from a few network sources:
1) list of blog posts (UITableViewController)
2) list of videos (UIViewController with an embedded UIScrollView)
3) list of images (UIViewController with an embedded UIScrollView)
Right now, there is a home screen with a menu and when you push one of the buttons, a destinationViewController (described above) is what loads the data on demand. I've noticed this is quite slow, especially when on a cellular data connection as opposed to wifi.
I was thinking about creating a class that requests all the data up front and kick it off every time the app is reentered. Does anyone have suggestions that could help me answer the following?
1) are there any classes, frameworks, or existing i code i can use to kick off these requests in a single place?
2) how do my destination view controllers (mentioned above) get the data?
3) how do my destination view controllers get informed that the data is ready if they happen to be invoked before the data is available?
4) is there a better strategy i should employ?
I appreciate the help.
Thanks,
jas
Off the top of my head, I would make the request class you mentioned and start all the request methods in applicationDidFinishLaunching in AppDelegate. I would also probably make custom NSObjects for each type of object you would be fetching and in each of your request class methods, convert the fetched data into said object, then cache each object to disk as they are downloaded. Then in your viewcontrollers, fetch the cached objects as needed.
When you are cacheing, make sure you cache each object with a key that will 100% be unique, because you are going to want to run a check on the current local cache before you start a new download. I would probably string together the file type and file name, and set that string as the key for the cached object.
To run the check on current cache in your request class methods, something that says "if current cache contains object for key:
uniqueKey... do nothing. If else, start the download and cache the object when finished."
Also run a check in your view controllers, because you're also going to want to handle the case where your view controller is requesting a cached object, but it hasn't downloaded yet. So something along the lines of "if current cache has object for key:key, great! use it. If else, start the download... cache it... then give me a call back here so i can use it while I display a loading message to the end user."
Im sure there are other scenarios that you are going to have to deal with, but that's the theoretical direction I would head in.
EDIT:
check out this, it will probably help you a lot. I think it also uses Ego Cache (if you dont want to write your own cache methods): https://github.com/Infusion-apps/Download-Manager
EDIT 2:
I also agree with #RyanDignards point #4. If possible, avoid fetching data you don't need. However, only you really know your UI/UX and app functionality, and my suggestion is assuming there is a good chance your end user is going to be using your app for the sole purpose of consuming the content you provide. So they are most likely going to be wanting to read the blog posts, watch the videos etc... The call is up to you, if you think there is more of a chance that the user will be viewing all the content than not, I would go the preload route, because nothing pisses off a user like having to wait.
1) RestKit is generally regarded as one of the the standard web interaction frameworks http://restkit.org
2) RestKit provides methods such as -[getObjectsAtPath: parameters: success: failure:] or post, which will provide the response in success. Additionally, it can convert the response directly into the respective objects for you with mapping.
3) Generally I would post a notification which is unique to that request, and any controller interested would get notified, with the response located on notification.object within the listener. Additionally most network requests provide for a callback handler where you could update the UI directly.
4) I would advise against preemptive loading since you're using resources for something that you may not actually use. My advice would be to breakdown your calls to the smallest possible level, then as the notifications are posted, that data would be inserted into the UI.

CoreData best practice implmentation on the UI side and in subproject

app scenario: on the UI, a button is tapped to get contact list from the server. the request goes to subproject which does the download and parsing and returns the result thru its delegate to the UI. so far everything works properly. lets say there is no internet connection and we cant have the contact list. to solve the problem, I want to cache the data in core data. if there is no internet, the cached data will be returned. now the question that bugs me, is it possible to create one data model and use it in subproject to save the data and in UI where data get pulled and edit from the same data model?
so basically i want to access core data from different subprojects and UI.
i couldnt find hints or tutorials regarding this issue. any ideas?
thanks in advance!
edit:
a project "b" that is added to the parent project "a". the project "b" is actually a static library.
if i let the library to do the saving and returning data to UI, wont it be inefficient to get all data from core data then send it to the UI?
i actually hope that there is a way to use same data model in both UI and the library.
i want prevent the UI to have huge load of data. its better to hace core data to handle that incl. memory mangement. i'm still reading some sources and trying to implement it on a test project.
I would argue that only the main project should deal with persistency, as than you can always decide to handle it differently — save it permanently or not, use core data or a home grown sql wrapper…. So it would be up the the delegate to decide what to do with more data.
But along with the delegate protocol you could decide to maintain different model protocols that define, what your models can hold. this would be independent to the implementation. The delegate now could return objects — no matter if core data models or not — to the delegator if this objects conforms to the protocols. The delegator in the sub module now could check for values on the server and/or in the cache.

iPhone Data Best Practices - caching vs remote

I'm developing an iPhone app that uses a user account and a web API to get results (json) from a website. The results are a list of user's events.
Just looking for some advice or strategies - when to cache and when to make an api call... and if the iPhone SDK has anything built in to handle these scenarios.
When I get the results from the server, they populate an array in a controller. In the UI, you can go from a table listing view, to a view of an individual event result - so two controllers share a reference to the same event object.
What gets tricky is that a user can change the details of an event. In this case I make a copy of the local Event object for the user's changes, in case they make an error. If the api call successfully goes through and updates that event on the server, I take these local changes from the Event copy and set the original Event object to match with setters.
I have the original controller observing if any change is made to the local Event object so that it can reflect it in the UI.
Is this the right way of doing things? I don't want to make too many API calls to reload data from the server, But after a user makes an update should I be pulling down the list again with the API call?
...I want to be careful that my local objects don't become out of sync with the remote.
Any advice is appreciated.
I took a similar approach with an app I built. I simply made a duplicate version of the remote data model with Core Data, and I use etags on the backend to prevent sync issues (in my case, it's okay to create duplicate records).
It sounds like you're taking a good approach to this.
Some time back, I developed an iOS app where in, I had almost same requirement to store data on server as well as locally to avoid several network call and also user can see their information without any delay.
In that app, user can store photos, nodes, checkIns and social media post and with all this data, app can form a beautiful timeline. So what we did was, we had everything locally and whenever user phone come in some WIFI zone, we start uploading that data to server and sync both (local and remote) databases.
Note this method works well when only one user can access this data.

Resources