... didReceiveResponse and didReceiveData are never called. And I found out why. Oddly enough, asynchronous loading occurs in the same main thread that I use. It does not create a new thread. So when I sleep the main thread, I also dream that I am doing work.
That's right. The connection is controlled by a start cycle; if you sleep a thread, the start cycle stops and this prevents your connection from doing its job.
So donβt do anything special. Let the application sit there when starting the launch cycle. A small spinner may appear on the screen to entertain the user. Talk about your business if you can. If at all possible, let the user continue to use the application. Your delegate method will be called when the connection is complete, and then you can do what you need to do with the data.
When you move the code to a background thread, you will again need a run loop to connect this connection. Thus, you will begin to create a launch cycle, plan your connection, and then just return. The run loop will continue to work, and your delegation method will be called again when the connection completes. If the thread is completed, you can stop the execution loop and let the thread exit. That is all that is needed.
Example:. We put this in specific terms. Let's say you want to make several connections one at a time. Paste the URL into the mutable array. Create a method called (for example) startNextConnection
that does the following:
Also, complete the required NSURLConnectionDelegate methods, especially connectionDidFinishLoading:
Ask this method to do the following:
If there were no errors, this would be enough to get data for all the URLs in your list. (Of course, you want startNextConnection
to be smart enough to just return when the list is empty.) But errors occur, so you have to think about how to deal with them. If the connection fails, do you want to stop the whole process? If so, just try the connection:didFailWithError:
method to do something suitable, but don't call it startNextConnection
. Do you want to go to the next URL in the list if there is an error? Then do ...didFailWithError:
call startNextRequest
.
Alternative: If you really want to maintain the consistent structure of your synchronous code, so that you have something like:
[self downloadURLs]; [self waitForDownloadsToFinish]; [self processData]; ...
then you have to load in another thread so that you can block the current thread. If you need it, configure the download stream with a start loop. Then create a connection using -initWithRequest:delegate:startImmediately:
as you did, but pass NO
in the last parameter. Use -scheduleInRunLoop:forMode:
to add a connection to the load stream startup loop, and then start the connection using the -start
method. This gives you the ability to sleep the current thread. Ask the procedure for completing delegation of the connection to set a flag in your example, for example, the self.downloadComplete
flag.