Difference between cancelling a connection and setting it to nil - ios

In iOS I am using NSURLConnection -
NSURLConnection *aConnection = [[NSURLConnection alloc....
is there a difference between:
[aConnection cancel];
and
aConnection = nil;
Thanks

When you send the connection a cancel message, it will stop to invoke your delegates as soon as possible and tear down the connection.
Note: it may happen in rare cases that you still get one already queued delegate message other than connection:didFailWithError: after you send cancel from a different tread than the one the connection schedules delegates.
With setting your reference to the connection to nil, you simply do this. This does not cancel the connection - and if this was your only reference, you also can't send a cancel anymore. ;)

Basically by doing this:
aConnection = nil;
you cannot be sure that there are no other references to this object. So you should do this:
[aConnection cancel];

Related

Fifth NSURLConnection's delegate not called

I am using NSURLConnection in my app for downloading. It is working fine.When i start the connection the delegates methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse*)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
get called.
But when the number of connections become more then 4 then for the 5th connection the delegate methods do not called until the delegate method "connectionDidFinishLoading" is called for any of first four connections (means one of any four connection has finished). Then the delegates (didReceiveResponse and didReceiveData ) of Fifth connection start getting called .In short my NSURLConnection is delegate methods only called for 4 connections at a time.
I just want to know is there any way that i can increase this limit so that more then 4 (may be 8 or 9) connection's delegates get called at a time ? Is this a limit by iOS or something is wrong with my app.
Check http://blog.lightstreamer.com/2013/01/on-ios-url-connection-parallelism-and.html
iOS has a limit on the number of concurrent NSURLConnections to
the same end-point? No? Maybe you should, we discovered it the hard way.
They also offer a thread pool implementation to get around this limit.
I think you should schedule these connections to a manual created queue other than the default one, so as to avoid the potential affect. It works well for me. Here are the sample code you can try:
NSURLRequest *request; // a URL request
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // manual create queue to schedule your URL connections
queue.maxConcurrentOperationCount = 10; // configure the max count
// by specifying NO for the #startImmediately# parameter,
// you can schedule an connection on the queue you like before it starts.
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection setDelegateQueue:queue];
[connection start];
Hope this will be helpful.
You can't fix it with NSURLConnection (practically), but if you use NSURLSession instead, you can trivially solve the problem.
The NSURLSession API lets you control the maximum number of concurrent requests per server. Just set the HTTPMaximumConnectionsPerHost property on the session configuration object, then create a session based on that configuration, then create tasks within that session much like you would create NSURLConnection objects.

SRWebsocket close the connection ios

