On iOS, can you make a synchronous network request

2019-06-14 11:17发布

On iOS, can you make a synchronous network request (off the main thread) and get progress callbacks (on a separate, non-main thread)?

I have have a serial (one-operation-at-a-time) background queue that runs all of time-consuming jobs that don't need to finish right now. I do want to show progress for the download jobs though. It doesn't look like you can instantiate an NSURLConnection and configure a delegate, start synchronous connection, and then get progress callbacks.

Is there a way to make a synchronous request on that background queue (synchronous in that the job behind it doesn't start until its done), and still get setProgress: callbacks which could be sent to update a progressbar? (Callbacks would have to be on a different queue thread, since my serial queue's thread is blocked until the request is finished.)

Apple's docs for NSURLConnection say that the synchronous request is actually built on top of the asynchronous behind the scenes. Do I have to re-implement that? I need a way to block a thread until the request finishes/fails. The best leads I have so far are NSOperationQueue's waitUntilFinished method, but I don't want to start async and continually poll on the synchronous method.

NSURLConnection Discussion

A synchronous load is built on top of the asynchronous loading code made available by the class. The calling thread is blocked while the asynchronous loading system performs the URL load on a thread spawned specifically for this load request. No special threading or run loop configuration is necessary in the calling thread in order to perform a synchronous load.

1条回答
Viruses.
2楼-- · 2019-06-14 11:51

Reimplementing a synchronous request on top of an asynchronous request is not that hard. You just need to manually spin the thread's run loop until you see that the request has finished (or failed). Here's a rough example:

NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:queryURL];
// Start the download and wait until it finishes
self.downloadFinished = NO;
self.downloader = [NSURLConnection connectionWithRequest:downloadRequest delegate:self];

while (!self.isDownloadFinished)
 {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
 }

Here are the relevant NSURLConnectionDelegate methods:

 - (void)connectionDidFinishLoading:(NSURLConnection *)connection;
 {
    self.downloadFinished = YES;
 }

 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
 {
    NSLog(@"An error occurred: %@", error);
    self.receivedData = nil;
    self.downloadFinished = YES;
 }
查看更多
登录 后发表回答