使用 Objective-C 同步 NSURLSessionDataTask

问题描述 投票:0回答:2

我尝试使用以下代码执行同步 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(sem, DISPATCH_TIME_FOREVER);
    dispatch_release(sem);


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

上面的代码可能是正确的吗?

objective-c nsurlsession completionhandler
2个回答
1
投票

我明白你想要做的是等待 DataTask 完成然后再继续你的代码,最好的方法是将你的请求放在带有completionHandler的函数中。

首先创建一个函数,该函数将返回带有完成处理程序的 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
}

1
投票

您可以使

NSURLSessionDataTask
PromiseKit 同步。手动安装,或者如果您使用 CocoaPods,则将以下行添加到 Podfile(使用 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
同步解决 Promise:

id value = [self promiseToLoadData:@"http://your.url"].wait;
if ([value isKindOfClass:[NSData class]]) {
    NSLog(@"%@", [[NSString alloc] initWithData:value encoding:NSUTF8StringEncoding]);
}
© www.soinside.com 2019 - 2024. All rights reserved.