I am using SRWebsocket in my connection class I am trying to disconnect the socket when the app goes to background i have tried these things
SRWebSocket *_webSocket;
-(void)close
{
[_webSocket close];
_webSocket.delegate = nil;
_webSocket = nil;
}
but it is not closing the socket please help me in doing so .
Keep in mind that, if you nil the websocket delegate at this point, when the socket actually closes (it's not inmediate), there will be no delegate to process the webSocket:diCloseWithCode: event. But the socket should certainly be closed anyway.
It may not be that, but it would make more sense to just send the close message. Then wait for the didClose and there, you can nil both the delegate and the actual _websocket.

Using NSURLConnection Multiple times

I am trying to start a second NSURLConnection after starting the first one. My first one works perfectly: the appropriate delegates are all called, and everything executes as planned. However, after the first one finishes, I create a second one, and nothing happens (the delegate is never called). What could be happening? I know I can't reuse the same NSURLConnection, but I reinitialise it before using it again, so it should be a completely new connection.
Here's my code for starting (both) connections. It's the same instance variable, but it's reinitialised. Also note that the second one is not started until the first one has finished running completely.
if (connection) {
[connection cancel];
}
currentResponse = nil;
error = nil;
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
if (!connection) {
NSLog(#"Connection could not be initialized.");
[self connectionFinished];
} else {
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[connection start];
}
You haven't shared how you're running it "on a different thread", but the typical problem is if you are using dispatch queues or operation queues, your connection is running asynchronously, itself, and therefore the dispatched operation is completing and getting released and you're losing your connection.
A couple of possible solutions:
You can perform your network operations synchronously in this background operation of yours (this is the only time you should do synchronous network operations). This is the simplest solution, though you haven't explained what you're doing with your NSURLConnection, so this technique may or may not work for you. But if you're just trying to download something from a URL, you can do:
NSData *data = [NSData dataWithContentsOfURL:url
options:0
error:&error];
This approach doesn't work if you're doing any a little more complicated that requires the NSURLConnectionDataDelegate methods, such challenge-response authentication or if you are streaming using didReceiveData to reduce your app's memory footprint or for performances reasons, etc. But if you're just trying to download data from a remote server (e.g. retrieving an image, an XML/JSON feed, etc.), this is easiest.
In a similar vein (i.e. you don't need the NSURLConnectionDataDelegate methods), but you're you're creating some rich NSURLRequest for your connection, then you can use either sendAsynchronousRequest or sendSynchronousRequest.
If you need the NSURLConnectionDataDelegate calls, you can use the setDelegateQueue (designating a NSOperationQueue) or scheduleInRunLoop (designating a NSRunLoop), and it will automatically dispatch the connection updates to the appropriate queue/runloop. Just make sure to initWithRequest using the startImmediately option of NO, set the delegate queue or runloop, and then start the connection. With this technique, you preserve the full richness of NSURLConnectionDataDelegate if you absolutely need it.
Alternatively, if you're not using operation queues, you could also keep your background operation alive until the connection is done. This approach gives you synchronous behavior in you background operation (keeping your connection alive), while preserving the NSURLConnectionDataDelegate methods. This technique is demonstrated by Apple's XMLPerformance Sample (see the downloadAndParse method of CocoaXMLParser.m and LibXMLParser.m), where they initiate the NSURLConnection and then use the following construct to keep the background operation alive until the NSURLConnectionDataDelegate methods end up setting the done instance variable:
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
} while (!done);
I confess that I find this final approach vaguely dissatisfying and would lean towards the other alternatives, depending upon what flexibility and functionality you need from your NSURLConnection. For us to provide more meaningful counsel, you just need to provide more information about (a) the sort of work you're doing in your NSURLConnectionDataDelegate methods; and (b) which technology you're using to run your code in the background.
For a few more options, also feel free to see GCD and async NSURLConnection.

Serializing NSURLConnection Requests (iOS) - Use Synchronous Request?

I'm looping through a list of dates and making a request to a web server for each date in the list.
I would like each date to be processed completely before the subsequent request is sent to the server. To do this, I have set up a serial dispatch queue using GCD. Each time through the date loop, a block is added to the queue.
The problem I am having is that my NSURLConnection is set up using the standard asynchronous call. This results in requests not blocking any subsequent requests. They are thus overrunning each other.
My question: Is this a case where it would make sense for me to use the synchronous NSURLConnection (within the dispatch queue) or is there some other way to make it work using the standard asynchronous call?
There are number of ways to do this. Whatever method you choose, starting the connection needs to be tied to completion of your processing task.
In each block you add to your serial queue, use a synchronous request. This is probably the quickest solution given your current implementation as long as you're ok with the limited error handling of a synchronous request.
Don't use a serial queue. Start the first asynchronous connection and process the response. When processing is complete start the next asynchronous connection. Rinse and repeat.
I think that using the synchronous NSURLConnection API is a fine idea. You have a few other options. One would be to write a wrapper object around NSURLConnection that used the asynchronous NSURLConnection APIs, so you get the nice information that the asynchronous API callbacks provide, including download progress, you can easily continue to update your UI while the request is happening, but which presents its own synchronous method for doing whatever it is you need to do. Essentially, something like:
#implementation MyURLConnectionWrapper
- (BOOL)sendRequestWithError:(NSError **)error
{
error = error ? error : &(NSError *){ nil };
self.finishedLoading = NO;
self.connectionError = nil;
self.urlConnection = [][NSURLConnection alloc] init...]
while (!self.finishedLoading)
{
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]];
}
if (self.connectionError != nil)
{
*error = self.connectionError;
return NO;
}
return YES;
}
#end
(This is all typed off the top of my head, and is heavily abbreviated, but should give you the basic idea.)
You could also do something like fire off each request in the completion delegate method for the previous one, forgoing the use of a serial dispatch queue altogether:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
{
[self sendNextRequest];
}
Either way, you need to think about how to handle connection errors appropriately. I've used both approaches in different places with good success.

How to make program wait for asynchronous NSURLConnection to finish before proceeding with next command?

