Should I have all my web service code in my view controller - iphone

I have noticed that with iPhone programming you kind of need to retrieve your data from within the ViewController because of the way the data is retrieved.
e.g.: ViewDidLoad is called. You start retrieving the data and then when its finished a message is sent to your viewcontroller e.g. requestFinished and this is where you configure/refresh your UI.
The problem that I have with this approach is that I have a bunch of web service code and XML building and parsing all in my view controller.
Does anyone know if this is the correct approach or is there a better way to do this.
In .NET I would have classes specifically for retrieving data from webservices and I would simply call the web service to fetch the data and I could use the same web service at various places inside my app.

There is no reason to do that different in Objective-C/Cocoa. You should create a class that handles the web service and notifies the view controller when data is available.

No, it absolutely isn't the correct approach. The key to this is the MVC paradigm, - model, view, controller - your data classes are perfectly suited to being the M = model so put all your data handling code inside a dedicated model class.
Because the url handling is hopefully asynchronous, your model will still need to inform your view controller when various events have taken place. You have a couple of choices here but the most appropriate is probably to use a delegate pattern so that the model can basically initiate a call back to the view controller when it has data that needs displaying etc.
(The other approach would be to use notifications which is less tightly coupled, and perfectly viable in this scenario, but delegates would be more appropriate).

Well you could create a parse that will parse your XML in a seprate class, and even your http request can be in a seprate class.
There is no need to do every thing in the the on viewcontroller.
Just be sure to create delegate or use the notification center if you are using threads. Set the delegate on either the request or parse to nil if the view controller get unloaded.

Related

Get WKInterfaceController reference while pushing interfaceController

