How can I avoid data corruption with multiple instances of NSUrlConnection - cocoa-touch

I have written an iOS app that calls NSUrlConnection multiple times to download image data from the web. Sometimes, one NSUrlConnection has not finished before the other starts. I am seeing corrupt jpeg data and I think it is because my didReceiveData delegate is saving data from two separate NSUrlConnections and munging the two jpeg data streams together into one data variable, hence causing the corruption.
My question is: what is the best way to avoid this? There doesn't seem to be a way to make each NSUrlConnection instance save to a separate data variable, or make each instance wait until the previous instance is done before saving.
My code basically follows Apple's example here except I call a loadData function multiple times which creates the NSURLRequest and NSURLConnection. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
Thanks in advance for any help.

When your delegate's connection:didReceiveData: method is called, you'll have the connection instance as the first parameter. So you'll need to use that to keep track of which connection just received data.
Apple's sample maintains one instance of NSMutableData. Your code will require several instances, one for each active connection.
Or, of course, you could have a separate delegate object (an individual instance) for each connection. That may be easier.

Related

Return result of asynchronous call to the method the called it

I'm writing a standard NSURLConnection class for the App I'm working on right now which I will hopefully be able to use subsequent apps as well.
The idea is to able to pass a URL and a parameters array to a method in this class that will start the connection and then have it return the result when it is done.
-(NSData*)go :(NSString*)url :(NSArray)params
Since I'm calling this from another class I'd like to be able to set the result to a variable in that calling class.
NSData *result = [[connect alloc]go:testurl :testparams];
The problem is that the result doesn't arrive right away so when I return the NSData I have set in the "go" method it is blank.
I've tried a few things like NSCondition and running a while loop on another thread in the go method to check if it was finished.
Unfortunately, and I did not know this beforehand, the asynchronous connections form NSURLConnections run on the same thread as my NSCondition in the "go" method ran on. Because of this when I locked up that method so it didn't return early, I also locked up my connection so it never reached it's completion callback.
How can I effectively pause my "go" method long enough for my connection to finish so I can return the data to anywhere in my app.
There's a chance I'm going about this the completely wrong way so please let me know if that is the case. It does need to work kind of like this though because multiple requests will be going out at the same time and I'd like different instances of this connection class to be able to control them all.

simultaneous NSURLConnection by using unique delegates for each NSURLConnection

I am try to handle multiple NSURLConnection at the same time by using a different delegate for each connection, for each NSURLConnection I create, I create a new delegate object, but for some reason only one NSURLConnection works at a time, any NSURLConnection I try to start whilst one is already running simply do not start, my delegate does not receive any of the method calls connection:didReceiveResponse:, connection:didReceiveData:, connectionDidFinishLoading: or connection:didFailWithError:. Am I misunderstanding something about how NSURLConnection and its delegate works. Reading other posts most people seem to have a single delegate for all there connections and then use some kind of dictionary to get the right object to handle the right connection. Is that the way you have to do it.
What you are describing should work fine. You can have multiple NSURLConnections in flight at once, each with its own delegate.
If you want to know why your case isn't working, you'll probably need to show your code in your question.
I hope that at least answers the general question.

Which NSURLConnection wrapper handles GET and POST equally well?

Which NSURLConnection wrapper handles GET and POST equally well ?
For GET method, I prefer google's GTMHTTPFetcher over ASIHTTPRequest. ASIHTTPRequest uses delegate, which probably the idea you will come up with normally. But that's the exactly reason I chose not to use it because when you have several connections(many connections in my case), then each connection has its own delegate and you end up with too many object. Or you can have just 1 delegate but you have find a way to find out which response is for which connection.
GTMHTTPFetcher handle this way much better in my opinion. It uses 1 SEL for 1 connection, sorta like target-action model. The code is much cleaner than delegate model.
But for POST method, ASIHTTPRequest has ASIFormDataRequest. I did not find an easy way to do POST with GTMHTTPFetcher. It does have setPostData method to set post data. But you have to set post body and those mime parameters by yourselves(from what I have see) And that's the headache. I find it has another class called GTMHTTPUploadFetcher. But I can't really figure out how to use it (I keep getting the NSAssert "need upload location hdr").
So for POST, I guess ASIHTTPRequest is easier.
I did not get a chance to use facebook-ios-sdk. And would like to hear other opinion about it.
So is there NSURLConnection wrapper handle both GET and POST well ? And any idea how to use GTMHTTPUploadFetcher?
The GTMMIMEDocument class is used to create a stream for uploading via GTMHTTPFetcher (or via anything else that takes an NSInputStream.) An example is here.
GTMMIMEDocument keeps a sparse list of the data parts to be uploaded, avoiding duplicating the data in memory.

Sharing Non-Persistent Objects Between Contexts in Core Data?

I was wondering if there is a way to share an NSManagedObject between two or more NSManagedObjectContext objects running in the same thread.
I have the following problem: I have one main context shared through all my code in the application and several different contexts that are created for each remote fetch request that I issue. (I created a custom class that fetches remotely and inserts all the objects found in the server in his own NSManagedObjectContext). Those fetch requests may run simultaneously since they use NSURLConnection objects that may end at different times. If the same remote object gets fetched by different connections, I will end up with duplicates at the moment of saving and merging the context with the main one. (That is, objects that have the same remote ID but a different objectID).
One possible solution would be to save (and so persist) every object as soon as it is created but I can't do that because it may have some relationships that may still have not been filled and won't validate during the save operation.
I'm really looking forward to a method that allows you to share the same non-persistent instance of an object between context. If anybody has encountered this issue and came up with a solution, I would be pleased to know!
Context cannot communicate between each other save through their stores. However, you can insert a managed object with a nil managed object context and it will be independent (albeit without relationships) of any context. You could pass that independent managed object around however you wished and insert it into a context when you needed to persist it. This is dangerous but possible.
However, if you're not running each connection on a separate thread then you don't gain anything by having multiple context. Each connection object will activate its delegate in sequence on the main thread. In this case, your easiest solution would be to use the same delegate for all the connections and let the delegate handle the insertions into a single context. To prevent duplication, just do a fetch on the remoteID and see if you get back an extant object before inserting a new object for that remoteID.
I don't think what you want to do is possible. I mean if you want to share changes between different contexts, you got to use notifications and merge it whenever did save or did change occur. But in your case, I'd say just use 1 context and save in the end. Or a less elegant way: save all the remote ids temporary in your app and check before inserting new ones. In this case, you can continue use multiple contexts and save after each didfinishloading.

Two Asynchronous NSURLRequests using Cocoa Touch

I am using the example shown here - listing's 1-5 to request the content of a URL and everything is working perfectly. Now my problem is, while the first request is sent off, I want to request content from a second web page, my problem is, even if I duplicate everything there for a second request and connection, and create another variable for NSMutableData that should hold the second request's data, I am only getting the second requests data filled into *receivedData (i.e. the original first requests NSMutableData)
Its like the moment I add code for a second request, only the second request is executing...
Does anyone know how to modify the code in the linked example so I can issue two separate requests?
Disclaimer: learning objective-C now, my background is C#/VB.
If you are using "self" as the delegate for both requests, then you'll be getting callbacks for both of the requests and you are most likely only writing the bytes into a single receivedData object. What you need to do is either create a new class to act as the delegate and create a new instance of the class for each request, or if you want to continue using "self" as the delegate make sure you take a look at the "connection" parameter passed into the delegate methods. That will indicate which connection the callback belongs to, allowing you to write the data to the appropriate receivedData object.