I have a class that makes multiple asynchronous connections where each connection performs its own logic in the delegate methods.
Because the delegate is the class itself, how can I implement this separation in logic in the NSURLConnection delegate methods?
My vote is for creating a different class for each operation you're doing. It may sound like a lot more work, but your code is going to be a heck of a lot cleaner which will probably lead to less bugs.
March 2014 edit - Don't use the delegate methods, use blocks.
Sounds to me like you need to better represent your objects in terms of object orientation.
You should have one class that manages multiple classes that each manage their own URL connection.
Either check the passed in NSURLConnection against a saved value to see which connection is responsible; or make the delegate different objects; or make the callback behave in a generic manner.
I ran into this problem like this. I have a class that does the same thing. I worked around it by storing each NSURLConnection object in a mutable dictionary instance var with its hash as the key. I then added a cancelAllConnections method in the class and I call it in each view controller's viewDidUnload method. The method removes all the connection objects in the mutable dictionary. Then I added a check in NSURLConnection's connectionDidFinishLoading to check for the hash key in the mutable dictionary. If the hash value doesn't exist, that means the connection was canceled, and the the callback selector won't be performed on a garbage object.
Related
My question is related to this discussion: http://www.cocoabuilder.com/archive/cocoa/202211-how-to-get-nsurl-form-nsurlconnection.html
I am sending several NSURLConnections to transmit data and need to be able to tell which specific connection failed or succeeded. There are NSURLDelegate methods (didFailWithError, etc) which return the related NSURLConnection. The problem is that there is no NSURLRequest returned in the delegate methods (and there is no NSURL accessor in the NSURLConnection).
The solution I've implemented is to maintain a NSMutableDictionary which pairs the URL string that was sent with the result of this NSURLConnection's "hash" method.
I've tested it and it seems to work - the hash of the NSURLConnection that is returned in the delegate method is the same as the hash from the NSURLConnection that was sent initially.
My question: is it safe to do this? Is there a better key to use than the hash? I'm asking because in my naive understanding, the hash is somehow associated with the address of that object in the memory, and it seems possible that backgrounding the app or turning the phone off and on may change this value as things are rewritten to memory.
Thanks very much!
I generally use ASIHTTPRequest, and when issuing multiple connections (concurrently in queue or parallel) I use the userInfo dictionary to pass around context.
The "hash IVAR" you refer to is actually defined in the NSObject protocol - as a method. It is intended to be used in a hash table, and as such should be sufficient for your needs.
I'd still prefer a more first-class approach to this problem, whilst making it more explicit which request is finishing/erroring-out.
Quick question, my data model is a singleton object and it contains a list of names that I want to archive. My idea is to make the model responsible for loading and saving it's own data. The model's load method will be called by the ViewController's viewDidLoad method and save by the ViewController's applicationWillTerminate. I could do the load/save directly within the ViewController, but this would be messy as the list of names are an instance variable of the model.
gary
You could just load and save in the init and dealloc methods (although it's common to call a save method explicitly). It's a good idea to encapsulate it within the model class. If you're loading from the network you might want to have a separate loadData method or something, rather than doing it from init.
Apple recommends using lazy initialization wherever possible, so I think you're heading down the right path, though you might want to consider making the method name something that looks like a property accessor, e.g. -names rather than -load (especially since there's a class method named +load that means something quite different).
I have a class with an NSDictionary attribute. Inside this class I dispatch another thread to handle NSXMLParser handling. Inside my -didStartElement, I access the dictionary in the class (to compare an element found in the XML to one in the dictionary).
At this point I get undefined results. Using NSLog (I'm not advanced in XCode debugging), I see that it bombs around access of the NSDictionary. I tried just iterating the dictionary and dumping the key/values inside the didStartElement and this bombs at different keys each time.
The only thing I can conclude is that something is not kosher that I'm doing with regards to accessing main thread attributes from the secondary thread. I'm somewhat new to multithreading and am not sure what the best protocol is safely access attributes from additional threads.
Thanks all.
I would be surprised if you could access memory used by one thread in another thread unless that dictionary is static/global. I would take one of two approaches, not knowing the intricacies of the iPhone SDK -
Handle all of the dictionary access in the separate thread (population, instantiation, lookups, etc.)
Use some sort of iPhone equivalent of a thread-safe dictionary: link
There are few ways to enable thread-safe access to instances variables in Objective-C. The simplest way is to define your #property declaration as atomic. In this case the auto-generated setters and getters would be synchronized on self.
The other way is to wrap your critical code in a #synchronized block.
The most preferable way would be to create an NSOperation subclass that handles the fetching and parsing, and provides callbacks via delegation or blocks (if you're >= iOS4.0), to notify your consumer that the operation was completed.
Concurrent NSOperations require a bit of boilerplate code in order to get them working correctly, see this (the example is for Snow Leopard, but the concept is the same): http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
I am writing an iPhone application which in numerous places needs to perform non HTTP or FTP networking of a very simple request response type.
I've wrapped all this up into a SimpleQuery class that integrates with the run loop.
SimpleQuery *lookup = [[SimpleQuery alloc] init];
[lookup setDelegate:self];
[lookup doQueryToHost:queryServer port:queryPort query:queryString ];
As you can see the calling object sets itself as a delegate. When the results are complete it then calls a method on the delegate with the results.
[delegate simpleQueryResult:resultString simpleQuery:self];
I am now in a position where I have a user of SimpleQuery that has two types of query so I need to extend SimpleQuery to support this.
I can think of two sensible ways of doing this.
Firstly passing a selector into doQueryString, or a seperate doQueryStringWithSelector.
[lookup doQueryToHost:queryServer port:queryPort query:queryString selector:#SEL ];
Secondly passing a tag into doQueryString so that when the delegate is called it can query the tag, as the simpleQuery is passed, to find out what the results are for.
[lookup doQueryToHost:queryServer port:queryPort query:queryString withTag:tag ];
I'm just wondering which is best from a coding style perspective, the first seems simpler but tagging seems more in keeping with the iPhone SDK and Interface Builder
An option which is used commonly in Apple's code (for example, in UIControl) is to provide both a target object and a selector. This works only if there is a single callback, and is more appropriate than a delegate in that case. (If there are multiple callbacks, then you'll probably have to go with a delegate and the tag approach.)
If you go this route, then you do away with the delegate altogether and instead have a method with a signature like this:
doQueryToHost:(id)queryServer port:(int)queryPort query:(NSString*)queryString target:(id)target action:(SEL)action
Note that "action" is typically preferred over "selector" in methods arguments in this case. The query would simply call the selector on the target when done. This would allow your clients to have multiple selectors, and also multiple target objects; this can help clean up code because you don't need to shove everything into a single delegate object.
If you want to go with your tag route, you should call it "context", which is what Apple uses (for example, in addObserver:forKeyPath:options:context).
There's a third option that's a common pattern in the kits, which is to use #protocols.
For example:
#protocol QueryCompleteHandlerProtocol
- (void)queryType1Complete:(int)intStuff;
- (void)queryType2Complete:(float)floatStuff;
#end
What this does is declare a set of method calls that an object adopting the protocol has to conform to (the compiler will actually enforce this).
So your SimpleQuery object will hold on to something like the delegate pointer, which you might declare like this among the ivars:
NSObject<QueryCompleteHandlerProtocol> *callback;
What this tells the compiler is that callback is an object that descends from NSObject and adopts the QueryCompleteHandlerProtocol protocol. Sometimes you see this written as:
id<QueryCompleteHandlerProtocol> callback;
When you want to call the callback there's nothing special about them, SimpleQuery's methods will just call:
[callback queryType1Complete:1];
[callback queryType2Complete:2.0];
Finally you client for the procotol class will declare itself as adopting the protocol:
#interface MyClass : NSObject<QueryCompleteHandlerProtocol>
...
#end
And will set itself as the callback with some code like:
[lookup setCallback:self];
This is where the compiler checks that MyClass conforms to QueryCompleteHandlerProtocol, meaning it has implemented queryType1Complete: and queryType2Complete:.
I'm not sure I understand the problem here. Can't SimpleQuery's user just set another delegate object for the second query, or branch on the simpleQuery: parameter? That's a basic part of the delegate pattern, just like having two UIActionSheets for one view controller.
I'm looking for a reliable design for handling assignments that have asynchronous requests involved. To further clarify, I have a class which handles Data Management. It is a singleton and contains a lot of top level data for me which is used throughout my iPhone application.
A view controller might do something such as the following:
users = [MySingleton sharedInstance].users;
MySingleton will then override the synthesized users getter and see if it is set. If it is not set, it will speak to a Connection Manager (a wrapper for NSURLConnection and its delegate methods) which fires off an asynchronous request, and this is where problems begin. I cannot guarantee when "users" will be available. I could change the request to synchronous, but that will directly effect user experience, especially in a mobile environment where bandwidth is limited already.
I need to be able to at some point, have some kind of locking/synchronization code going on in my getter that doesn't return users until it is available or is nil.
Once the NSURLConnection has the data available, it needs to callback something/somewhere with a response object and let the getter know the data is available.. whether it's failed or succeeded.
Any suggestions on handling this?
I solved this problem a couple ways in different apps.
One solution is to pass an object and selector along to notify such as:
- (id)getUsersAndNotifyObject:(id)object selector:(SEL)selector
This breaks the nice property behavior however. If you want to keep the methods as properties, have them return immediately, with either cached data or nil. If you need to go out to the network, do so asynchronous and then let the rest of the app know the data changed via KVO or the NSNotificationCenter. (Cocoa Bindings would be an option on the Mac, but they don't exist on iPhone).
The two methods are fairly similar. Register for updates with your shared instance, and then ask for the data. KVO is a little lighter weight if you just dealing with raw observable properties, but an NSNotification might be more convenient if you're interested in several different pieces of data.
With an NSNotification, the client object could register for one type of notification which includes the changed data in its userInfo dictionary instead of having to register obvservers for every single key path you're interested in.
An NSNotification would also allow you to pass back failures or other status information a lot more easily than straight KVO.
KVO method:
// register observer first so you don't miss an update
[[MySingleton sharedInstance] addObserver:self
forKeyPath:#"users"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
context:&kvo_users_context];
users = [MySingleton sharedInstance].users;
// implement appropriate observeValueForKeyPath:ofObject:change:context: method
NSNotification Method:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(sharedDataChanged:)
name:MySingletonDataUpdatedNotification
object:[MySingletonDataUpdatedNotification sharedInstance]];
users = [MySingleton sharedInstance].users;
// implement appropriate sharedDataChanged: method
You can either use a delegate pattern or a notification pattern here.
A delegate would let a particular object know when users is complete, a notification pattern would notify any object that wants to know. Both are valid, depending on your situation.
Just remember: if you have any race issues in your app, your architecture is probably all wrong.
It took me a while to realize what the best way of handling this kind of typical task; it turns out the clue is in the design of many of Cocoa and CocoaTouch's own APIs: delegation.
The reason so many of Cocoa's APIs use delegation is because it fits very well with the asynchronous nature of many GUI apps.
It seems perfectly normal to want do do something along the lines of:
users = [MyDataFactory getUsers];
Except, as you point out, you have no idea when the getUsers method will finish. Now, there are some light-weight solutions to this; amrox mentioned a few in his post above (personally I'd say notifications aren't such a good fit but the object:selector: pattern is reasonable), but if you are doing this kind of thing a lot the delegation pattern tends to yield a more elegant solution.
I'll try to explain by way of an example of how I do things in my application.
Let's say we have a domain class, Recipe. Recipes are fetched from a web service. I typically have a series of repository classes, one for each entity in my model. A repository class' responsibility is to fetch the data required for the entity (or a collection of them), use that data to construct the objects, and then pass those objects onto something else to make use of them (typically a controller or data source).
My RecipeRepository interface might look something like this:
#interface RecipeRepository {}
- (void)initWithDelegate:(id)aDelegate;
- (void)findAllRecipes;
- (void)findRecipeById:(NSUInteger)anId;
#end
I'd then define a protocol for my delegate; now, this can be done as an informal or formal protocol, there are pros and cons of each approach that aren't relevant to this answer. I'll go with a formal approach:
#protocol RepositoryDelegateProtocol
- (void)repository:(id)repository didRetrieveEntityCollection:(NSArray *)collection;
- (void)repository:(id)repository didRetrieveEntity:(id)entity;
#end
You'll notice I've gone for a generic approach; you will likely have multiple XXXRepository classes in your app and each will use the same protocol (you may also choose to extract a base EntityRepository class that encapsulates some common logic).
Now, to use this in a controller, for example, where you previous would have done something such as:
- (void)viewDidLoad
{
self.users = [MySingleton getUsers];
[self.view setNeedsDisplay];
}
You would do something like this:
- (void)viewDidLoad
{
if(self.repository == nil) { // just some simple lazy loading, we only need one repository instance
self.repository = [[[RecipeRepository alloc] initWithDelegate:self] autorelease];
}
[self.repository findAllRecipes];
}
- (void)repository:(id)repository didRetrieveEntityCollection:(NSArray *)collection;
{
self.users = collection;
[self.view setNeedsDisplay];
}
You could even extend this further to display some kind of "loading" notice with an additional delegate method:
#protocol RepositoryDelegateProtocol
- (void)repositoryWillLoadEntities:(id)repository;
#end
// in your controller
- (void)repositoryWillLoadEntities:(id)repository;
{
[self showLoadingView]; // etc.
}
Another thing about this design is that your repository classes really don't need to be singletons - they can be instantiated wherever you need them. They may deal with some kind of singleton connection manager but at this layer of abstraction a singleton is unnecessary (and its always good to avoid singletons where possible).
There is a downside to this approach; you may find you need layers of delegation at each level. For instance, your repositories may interact with some kind of connection object which does the actual asynchronous data loading; the repository might interact with the connection object using it's own delegation protocol.
As a result you might find you have to "bubble up" these delegation events throughout the different layers of your application using delegates that get more and more coarse-grained as they get closer to your application-level code. This can create a layer of indirection that can make your code harder to follow.
Anyway, this is my first answer on SO, I hope its been helpful.