синхронный NSURLSessionDataTask с использованием target-c - PullRequest
3 голосов
/ 27 июня 2019

Я пытаюсь сделать синхронный NSURLSessionDataTask с кодом ниже, но не могу продолжить.

__block NSData *rData = nil;
  __block BOOL taskDone = NO;
 __block NSData *rError = nil;


    NSURL *url = [NSURL URLWithString:dataURL];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:1 timeoutInterval:30];

    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:nil delegateQueue:nil];
    NSURLSessionDataTask *taskData = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        rData = [NSData dataWithData:data];
        rError = [error copy];

        taskDone = YES;
    }];

    [taskData resume];

    while (taskDone == NO) {
        if (_close == YES) {
            [taskData cancel];
            return nil;
        }
        usleep(20000);
    }

Мне нужно синхронный вызов, чтобы я мог удалить цикл while, который не нужен.Ниже мой код с синхронным вызовом с использованием семафора

 dispatch_semaphore_t sem;
   __block NSData *rData = nil;
   __block BOOL taskDone = NO;
  __block NSData *rError = nil;


    NSURL *url = [NSURL URLWithString:dataURL];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:1 timeoutInterval:30];

    // creating semaphore
    sem = dispatch_semaphore_create(0);
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:nil delegateQueue:nil];
    NSURLSessionDataTask *taskData = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        rData = [NSData dataWithData:data];
        rError = [error copy];

        taskDone = YES;

        //call semaphore
        dispatch_semaphore_signal(sem); 
    }];

    [taskData resume];
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    dispatch_release(sema);


   // THIS part not sure...  how can we accommodate this below code
    while (taskDone == NO) {
        if (_close == YES) {
            [taskData cancel];
            return nil;
        }
        usleep(20000);
    }

приведенный выше код может быть правильным?

Ответы [ 2 ]

1 голос
/ 29 июня 2019

Вы можете сделать NSURLSessionDataTask синхронным с PromiseKit .Установите его вручную или добавьте следующую строку в Podfile, если вы используете CocoaPods (протестировано с CocoaPods 1.7.3):

pod "PromiseKit", "6.10.0"

Добавьте следующую строку в начало файла кода:

@import PromiseKit;

Затем создайте оболочку для своей задачи:

- (AnyPromise*)promiseToLoadData:(NSString*)dataURL {
    return [AnyPromise promiseWithResolverBlock:^(PMKResolver _Nonnull resolver) {
        NSURL *url = [NSURL URLWithString:dataURL];
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:1 timeoutInterval:30];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:nil delegateQueue:nil];
        NSURLSessionDataTask *taskData = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (error != nil) {
                resolver([error copy]);
            } else {
                resolver([NSData dataWithData:data]);
            }
        }];
        [taskData resume];
    }];
}

Используйте wait для синхронного разрешения обещания:

id value = [self promiseToLoadData:@"http://your.url"].wait;
if ([value isKindOfClass:[NSData class]]) {
    NSLog(@"%@", [[NSString alloc] initWithData:value encoding:NSUTF8StringEncoding]);
}
1 голос
/ 28 июня 2019

Я понимаю, что вы хотите подождать, пока DataTask будет завершен, прежде чем продолжить работу с кодом, лучше всего поместить запрос в функцию с помощьюручки завершения.

Сначала создайте функциюкоторый возвратит NSURLSessionDataTask с обработчиком завершения:

-(NSURLSessionDataTask*)startSessionDataTaskWithCompletionHandler:(void (^)(NSData *myData))completionBlock {
    //Set your request
    NSString *dataURL = @"www.yoururl.com";
    NSURL *url = [NSURL URLWithString:dataURL];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:1 timeoutInterval:30];

    // I recommend to use sharedSession because is a simple request, so its not needed a specific session configuration.
    NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession] dataTaskWithRequest: request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!error) {
            if (completionBlock){
                completionBlock(data);
                return;
                //When you call this function, the completionBlock will use this data
            }
        } else {
            //Error handle
            return;
        }
    }];
    [dataTask resume];
    return dataTask;
}

Затем вы можете вызвать эту функцию из любого места:

NSURLSessionTask *task = [self startSessionDataTaskWithCompletionHandler:^(NSData *myData) {
    // put whatever code you want to perform when the asynchronous data task finish, for example:
    rData = [NSData dataWithData:myData];
}];
if (!task) {
    // handle failure to create task any way you want
}
...