I have an app that interacts with a web server's API via RestKit. Users have a single account from which they can log in on both a browser client and their iPhone. In both places, they can make changes to their data by adding objects, deleting objects, and editing objects. How do I implement a way to sync all user additions, edits, and deletes by both pushing changes to the server and receiving changes from the server? Right now I have a hacky way of comparing Modification Dates on all objects, but I'm wondering if there's a more elegant solution.
Related
I would like to sync a core data app with a user with a different iCloud ID and I am trying to figure out the most graceful way to do this. I do not want the data to sync with all users, but want to be able to sync among family members for instance. From the research I have done, I do not think I can do that using iCloud Core Data sync because it only syncs between devices with the same iCloud ID. I have looked at this stackoverflow answer and read a little bit about Ensembles, Parcelkit and TICoreDataSync, Parse etc., but it is not clear to me if any of those options will allow me to sync with multiple users. Does anyone have a good method for syncing a Core Data app with multiple users?
Ensembles and TiCoreDataSync might work. They can use Dropbox file syncing, so in principle they should work with Dropbox shared folders. I don't think these are the main intended uses, so I suggest contacting the developers and/or doing some good testing yourself before assuming this would actually work.
You'll need to think about the user experience, though. At a minimum, your users would both need Dropbox accounts and would have to set up a shared folder before beginning to sync data this way.
Parcelkit probably won't work. It uses Dropbox's data store API which, unlike other Dropbox services, doesn't appear to support shared data.
Services that do support this kind of sharing exist-- for example, Parse and Firebase-- but make sure to review their pricing carefully before using them. Also of course, there have been any number of projects that have their own custom server back end, but that obviously requires having someone on the team who can do that kind of work.
You need to think about other device types (Android at least) if you want your application to be reaching more users.
I'm doing the same now by the following way:
Setup an online database with proper web services (careful with implementation for security matters - DB should NEVER be exposed by anything other than the web services).
Create a Class for your communication with the server (using Class methods with security handling like authentication and authorisation).
Use the class in your app to communicate with the server (SQL operations are done on the server).
To integrate with CoreData you need to create the model in your app similar to the structure in the backend database. Then you need to create a similar class for the app that deals with only local CoreData.
A higher level class might be required if you want to make sure that operations done on both server and local data storage.
Besides, you have to implement a lot of conditions to make sure that data written in local ONLY after making sure that it is stored online (or create an engine for differed operations to run later).
Another Way if you are familiar with notifications:
Use structured notifications between devices for data operations in order to keep everything in sync with other users. The problem with this is the "Autonomy" of the operations. If two operations were done in approximately the same time, you have to find a way to make sure the order of the operations is done properly (maybe timestamp or something).
I'm looking into the same thing for my app and I 'think' you can do a fairly unsecured version of what you are after using using the public folder in cloud kit as mentioned in this question (no accepted answer at time of posting) : Private data sharing using CloudKit
You would need to find a way to differentiate between data that is truly public and those shared among the users you need and some level of authentication.
I'm going to try exporting a permission file with access permission in it to whomever I want to share with combined with a unique identifier located in that permission file.
Keep in mind, as mentioned in the comments of the linked answer, my implementation will be security by obscurity (thanks for that phrase) unless you find a way of adding proper validation to it but my data is relatively insensitive.
Hope this, or any ridicule in the comments, points you in the right direction : )
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.
I need a suggestios on how to correctly implement CoreData with objects that can be uploaded/downloaded from server and sent through game center.
The app is similar to a trading card game, you can get the idea from these 2 separate entities:
Card: The actual unique cards with all the information about each one. The "Card"s entities are static and do not change, they do not need to be sent on server either because all I need to do is send the "CardId" to pull a "Card" entity.
UserCard: All the cards that a user owns, a user may have the same card multiple times but this would be a different "UserCard" with a pointer ("CardId") to a basic "Card". They are always changing. They need to be easily sent through GameCenter and uploaded/downloaded from server. Also, some temporary "UserCard"s would need to be downloaded from server when the user visits a friend's profile to see which cards they have.
Does anyone have any suggestion on how to do this correctly? Currently I have two ideas:
A. Use CoreData for everything, this would mean that the "UserCard"s are NSManagedObject subclasses which get intelligently encoded/decoded (using NSCoding) to upload/download and send through GameCenter. The basic "Card" is set as a relationship in Core Data. A "temporary" attribute is also set for the "UserCard"s to be able to know which ones do not belong to the current user so they can be deleted later.
B. Use CoreData only for the Basic "Card"s and use a NSObject subclass for the "UserCard"s. This allows me to directly use the "UserCard"s without the need to insert them into CoreData. Makes it easier to download/upload and send through GameCenter. It also removes the need for the "temporary" property because the objects will just be deallocated when the view has stopped using them. The problem with this method is that I would need another way to store the current user's "UserCard"s in the device because they do need to be available offline.
Thank you!
Personally, I would use CoreData all around. Reasons:
You're already having to dive into CoreData to deal with Cards anyways
Just create an NSManagedObject category called NSManagedObject+JSON. In it have a simple method called -(NSDictionary*)jsonRepresentation and have the UserCard format itself into a dictionary and return itself. Super easy.
It would be safer to use CoreData and save often, rather than run the risk of writing to a file and it either: 1. getting corrupted (highly unlikely but user would be mad if it did); or 2. not getting fully written (user could kill the app before it has time to write everything to a file)
The extra little bit of work to implement the UserCard entity would be small.
You get the built memory management and searching functions of CoreData.
I just finished a large project working with CoreData so I may be a little biased. From what you've stated in your question though, I would take CoreData for everything. Here are some helpful opensource libraries when dealing with CoreData and a web server:
MagicalRecord
AFIncrementalStore
And a great tutorial for integrating CoreData with a web server.
I am about to build an internal-only iOS app for storing simple business data. The data store will consist of a single entity only, with one entry per day. To start with there will be around two years worth of data (~750 entries).
I want to set the app up to do one-way syncing only. i.e. Only one person can enter data, but others can read it. iCloud is out as it only works for a single user account.
Is there a lightweight way to sync this datastore out from the single write user to the other read users? Setting up a full sync system seems overkill for this case.
Instead of iCloud, you could use one of the online backends such as Parse.com or Simperium. They would allow you to share data using a db and also provide for user accounts, authentication etc. If you want to run the server locally you can investigate DataKit.
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.