When using async download methods and delegates, is it possible to start multiple simultaneous nsconnections and handle them separately as each query completes? Or, will the system not automatically distinguish between them as your delegates receive pieces from each query? In which case, what would be a good approach to identify each connection uniquely as it enters through the delegates?
The system won't automatically distinguish the NSURLConnections, instead, each delegate methods called is precising the concerned connection.
For example : - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
the connection is connection. This way you can set several NSURLConnections and react accordingly.
I personnaly set NSURLConnection objects as ivars and test for equality in delegate methods, because using delegate, you will need to access the data containers from different methods.
You will find more information in the excellent URL Loading System Programming Guide from Apple.
Related
I'll first of all point out that i need advice and not code samples here. I know how to do the code...
I'm in a project where i feel the need to refactor a singleton class with (in my opinion) excessive use of delegations.
The state is that there are two classes, a singleton class "Manager" and another class "BackendManager". These two do most of the entire app's client-server communication as well as a some application logic.
The application is built up of a login, a menu, and some different functions. All these functions are completely independent, one could be a google map showing some business locations and another could be a calendar showing which meetings the user has. The only connection between these to functions is the login itself. This tells me for sure i need to take the code in the "Manager" and "BackendManager" classes related to the map and put in one place and the stuff for the calendar and put another place. And the same for all the other functions. Furthermore take the login and menu functionality and put somewhere else.
The thing i'm unsure about is whether or not to keep the delegation pattern for all these methods or replace some of it with notifications. The reason is that it's currently a big mess. The "Manager" has a "ManagerDelegate" protocol. It's obvious that this protocol has just gotten bigger and bigger in time. First it defines some login methods, for example
- (void)loginSuccess;
then it defines some maps functions
- (void)backendManagerDidLoadLocationTypes:(NSArray*)locationTypes;
- (void)backendManagerDidLoadLocations:(NSArray*)locations;
- (void)backendManagerDidLoadUserLocatios:(CLLocation*)location;
- (void)backendManagerDidLoadSearchResults:(NSArray*)results;
...
then some calendar functions
- (void)backendManagerDidLoadEvents:(NSArray*)events
- (void)backendManagerDidLoadEventTypes:(NSArray*)eventTypes
...
this of course goes on for all functions developed for the menu, as mentioned these are all independent of eachother.
You can imagine the "BackendManager" is just a convenience class for doing the actual fetching of data for rest services. It is done so the "BackendManager" roughly defines all the same methods as the "Manager", for example for the login functionality:
*Manager*
-(void)userLogin:(NSString*)username pin:(NSString*)pin
-(void)backendUserLogInSuccesCallBack:(BackendManager *)controller
*BackendManager*
-(void)userLogIn:(NSString*)username pin:(NSString*)pin
//Same for all other functions in both classes
So the "Manager" just calls the "BackendManager" and then the "BackendManager" will callback the "Manager" which will call the actual controller from where the call originated, for example LoginViewController. This makes the "Manager" superflous and just an annoying class to always go though when trying to understand the code.
Anyway, after walking through all this logic heres what i plan to do:
Build a model class for every function in the app.
LoginModel
MenuModel
MapModel
CalendarModel
...
These will all be singletons and i'll probably make a class to help doing the service-calls, but parsing of the response and other logic will be in the Models themselves for now.
So the question is - does this sound like the right approach, and am i right in thinking that it would be correct take the calls from "Manager" to the controllers, which are currently done using delegation and change them to use notification pattern (NSNotificationCenter), the calls corresponding to these would now be done in for example the LoginModel where is would throw a notification when logged in. The LoginViewController would then be listening for this notification.
The change to notifications is mostly based on the MVC model teached in the Stanford lessons, here i interpret that the delegation pattern is mostly used when communicating between Controllers and Views, and notifications of KVO is used when communicating from the Model to the controller.
This means that now, instead of sending userdata back from the "Manager" to the controller like
- (void)backendManagerDidLoadLocationTypes:(NSArray*)locationTypes;
above, I will throw a notification when they have been fetched and the controller will then fetch the locationtypes from the model using a different call. This would give me two calls in the Model, one to "update" the locationTypes (from server) and one to "get" them (locally). So maybe these types of calls are the ones where i should stick to the delegation pattern? Even though i'd rather use delegation only between views and controllers.
First off, this question is more suited for programmers.stackexchange.com, but I'll give you a quick answer here.
I like the approach of using notifications application level events. UserDidLogin and LocationDidChange are good examples. These events signal a change that all view controllers will want to know about.
I would avoid singletons. Usually view controllers can exchange data in -prepareForSegue:sender: or however you create your child view controllers.
As far as notifications for completed network events with update and get methods: I would avoid this. Always ask for the data using some async method (I prefer completion blocks), let the model take care of when to use a cached copy and when to update from the server.
I would also recommend splitting the control of access to model data from the model. People sometimes label this as a manger pattern, a factory pattern, or a data source pattern, but it all amounts to the same thing. Have a separate object which knows how to fetch data for one particle model. That object will return back fully formed model data.
For example, have a locationTypeDataSource object. The view controller requests location type data from this data source. The data source thens tells the view controller when the data is ready. This could be reported as a notification, KVO, or completion block.
Notification:
[self addObserverForName:LocationTypeDidLoad object:self.locationTypeDataSource queue:nil usingBlock:^(NSNotification *note) {
[self.tableView refreshData]; // or whatever
}
[self.locationTypeDataSource fetchLocationTypes];
KVO:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"locationTypeDataSource.locationTypes"]) {
[self.tableView refreshData]; // or whatever
}
}
[self addObserver:self forKeyPath:#"locationTypeDataSource.locationTypes" options:0 context:NULL];
[self.locationTypeDataSource fetchLocationTypes];
Completion Block:
[self.locationTypesDataSource fetchLocationTypesWithCompletion:^(NSArray *locationTypes, NSError *error){
[self.tableView refreshData]; // or whatever
}];
The key is to use a separate object to fetch and prepare model data.
I want to implement a webservice client in iOS which uses SOAP and XML for requests/responses.
My view starts the initial businnes logic (a user presses a button or something and initiates some businnes method called method_A).
So I have a class with method_A and this method checks if the user is logged in etc and then starts the request asynchronous via the SOAPConnector-class. So the UI is not blocked (asynchronous).
The SOAPConnector-class takes the XML and handles the requests. I use therefore NSURLRequest and NSURLConnection with sendSynchronousRequest.
The response is sended back to a Response-class which takes the response. This class then wants to parse the response XML. Therefore I use an extra class called XMLManager which uses NSXMLParser to parse the xml. But again here we need a delegate which gets the parsed xml. And again after parsing I have to implement an extra method to give back the parsed xml to the first class which initiated the request.
I am really wondering if this is the right way. The first problem is asnychronous request to not block the UI (the first callback). The second problem is the parsing where I am forced to use the delegate (the second callback). This results in a lot of classes and methods and I doubt this is the right way. The classes' only purpose is to manage the delegate and async problems. So I am asking for any suggestions and help how to solve this. Do you know some good design patterns to solve this problem?
Apart from some inconsistencies in the way you describe the design patterns you've selected:
and then starts the request asynchronous
vs.
I use therefore NSURLRequest and NSURLConnection with
sendSynchronousRequest.
That said, your approach seems sound. Addressing the issues you've identified:
I use therefore NSURLRequest and NSURLConnection with
sendSynchronousRequest.
Isn't that the purpose of using an asynchronous API? If your NSURLConnection is really operating asynchronously, that issue should be covered.
The second problem is the parsing where I am forced to use the
delegate
This approach does result in more classes, delegation, etc. but it conforms to best practices when it comes to testing. If you are performing unit testing or other testing strategies (you are aren't you?) then testing in isolation is all the harder unless you breakdown this process functionally.
If you have access to the book Test-Drive iOS Development there is a great section on the best practices for consuming web services with a view toward testability.
I have created objects that are interfaces to a web service. One typical object would be a "TaskService". When a client uses one of these objects, it invokes one of the service's methods (such as "GetTasks") and the service will asynchronously go off to call the remote web service, and post back the retrieved data via a delegate.
Currently, to use one of these services you have to create it with [[TaskService alloc] init], but I decided it makes more sense to make each service into a singleton object.
Is it common to see singleton objects that hold reference to delegates? My main issue with the design, is that each object, whenever it requires use of a particular service, will have to set itself as the delegate before invoking the service, which doesn't seem quite right to me... What if another object were to set itself as the delegate inbetween you setting yourself as the delegate and invoking the service?
Many thanks in advance!
Regards,
Nick
Imo this is not a good idea for the reason you cited. The Singleton pattern is really for things there are only one of, but it sounds like your app can have need for multiple instances of these services. I think you'd wind up working around this (using an operations queue or some kind of delegate multiplexer) when you really just need to instantiate multiple instances of your service.
When the occasion warrants the use of a Singleton object, I always avoid delegation for the reason you cite. Consumers of a singleton can't know (without some ugly coding) if they're stepping on some other consumer's toes by setting themselves as the one-and-only delegate of the singleton. NSNotifications are a much cleaner tool for the job; any arbitrary number of listeners can consume the notifications without caring who else may be listening.
Delegation works best when there is clear ownership between the classes. Nobody owns a singleton.
Singleton isn't really the problem, you cause the same sort of issues by simply instancing a class and passing it about as a global variable.
As other's have mentioned a queue is a possibility, or when you invoke a task on a service in your Singleton have it instance a TaskRequest object passing in the method and the call back delegate, that way requests can't trample on each other. In fact it would be a good idea to do that with a queue anyway.
The scope of a singleton is entire application. For example: Let consider the example of shopping application the logger data, about the user ID which need to be accessible on different part of application like order, payment, cart etc.
Delegates are used for 1 to 1 communication, for example: You can take as example You have two classes TV and remote control device. You want to change the channel of TV. Delegate methods of TV for changing channel are implemented in remote control device class. So you use remote control device and you change the channel of the TV.
The singleton is used to communicate with multiple receivers, while the delegation pattern is used usually for 1 to 1 communication.
I am using Distributed Objects (DO) in Objective-C. I have a "server" object that I have vended on the network. Other objects on the network have a proxy to my server object and can thus call methods on the server object. However, can I determine any information about the objects that are calling methods on the server object? That is, I have many "client" objects that can call the server and I would like to distinguish these objects. Also, can I determine other attributes about these objects, e.g., host name, unique identifier?
I had a similar problem. I found that a possible way to identify clients is to have them pass some kind of token object through to the server as part of each call. On the server you can do:
NSConnection* clientConnection = [passedTokenObject connectionForProxy];
This will get you a handle on the connection, which will be unique to each client. Whether or not you can get the information you need depends on what Apple allows you to do with that connection object.
In my application, I had clients first do a "registration" call that I used to gather the information I needed about them.
The other thing that might be useful is to become NSConnectionDelegate for the NSConnection that you use to vend your server object. This will give you access to these methods:
- (BOOL)connection:(NSConnection *)parentConnection shouldMakeNewConnection:(NSConnection *)newConnnection {
// You can inspect new connection being established here and maybe glean info about the client
return YES;
}
- (BOOL) connection:(NSConnection *)c handleRequest:(NSDistantObjectRequest*)doReq {
// You get to see every method that is invoked here and can maybe glean info that you need.
// Returning NO means you're just snooping on the call and it will be handled in the normal way.
return NO;
}
The available "tools" aren't very sufficient I have found and I needed to rework my vended API to help provide the information I needed.
I found that the most effective solution to this problem is to explicitly pass a reference to the calling object as, say, the first parameter of the method. That way, the calling object can be easily identified and even called back if necessary. The resulting argument is of type NSDistantObject *.
OK, I am building an application that will be using ASIHttpRequest in several places to either get JSON data from a web service or will be posting to a web service. I have it working, but really don't like having several instantiations of the request object sprinkled around the different view controllers (Login view controller, a tableview controller, and a detail view controller. I would like to move all my ASIHttpRequest methods to one class and just get back a dictionary of values that came back from the web service. The problem with this is that the delegate methods don't return that I need to have returned.
What would be some suggestions on how I can consolidate all the methods that will create an HTTPRequest and return values when the request is finished.
I can post code if need be, but this is really more of a general question and not a specific issue. If there are any tutorials on how this should be done, I would appreciate it. I want my code to be efficient and pretty :)
Thanks!
Your problem is going to be asynchronousity. I'm not sure what you mean by consolidate, but you can have a singleton (you can just use your app delegate) to call the requests. So you would do something like this:
[(MyAppDelegateClass *)[UIApplication sharedApplication].delegate doLoginStuff:(NSDictionary *)params delegate:self];
If you're doing all this asynchronously, you can't just call this method and have it return something. You'll be stuck with having some sort of callback to your view controller, which is the way ASI works out of the box essentially. At best, you can minimize the code to generate the request and set any repetitive properties.
I'm not sure what you mean by having the instantiations floating throughout. If it's memory you're worried about, it would be no different reusing the same object. ASI typically uses an autoreleased request, so it would be the same as creating it in a "consolidated" method. If it's just clean code, I would do a singleton way and maybe make a shortcut c-based method call in some type of Utilities class that you create and import in with your prefix file. But again, you need the callback methods in your view controller so it doesn't get too much cleaner than it already is meant to work. I share your pain though.
When any request comes back, I almost always have a method that parses the results. Typically I'm only working with one type of web service, so have a method that parses the results and (also logs it to NSLog for debugging purposes) also gives me back an NSDictionary or NSArray.