Best practice to replace a synchronous NSURLConnection with NSURLSession

我是研究僧i 提交于 2020-04-30 07:38:05

问题


As

NSURLConnection sendSynchronousRequest:returningResponse:error:&connectionError

is set deprecated I will have to replace an Importer I wrote a long time ago.

The Importer does the following:

  1. It fetches data from API-A. The data there can be on multiple pages.
  2. It uses the data from the first fetch (also multipage) to query data from API-B and merges
  3. Results from the API-B query will be merged with data from API-A

I implemented this with a background-operation where I use methods for each API which called recursively if there are mulitple pages for the request.

But as NSURLSession does not support synchronous request I currently only see the option to have lot of overhead (e.g. iVars) control what's called in the completion block (e.g. next Page or start to query API-B).

So, what would be an elegant solution to bring this to NSURLSession.

NB: Just to make sure, my previous solution does not block the main thread at all. But back then it was the easiest way to control the merge of two sources.


回答1:


This answer is not supposed to be best practice. It was just practical for me.

Faced with the situation when a bunch of synchronous requests is executed in background and the order of execution matters I've ended up using the following:

SyncRequestSender.h

#import <Foundation/Foundation.h>

@interface SyncRequestSender : NSObject

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
                 returningResponse:(NSURLResponse **)response
                             error:(NSError **)error;

@end

SyncRequestSender.m

#import "SyncRequestSender.h"

@implementation SyncRequestSender

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
                 returningResponse:(NSURLResponse **)response
                             error:(NSError **)error
{
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);


    NSError __block *err = NULL;
    NSData __block *data;
    NSURLResponse __block *resp;

    [[[NSURLSession sharedSession] dataTaskWithRequest:request
                                     completionHandler:^(NSData* _data, NSURLResponse* _response, NSError* _error) {
        resp = _response;
        err = _error;
        data = _data;
        dispatch_group_leave(group);

    }] resume];

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    if (response)
    {
        *response = resp;
    }
    if (error)
    {
        *error = err;
    }

    return data;
}

@end



回答2:


This's an example in AFNetworking, it shows how to wait an asynchronous task.

- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
    __block NSArray *tasks = nil;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
            tasks = dataTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
            tasks = uploadTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
            tasks = downloadTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
            tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
        }

        dispatch_semaphore_signal(semaphore);
    }];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    return tasks;
} 


来源:https://stackoverflow.com/questions/37431455/best-practice-to-replace-a-synchronous-nsurlconnection-with-nsurlsession

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!