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.
Related
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.
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.
Background:
I am in the early stages of an an iPhone App and REST WebService product. Basically, I have a database on the a server and have written some REST APIs to access this database. I have a companion iphone app that will consume these REST APIs.
Questions:
What is the best approach to place the code for accessing the REST Apis? Should I create a separate subclass of NSObject and place the interface and implementation details there? I would like to reduce the amount of code duplication throughout the application in the various ViewControllers that would interact with the REST API.
For Example:
My app would start up and make a REST API call to determine the current state of local information on the device by comparing the value returned from the API vs local. Then I would initiate an update request from the API to refresh the local datastore.
Now if I have all of this logic in the start-up ViewController I have multiple calls using NSURLConnection which only has on delegate. I don't know how to make these separate calls in the same ViewController.
What are some approaches to solving this problem?
I generally create custom objects which use ASIHTTPRequest (using composition, not subclassing) which can be initialised with any required parameters, and use that to manage requests to the RESTful service. The custom object will provide a delegate protocol for handling success, failure and other custom notifications so that I can use this feedback to update the application UI while the request is performed asynchronously.
If you need to parse large amount of data returned from a request, make sure you launch a separate thread to do this, rather than doing it in your HTTP request success callback, otherwise this will keep the network activity spinner active longer than it actually should be.
If you need to manage multiple requests of the same type, you could add a "tag" property to your custom request, so that when your success/failure delegate response is called, you can easily identify which request it belongs to without having to keep an instance variable to the original request.
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.
hi i am developing a sms App for my client. so far i have put down this plan in place.
1)The app keeps polling the server with an asynchronous request so that it does not interfere with the user interface.
2) for sending sms i am currently using synchronous request , depending on the reply from server i have do various things. i am showing the spinning circle and make the user wait until i get the response from server.
my client has problem with point 2.
The client says as soon as the send sms button is clicked it has to go back to the homescreen and should be able to navigate to any screen and do all other things that the app offers. i could have used async request , but i am not sure how to handle the responses from the server when i am on different view controller other than the one request is called from.
Can somebody help me on this.
Thank You.
The classic way of handling the response of an asynchronous action is either using delegation or notifications. Do not use a singleton. This breaks modularity and decoupling of different view controllers.
Roadmap of how to handle asynchronous actions
Register for the response of the asynchronous actions. This can be setting the delegate of the requesting object e.g. NSURLConnection to the view controller, which is typically self in this context. The othe possibility is that you register for the notification which is fired by the requesting object if things have happend e.g. when a download is finished or an error occurred.
Implement the delegate methods or the notifications to update your model and/or your user interface. Be aware that updating the UI has to happen on your main thread.
Start the asynchronous action. What happens in the background is that a separate thread is spawned or an operation is dispatched using GCD. These are implementation details and do not bother you.
Wait for the answer, which will result in one of your implemented methods to be executed which you then use to update what has changed.
Difference between notifications and delegates
The two differences between delegates and notifications is that delegate is a one-to-one connection between the delegate and the delegating object. Notifications are posted application wide and can be observed by as many objects as needed creating a one-to-many connection. Think about this as a broadcast. The second main difference is that delegation can be used to transfer information back from the delegate to the delegating object. Meaning that the delegating object asks the delegate for certain information. Typical example would be the data source of an UITableView. Notifications however are a one way street. The information flows from the posting object to the observing objects. This makes sense because think about the situation where you would have more than one observer and each would give feedback to the posting objects. Which one would be the right one?
In your case you would have to look up the delegate methods of the asynchronous HTTP request object and implement them accordingly.
Maybe you can try ASIHTTpRequest , It has Sync an Async request
If you using Async request , you can do anything after you press a button to do a request .
Check this
The solution depends on the response processing.... if you are just showing user that the sms sending is failed/successful than you can do it in any general utility class that shows alert.. but for this you have to create the singletone instance of your connection class so delegate(class itself) don't die when the response comes back.......
For this we need to keep track of currentViewController ....... we can do this by creating a reference ........ id currentViewController in appDelegate(with setter/getters).......... so it could be accessible in everywhere application........
its referred object should be changed each time when user changes the viewController.... that will help us to know on which viewController user is currently working.
than when the singeltone class of connection finished its response loading we can use this currentViewController with your desired viewController.
I am not sure how you are using different view controller....... pushing it/ presenting it or adding its view.....