How can I make my program wait for an asynchronous NSURLConnection to finish before going to the next line of code?
SetDelegate *sjd= [SetDelegate alloc];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:post delegate:sjd];
[connection start];
This is how I start the connection and I handle the data received in the delegate but I want to wait for the connection to end before proceeding mainly because this is in a for loop and it has to run for each element in my database.
I need to put data from the phones database to a remote database and after the data was successfully put in the data in the phones database is deleted. I am going through each element in the phone's database and start a connection that's why I don't see how the next stuff can be done from the loop. I'm a beginner when it comes to objective-c programming so I'm not sure if this is the right way or not to do it
Making the call synchronous is not an option because it blocks the program and i have a progress bar that should show.
Your question is a bit odd. You have impossibly constrained the issue. You cannot have a line of code "wait" for a process to finish w/o it blocking something, in this case whatever thread the loop is running in.
You can use a synchronous call if you wanted to, it doesn't block your app, it only blocks the thread it is executed on. In your example, you have a loop that is continually getting remote data and you want your UI to reflect that until it is done. But you don't want your UI blocked. That means, this thread with your loop already MUST be on a background thread so you can feel free to do a synchronous call in the loop w/o blocking your UI thread. If the loop is on the UI thread you need to change this to do what you want.
You could also do this using an asynchronous connection. In that case, your operation may actual complete faster b/c you can have multiple requests in progress at the same time. If you do it that way, your loop can remain on the UI thread and you just need to track all of the connections so that when they are finished you can communicate that status to the relevant controllers. You'll need iVars to track the loading state and use either a protocol or NSNotification to communicate when loading is done.
EDIT: ADDED EXAMPLE OF SYNCHRONOUS CALL ON BACKGROUND THREAD
If you want the loop to finish completely only when all requests are finishes and not block your UI thread here's a simple example:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// post an NSNotification that loading has started
for (x = 0; x < numberOfRequests; x++) {
// create the NSURLRequest for this loop iteration
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
// do something with the data, response, error, etc
}
// post an NSNotification that loading is finished
});
Whatever objects need to show loading status should observe and handle the notifications you post here. The loop will churn through and make all your requests synchronously on a background thread and your UI thread will be unblocked and responsive. This isn't the only way to do this, and in fact, I would do it using async connections myself, but this is a simple example of how to get what you want.
If you just want to know when it's complete and don't really care about any data, simply use the NSNotificationCenter to post a notification and have your view subscribe to it.
Delegate - Post Notification upon completion
-(void) connectionDidFinishLoading:(NSURLConnection*)connection {
[[NSNotificationCenter defaultCenter] postNotificationName:#"NSURLConnectionDidFinish" object:nil];
}
View - Add observer and run some code when observed
-(void) viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(yourCleanupMethod)
name:#"NSURLConnectionDidFinish"
object:nil];
}
-(void) yourCleanupMethod {
// finish up
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Now, if you need to pass a simple object back as data you can try loading up the object parameter in your notification like this:
[[NSNotificationCenter defaultCenter] postNotificationName:#"NSURLConnectionDidFinish" object:yourDataObject];
Then change your view and cleanup signature like this:
-(void) viewDidLoad {
// Notice the addition to yourCleanupMethod
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(yourCleanupMethod:)
name:#"NSURLConnectionDidFinish"
object:nil];
}
-(void) yourCleanupMethod:(NSNotification *)notif {
// finish up
id yourDataObject = [notif object];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Now I found myself needing something a little more than this so I ended up creating a singleton to handle all of my requests. Since all of your delegate methods in NSURLConnectionDelegate give you and instance of the NSURLConnection for the specific connection, you can simply store a mutable data object in a dictionary and look it up each time by the connection. From there I have a method signature that takes and object and selector in that I associate with the connection so after everything has wrapped up, I can pass that mutable data object to the requestor by performing the selector on that object.
I won't include all of that code here but maybe that will help get you thinking about what is possible. I found that I had a lot of code tied up in making web service calls so wrapping everything up in a singleton gave me a nice clean way of getting data. Hope this helps!
If you really want it to wait, why use an asynchronous call at all? Use a synchronous call instead:
NSURLResponse* response = nil;
NSData* data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:nil]
This approach will block the thread it's executed, so you should be sure you want to do it! Did I mention that it will block? :)
You say you want to wait for an asynchronous call to complete, so I'm assuming you're calling the code you posted up in a separate thread.
I would recommend having a look at the new sendAsynchronourRequest method. I've posted up an example of how you can wrap this up in a class which would inform its delegate when the connection has completed / timed out / failed. I'm only referring you to this post because it sounds like you're trying to achieve something very similar to what I was at the time, and this DownloadWrapper class worked flawlessly for me. It's new in iOS5, mind you.
This golden nugget helped me!
I was using synchronous NSURL just fine until I decided I needed SSL for my connection between my client and my server. I took the approach of key pinning which is comparing the cert on the device to the cert on the server (read more on link above) and in order for it to work I needed to add code to the NSURL methods, which from my research you can't do with NSURL synchronous.
Until I found this ridiculously simple solution which worked for me:
NSString *connectionRunLoopMode = #"connectionRunLoopMode";
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:urlRequest delegate:urlConnectionDelegate startImmediately:NO];
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
[connection unscheduleFromRunLoop:currentRunLoop forMode:NSDefaultRunLoopMode];
[connection scheduleInRunLoop:currentRunLoop forMode:connectionRunLoopMode];
[connection start];
while ([currentRunLoop runMode:connectionRunLoopMode beforeDate:[NSDate distantFuture]]);
NSURLConnection is already asynchronous. Simply implement the delegate methods. If you want to update the UI on the MainThread (e.g. a progress bar), you can do so in didReceiveData.
or look at this

Resources