I have a Dashboard Controller in Apple watch and I am navigating to next WKInterfaceController without using Segue.
pushControllerWithName("Messages_Detail",context: ["Data": messageDetailData])
Now I need to pass data from Dashboard to Messages_Detail later on after it has been loaded. I don't have any reference of it in Dashboard. How can I pass data to it?
Here you have a regular task of passing data between controllers and it is not a Watch-specific task generally speaking. Actually you need to send data back (with sending data forward you're already OK). I see 2 ways to solve your task depending on the current implementation:
Use the Messages_Detail controller as a delegate of the Dashboard one. You also should define some protocol that will describe which methods of the Messages_Detail are available to call in a delegate context.
Use NSNotificationCenter or any other implementation of a Pub/Sub pattern to provide communication of different parts of your app. In this case your Dashboard will post notifications which the Messages_Detail controller will observe.

iPhone - Architecture for viewController and network requests

So, I have 2 types of data, some needs to be persisted and some doesn't.
I'm thinking about where to put all my network related code, inside my UIViewControllers, where all the network request start from, or in a another layer.
What I had in mind is this:
Have a layer called NetworkManager.
NetworkManager is singerlton to all my web service calls.
For data that needs to be persistent and can be presented in a list, I would have network manager issues the request, save the response in my local core data DB, and have my UIViewController listen to that data using FetchResultsController.
But, there's many other types of requests. For example : login request, user info request, friendsNearBy, and so on… some don't have to be persistent in my db, and some don't fit the FRC architecture.
For these type of request, as far as I see, there are 2 ways of handling it:
1. Have another layer that separates between the ViewControllers and the NetworkManager.
Let's call it Mediator. The Mediator gets the dictionary(JSON) request from the networkManager, decides according to the app logic if there's anything else needs to be done with it, and then post a notification with appropriate name and data. If the mediator saves the UIViewController who issued the request, it can delegate the response directly to him instead of posting a notification.
The Flow would be like this:
MyUiViewController - > Mediator -> NetworkManger->Mediator-> PostNotification (or directly back to MyUiViewController)
Pros:
Decoupling
Nice structure and separation of concerns
Cons:
Harder to code
Sometimes harder to understand and debug.
2. Not having this 3 layered architecture, but instead having MyUiViewControllers, issue a network request with blocks. Meaning instead of the Mediator intercepting the response before MyUiViewController, just let MyUiViewController handle the response using blocks as he is the one that issues it.
Pros:
Simple and quick to code
Easy to understand
Cons:
Coupling of network code inside your controllers
I was hoping to get suggestions and comments about what's best from people's experience, or other/better way of doing this.
Have you got whats the best method already?
Here's what i do generally,
Have a NetworkManager which is not Singleton. Define a protocol with method OnSuccess,OnError. Implement this in your ViewController which initiates the network connection. Set the delegate on NetworkManager and let delegate be called when Asynchronous request is executed.
Use delegates instead of blocks as its easy to maintain.
This may not be best solution, but hopefully it gives you some pointers.
I recommend option 2 with a little bit of what you listed for option 1. In my apps I tend to have two distinct modes of operation that operate concurrently.
Automatic downloads:
App essential data is downloaded and saved directly to the database. It's initiated each time the app becomes active. As each request completes an NSNotification is sent out for any visible view controllers that may need to know about the new data.
For example, if I save player data I'll send a notification like "PlayerDataUpdated". When a view controller is visible it listens for notifications. When it's not visible it doesn't listen for notifications since any changes in to the database will be discovered during viewWillAppear.
User Initiated downloads:
For user-initiated network requests, such as pull to refresh, you should call the appropriate method on NetworkManager from the view controller that needs the updated data.

Delegates and Notifications in Objective-C

In my AppDelegate, I download some data from a JSON feed. I am downloading a now/next/later schedule for a few channels. I have three different view controllers for each now, next and later. In each view controller, a user can add/remove the channels so when that happens, the newly added channel data has to be downloaded again.
Since the data is downloaded in the AppDelegate and stored there, how would I pass it to the three view controllers? Should I implement three separate delegates? Keep in mind that when adding a new channel, its data has to be downloaded again (which I am doing outside the AppDelegate now).
Any help please?
Thanks
This is basically a matter of style and your approach isn't invalid as such.
I'd do it another way, though - the AppDelegate is not meant to be used as a workhorse and having several AppDelegates at the same time is simply impossible.
Here are some thoughts about how this could be done (though it's of course not the only proper way):
First, I'd employ Core Data or some other sort of storage which is available from anywhere within your app.
Then maybe I'd introduce some sort of "data controller" class (maybe a singleton). This class should handle both download of data and the distribution of that data to your viewcontrollers as requested.
By having one central controller for that purpose, you'd ensure that data gets downloaded only once because the controller knows exactly which data is already in stock.
Your viewcontrollers would neither be responsible for managing downloads anymore nor would they access the data on disk by themselves. They'd just make a request to your data controller and get a callback when the requested data is available - no matter if it was on disk already or has been downloaded for the occasion.
This keeps your VCs slim and focused and reduces the pain of making changes to your interface.
Toastor's answer is correct and as he says, there are several ways to do this. One is to call a data access class and change the values OR listen for changes on the values. For the later, the Key-Value Observing Programming Guide says the following:
KVO is particularly useful for communication between model and
controller layers in an application.
A controller object typically observes properties of model
objects, and a view object observes properties of model objects
through a controller.
In addition, however, a model object may observe other model
objects (usually to determine when a dependent value changes) or even
itself (again to determine when a dependent value changes).
Another is to make the dependency explicit, maybe passing a data access class saved in your app delegate. See Object-oriented design question, iPhone.

How does one communicate between view controllers in a UINavigation type application?

I have a UINavigation based application that gathers information on various screens and eventually makes a web service request using all the parameters collected.
So I have A,B,C,D view controllers. A gets the name & number, it then pushes B onto the screen with some basic info ETC ETC until it gets to D where I actually fire off the web service.
The poor method I have been using is to duplicate class fields from A onwards. Meaning if I collect name, and number, then I make those the fields of B, which then adds a few fields, and then C has class fields of both A & B which seems like a poor programing practice.
What can I do to get access to class A's fields in class D? I have gotten certain ideas but not sure how valid they are.
1). Use NSNotification (Is this overkill?) If so how do I pass fields?
2). DO I just retain all 5 view controllers and just get the info at the end? (seems very inefficient)
3). Should I just instantiate a NSObject class called Payload and just set its fields every time I bounce from one view controller to the next? (If so do I create it in class A? What if user navigates back to class A, will it then get reset ETC ETC)
As you can tell I have tried to find a solution and I am fairly new to it. Some detailed suggestions would be highly appreciated.
Depending on situation, there are several ways that seem appropriate.
Get to know MVC Design Pattern
Classes are not data storage. If class doesn't have interface to interact with represented object, excluding accessors, you're doing it wrong.
3.
I have a UINavigation based
application that gathers information
on various screens and eventually
makes a web service request using all
the parameters collected.
So, your web request is based on parameters gathered from various views. Why not create an
model of said request? MyRequest or something like that :) Or several more specific variants, sharing common parent class? This generator holds logic, gathers data and parameters as you advance trough views and provides NSUrlRequest at the end to WebView or maybe different kind of object which is NSURLRequest delegate and conforms to UITableViewDataSource/Delegate protocols to be used to display downloaded data.
I'd go for 3) and yes you should create it at the beginning (Class A).
But maybe user go back to Class A to change the value on purpose so resetting it doesn't seem to be a problem.
Why not use a singleton object and pass it around?
The advantages of this method are:
There's only one instance whose
reference is being passed around
between viewcontrollers
Changes you
make are reflected the next time you
access this object from another view
controller
And to answer one of your questions, NSNotification allows us to pass objects along....
Here's a good example on singleton objects in iOS by Matt Galloway. It's the one I always refer to:
http://www.galloway.me.uk/tutorials/singleton-classes/

