I have some complex networking in my app( I don't use any third party dependencies, because of project requirements). For instance, I send three network requests in parallel after first two requests provide results. All my networking is done in separate models, known as networkClients(following MVC-S pattern) and are called directly from repository, not from ViewControllers. However, I need the last request to notify my viewController after I get response from network. How should I do that? I don't think notification center would be right solution because it can cause memory leaks and I have not found correct approach to complex problem like this. Please provide some prominent solutions. It should conform to good design pattern like MVVM or MVC and should not be some workaround or hack. Maybe delegates would work? I know that rxSwift would solve my issue, because I could start observing for results after initializing viewController and after data would be updated from repository my viewController would also be notified...
The right design doesn't have VCs observing the network clients directly. Those network operations should be assembling parts of a model, which is what the VC really cares about. Have the VC observe that singular model.
It can do this observing using one of the well known patterns for loosely coupled communication between objects. The OP correctly mentions delegates. Notification center and KVO are others. There's plenty of discussion on SO about which to use and how to implement. (I'd go with NSNotificationCenter as an easy and rational start).
So the order of operation is like this:
allocate the model
launch the network requests and setup those request completions (completion blocks, probably) to update that model with their responses. (the model can launch the requests, which is a reasonable practice).
create the view controller(s) that setup model observation when they initialize (probably, in viewWillAppear or later)
What about the fact that >1 requests are in flight simultaneously? A commenter above points out correctly that GCD offers a way to group those async operations into a single one. But you can do this yourself straight-forwardly: the model decides when it's completely built. The completion code for each request will change some condition in the model to the "ready" state. Each request completion can check to see whether all of the ready conditions are met, and only then post a "ready" notification for observers to see.
Another niggling issue: what if those requests all run very, very fast? Maybe there's some cached response that's ready early, making the model "ready" before the VC has had a chance to setup observation? Handle this straight-forwardly in the VC: before observing the model, check to see if it's ready already and run the same update code that runs on the notification.
Related
I don't have a current problem really, but rather a question that I can't seem to find a satisfying answer to.
What is good practice to use when handling callbacks and invokations of NSURLConnection in objective-c? Let's look at some examples.
Let's say I have 3 different ViewControllers, and I've created a class that does the network calls with NSURLConnection in order to obtain a JSON from some site. All 3 VC's will be doing different kinds of network calls. How would one go about doing this without having to repeat code or have the network handling all spread out? And what if I need to make more network calls depending on the result of a previous call?
I use the normal NSURLConnection delegates, such as didReceiveResponse, didReceiveData, connectionDidFinishLoading etc. So what I do is I store the statusCode in didReceiveResponse and in connectionDidFinishLoading I call a function I name handleResponse which checks the statusCode and if the statusCode states that the call was successful I translate the NSData* object that I've stored the data I received from didReceiveData delegate. This is all fine, but the data I translate I want to be sent to the correct viewController.
There are several options to do this:
I let the delegate for the NSURLConnection calls be the
ViewController itself. This sucks, since I have to duplicate the
NSURLConnection code in every VC I want to make a network call,
obviously.
Or I could handle all the data in the Network class that performs
the NSURLConnection calls. This sucks since I get logic code in a
network class, and I don't really want that? This also requires that the Network Class knows about classes and data structures that it probably shouldn't. It's a network class and should not do anything but networking stuff.
My final approach, which I try for the first time now, is to let the
ViewController tell the network class that it wants to make a
NSURLConnection call, and sets a NSNotification message which the
Network class should invoke in the handleResponse method I
mentioned earlier. The Network class sends the data it received
through that NSNotification and the logic for handling that data
falls on the VC that asked for instead. To me this is most logical
and feels like a somewhat good way of doing things.
The problem with solution 3 is that I have to have different Notification methods to handle different kinds of data, which could result in quite a few such methods. If different VC's also use the same kind of data handling as another NSNotification method, then I have to duplicate that code as well. I'm also fairly new to using NSNotification in general and not very knowledgeable about its drawbacks.
Final question, let's say I want to make 4 different NSURLConnection calls, one after the other has been confirmed finished and successful. How would you go about that? I've done this a few times, but it ends up as a counter in the form of an enum to keep track of which network call was just made and which one should be next, which results in switch-statements executing certain code depending on which was just performed. I'm thinking about maybe implementing some sort of queue which goes through all calls in a sequence instead.
I appreciate any kind of input!
Most if not all of these problems are solved by AFNetworking. Specially the problems concerning having to duplicate requests or connections.
For the final question, for example you can do it with blocks AFNetworking provides such a structure, so you can specifically coordinate multiple calls.
AFNetworking
There are a lot of tutorials out there and the brief documentation of the library github site provides short, concise and easy to understand examples. Getting to use it takes a few minutes.
I have got several types of a logic controller class that handle the communication with a remote resource. To do so each class uses an instance of a network controller class that deals with the connection details: connects to a resource, sends data, receives data. The logic controller classes are notified of data changes from the network controller class using notifications. So in my current solution each logic controller class registers for the notifications and implements specific functions to deal with them differently.
However, if I want to do proper code engineering, I wonder whether it would be more robust to use protocols and delegation.
I wonder if I could define which methods the logical controller classes need to implement in order to receive the notification. However I am not sure if this makes sense and is correct because I do not want inheritance here.
Any suggestion?
Typically you have 1 or 2 (explained later) methods per notification. So it is a quite simple mapping. The reason for that is that you have one notification per "event" and there is little reason to chance that for delegation.
But your design is good. What is the difference between delegation and notifications? (Robustness is not.)
A delegate is a single instance that customizes the behavior of the delegating instance. Therefore beside the usual "inform" methods (will…, did…) it can have the ability to change the behavior of the delegating, i. e. returning NO as an "invalid marker" (should…) or change the data set, a operation is executed on. (Sometimes this is the 2nd method for an event.) It is obvious that in such cases you cannot have multiple instances at a time. Delegation is in competition with subclassing and often the better choice (white boxing vs. black boxing).
You can have as many notification receivers as you want to. Obviously they cannot change the behavior of the notification sender. Therefore it is the better choice, if you have several instances that only needs an information that an event happened.
If understood your use case correctly, notifications are perfectly fitting your requirements.
I'm not sure this question is strictly limited to iOS, as it's more of a general application-design question on data integrity. But at the moment, I'm getting into iOS and have hit a "best practice" wall.
If we use the Twitter app as an example. We have one tab for our timeline and one tab for our profile. So (to keep things very simple) each one is a View Controller, backed by an object (model). I tweet on the timeline VC, then I head on over to my profile tab. Both viewDidLoad methods have already ran, so the data that was loaded to draw the UI is currently stale. The "count" of my tweets is now out of date. In the iOS world, what is the best methods/approaches to keeping the VC model data synced with the backend?
Is it on a time interval? Or network requests in the viewWillAppear method? Is it event driven, ie. when I tweet in one VC, and it's been saved in the backend web service, I notify any VCs that care that there's a new tweet
I'm not 100% sure this question will have an "answer" in the SO sense, but I'm just trying to understand what's the done thing in the iOS world (as someone who comes from the web development world).
Here's a loose sketch of some things our team has done on a networking application that might give you insight for your own architecture.
At the level of the VC (in viewWillAppear) we typically have multiple NSNotificationCenter observers that will call whatever update methods you need to run after a network update call.
Firing off these notifications is some network listener that lives on a background thread. It's job is to wait for responses from the backend server (typically JSON blobs) that contain updates to the data model. I believe ours has a time interval that will periodically phone home and check to see if we have new things to update.
Note you will necessarily have to devise an asynchronous solution for network calls as the passing/receiving of data packs can be unreliable, and take time, and thus should be computed in the background. You'll also need a way to handle data loss and other errors between server and device. And of course in order to see UI updates, you'll need to switch back to the main thread when updating the VC.
Assuming a some change of state (i.e. new message), then it makes the call to get the new data, which then fires off an NSNotification (with a new payload of info), that goes to the observer on the VC.
As you mentioned with viewWillAppear, UIViewControllers are a core building block of iOS apps. They have a lifecycle to follow to help with things like this scenario.
You have many options, but the best practices would to make calls on the viewWillAppear method and then reload your table views, collection views, etc.
Another thing you can add is push notifications on data change. You can now send a push notification with the "content-available" option that is silent and sent to your app when data changes on the backend. Then your app can refresh data only when needed.
I would stay away from timers. They will keep making network request and keep the radio from going into a battery saving idle mode.
I am building a remote app which is receiving different states of its accessory. It is receiving things like: power state on/off, volume state 5, equalizer setting jazz, etc. and has nothing more to do than map theses states into the UI with selected or unselected states and send changes done back to the accessory.
About the app architecture:
The app is connected with it's accessory as illustrated in Apples EADemo project using the external accessory framework.
The UI is build within non-repeating customized UITableViewCell full of UIButtons. When starting the app a data model class will receive all current states from the examples EADSessionController and has to communicate theses states to the UI (the cells directly rather than the UITableViewController) with one of the mentioned patterns. This will be a stand alone, one-page app looking like a real remote.
Thinking of NSNotification, delegates and KVO (key-value-observing) I am trying to figure out which of these patterns I should use for this special approach?
Any answer on why choosing one of them and a brief description on how to implement would be appreciated. If your answer will be KVO please give some more insights since I never used this pattern so far.
It really depends.
The most loosely coupled one is to use NSNotification and NSNotificationCenter, as the instance which post the notification does not necessarily have knowledge about the observer, and there can be more than one observer.
The delegate pattern is a little more rigid, and there could usually be only one delegate object that receives a message. If the UITableViewController in your project is the only instance that handles a message(, or it would properly propagate the message to other components), it is still OK.
The KVO pattern requires more precisely designed observation relationship. You will have and have to look after exactly how the KVO is implemented. And KVO also allows one-to-many observation. The down side of KVO is if the observing relationship is dynamic and transient, you must take much more care about how these objects were torn down, or you could get a lot of crashes like sending updates to a dealloc'ed instance, etc.
If you are working on a library which would be delivered to a 3rd party to use, perhaps NSNotification would be the first choice.
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
At the above link, I see the following in regards to how the model layer should communicate with the ViewController.
"When a model object changes (for example, new data is received over a network connection), it notifies a controller object, which updates the appropriate view objects."
My question is, how does the model object notify the Controller object? What are various ways this can be done? My model layer gets the user's location and then calls a web service. How should I notify the controller object when that data is downloaded?
There are several ways to do this, depending on your specific case. Generally you would use a protocol/delegate implementation, key value observing, or notifications. There is a pretty good overview here.
Edit:
Thought I should add, as the comment to this answer mentioned: using callback blocks is also a very solid option, depending on your needs. There are a lot of possible deciding factors on what solutions are best for what cases but here is a general outline I follow.
If you are guaranteed to only need one observer at a time: I generally use blocks or delegates. My personal preference is that I use blocks if there are only one or two callbacks because this is where they shine, but I use delegate protocols if there more than a few possible methods.
If you may need multiple observers, I use notifications via NSNotificationCenter.
I use Key-Value-Observing when I only need to observe specific properties on an instance, instead of events.