My question is mostly related to an architectural or design pattern for hierarchical models in Objective C. For background my app is relatively simple. In general it talks to a web service to retrieve and display things a user can follow. When someone follows something, the thing they are following is conceptually stored for access later by posting to the web service.
I would like advice on where the logic should go to manage the interaction between the web service and the group of things a user follows.
For example, is it appropriate to create a model object like MyStuffModel with an array property named followedThings that holds references to AThingModel objects? And if so, would the logic for refreshing from the web service, etc be written and executed in the model?
Potential code example
#interface MyStuffModel : NSObject
#property (nonatomic, strong) NSArray *followedThings;
- (void)refreshAllFollowedThingsFromWebService;
#end
#implementation MyStuffModel
- (void)refreshAllFollowedThingsFromWebService
{
//call my API client (built on AFNetworking), get back a response
//populate followedThings, notify a view controller, etc
}
#end
Or, should I not have a MyStuffModel object and manage the calls to my web service by calling my API client directly from a view controller?
In your experience, which approach is desired? Or is there another way?
I would do all of the networking from within the model. Here's an outline of how all the pieces fit together
the controller tells the model which items to follow
the model forwards that information to the server
when the server has new information, it uses APNS to notify the model
the model requests the new information from the server
after the data transfer is complete, the model uses NSNotificationCenter to inform the controller that new information is available
the controller reads the information from the model
the controller updates the view with the new information
Using Apple's Push Notification Service (APNS) allows your server to notify your app when new data is available. This helps reduce network traffic since your app doesn't have to constantly poll the server to determine when new data is available. If you aren't familiar with APNS, there's one very important feature of the service that you need to be aware of (since it seems to be a point of confusion for many new users). The service only guarantees delivery of the last message sent. So, for example, if the server gets 10 new items for a particular device, and sends 10 notifications to the device while the device is either off or in a tunnel, then the service is only guaranteed to deliver the 10th message. The point is that you can't use APNS to send any data from the server to the device, since some messages may be lost. You should only use APNS to notify the device that data is available.
I always create model classes (and interfaces, no idea if thats applicable in ObjectiveC).
The model is in many cases a view of the database backend.
Your model class should hide the database access and provide a simple interface, for example using a addNewFollower method. This method should then (optionally do sanity checks) and persist this to the database backend.
This approach allows you to easily replace your database integration without touching the service layer at all. For example using an in-memory mock database for testing.
I always create simple "dumb" objects for models, as they model the data, nothing more. If you're doing networking/api calls, I'd create a separate set of classes that deal strictly with API calls and utilize your models as the interchange data. Mixing data and functionality is always fishy to me.
Writing a clean, reusable, testable, and reliable API client, that can handle errors, parallel/serial calls, logging etc, requires quite a bit of code that really should be separated from your other application tiers. Data is just data, keep it clean, keep it simple.
The other thing is that some endpoints don't always return data exactly as it is defined in that 1 model where you are shoe-horning all of your code.
I wouldn't put it in the controllers either, I personally always create a different set of classes that can be used specifically for API calls, which also throw their own exceptions, handle serialization/de-serialization etc.
Related
I create a SQLite connection with SQLite.swift but I'm not sure where to store the DB connection so I can use it during the duration that a user has the app open across various views.
Is using UserDefaults here an appropriate case? Or EnvironmentObject?
What is the recommendation with iOS apps in terms of keeping a DB connection open for reuse?
Is using UserDefaults here an appropriate case?
Definitely not. Like you said yourself: you want it to exist while the app is open. While UserDefaults is for things you want to store when app is not running.
Or EnvironmentObject?
You could, but semantically it's still wrong: Apple defines it as "A property wrapper type for an observable object supplied by a parent or ancestor view.", which doesn't really fit the DB connection. It's not an observable object with states.
Ideally you step back and look at a more generic architecture of your app.
Views want data in a specific format. They don't care where the data is coming from.
The fact that data is coming from DB is an implementation detail - tomorrow you may decide to retrieve it from remote server, and you don't want to change every single view because of that.
So what you really want is
View talks to some sort of "data provider" interface that defines an interface by which views can get their data regardless of where it's stored.
Your implementation of "data provider" is to talk to the local database (currently, but it can changed base don your needs).
In this structure the DB connection(s) are managed by data provider, and do not need to be shared with anyone. And your views will actually use Observable objects, except those observable objects are data itself, not the connection to database (and in fact views will not "know" where the data is coming from).
I will not go into details on how to make that model happen - there are many other details here (like what's overall architecture of your app), but this is the gist of the idea.
I am creating an application that does not store any data (other than basic user name, password, etc). It uses API calls to get data and displays them when loaded through Volley.
I know typically it is best practice to use content providers and loaders when you store things in SQLite. My question is: should I still be using content providers and loaders given that my app does not utilize a database. Does anyone have any best practices/tutorials on how to do so with Volley?
Thanks!
It depends on your use cases. But here, no there is no need. There are other callback mechanisms you can use like broadcasts, async tasks, handlers or even content observers. There is a nice official tutorial of how to communicate with the UIThread aka. the visible stuff from some background logic.
Also if you want to you also can use loaders without any content provider. See this so post for more informations.
I've been developing an application similar to Whatsapp (with its special features of course) and am now at the point where I think I should refactor all the existing code to make it conform with the MVC design pattern (because of too much glue code).
If I'll break my application to some simple stuff, we'll have:
First Message:
ID
Any Unread Message
Source User
Target User
Normal Message:
ID
First Message (weak reference)
Received State (Got to server/Got to client/Read by client)
Am i owner of message (am I source)
Date
User:
ID
Phone Number
Profile Image Link
Note the "Any Unread Message" should be ON if there are any messages the user didn't read. just an optimization from the server.
I've never really worked with the MVC design pattern properly so I would like to make sure that my plans are correct or perhaps there are additional/other stuff I should do.
I was thinking about:
Model:
Create a Core-Data xcdatamodel file which will hold the above entities
Use the library mogenerator to generate entity files from the core-data model
Create Data-Models for each operation. for example: Register Data-Model which will handle all the registration api with the server;
Message Data-Model which will handle sending a new message and
retrieving new messages; etc. All of these will be singleton.
View:
all the views of whatsapp like outer UITableViewController (to display unique users) and inner UITableViewController (to display
messages from a specific user).
Controller:
uses some of the above data models to fetch new data explicitly
I'm thinking to just give an API from the model to the controller which it can use it explicitly but that doesn't use the notifications or Key-Value-Observing designs.
I haven't found any online tutorial or document that explains what's the better thing to do.
Any suggestions?
Well I managed to successfully implement the MVC design pattern in my project by sticking to the theory - using notifications between the model and the controllers and using KVO between the views and the controllers.
:)
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'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.