How to communicate between classes when both data and UI are involved?

I'm working on a largely navigation-based iPhone app that communicates with a REST API using OAuth, and I'd like to know how my classes should best communicate with each other. I've got multiple UITableViews, multiple UITableViewDataSources, an API class, and a view controller that handles authentication in a web view.
Here's how I have things structured now:
My UIApplicationDelegate owns an instance of the class that knows how to communicate with the REST API
I can ask the API class to call a REST method, and it returns with the data (it wraps ASIHTTPRequests to handle OAuth transparently, so it doesn't currently know which object asked for the data)
If the user isn't authenticated, I can ask the API class to initiate the OAuth process
The OAuth dialog can be presented, and the application granted access to the API on the user's behalf
The trouble I'm running into is that my UITableViewDataSources need to communicate with the API class to fetch their data, but authentication might need to happen first, which involves a modal authentication view presented by a view controller.
Would it be better to have each UITableViewDataSource model own its own instance of the API class, or should the API class be a singleton?
If each model owns an instance of the API class, how should it communicate to the view controller that authentication needs to happen?
If the API class is a singleton, how should it interact with multiple models and view controllers to present the authentication dialog? Delegates for each? Post NSNotifications?
Some other way I haven't thought of?
Really, I think the core of the problem is that I have one class that's primarily used for data fetching purposes, but it might need user interaction to do so successfully.
I typically use a singleton exactly in the way you describe and it works well. Here is how I would answer your questions.
Singleton
N/A. Use a singleton.
Notifications work well, but I tend to prefer to pass a delegate with each request and then keep a hold of it inside the singleton until the request has finished at which point I just call back to the delegate with a success or failure message. Notifications can get pretty messy if you have multiple view controllers that are live in your navigation stack all potentially listening and responding depending. I've seen that introduce some really weird bugs. If you're careful, notifications work just fine, but passing a delegate allows you to associate a specific delegate, typically the current view controller, with a specific request which is often ideal.
I think you're on the right track.