【问题标题】:Wait response for HTTP request using NSURLSession - Objective C使用 NSURLSession 等待 HTTP 请求的响应 - Objective C
【发布时间】:2020-02-10 01:40:37
【问题描述】:

现在我正在开发一个小类,它有一个发送 POST 请求的方法。该方法旨在返回一个 ResponseModel(基本上有两个 ivars:代码、消息),该模型将从响应映射。 我正在使用dataTaskWithRequest:urlRequest completionHandler: 方法。像这样:

+ (void)sendPOSTRequest1:(id)data withResponse:(void (^) (ResponseModel * data) )taskResponse {
    NSError *error = nil;

    NSMutableURLRequest * urlRequest = [self getRequestObject];

    [urlRequest setHTTPMethod:@"POST"];

    NSData * requestData = [self encodeAndEncrypt:data];

    [urlRequest setHTTPBody:requestData];


    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session
                                      dataTaskWithRequest:urlRequest
                                      completionHandler:
                                      ^(NSData *data, NSURLResponse *response, NSError *error) {

        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;

        ResponseModel * responseModel = [NSKeyedUnarchiver
                                         unarchivedObjectOfClass:[ResponseModel class]
                                         fromData:data
                                         error:&error];

        taskResponse(responseModel);


    }];

    [dataTask resume];
}

并以这种方式调用该方法:

DummyModel * dummy = [[DummyModel alloc] init];

__block ResponseModel * result = [[ResponseModel alloc] init];

[HTTPRequest sendPOSTRequest1:dummy withResponse:^(ResponseModel *data) {
    result =  data;
    NSLog(@"data %@",data);
}];

// It`s not sure that the asyncronous request has already finished by this point
NSLog(@"POST result : %@",result);

我的问题是我不想在回调块中执行代码,因为我需要等待响应才能返回一个 ResponseModel 并且执行此操作的任何人都可以接收该模型并制作其他东西。 我一直在研究使用 NSURLConnection 因为它有一个执行同步请求的方法,但现在它已被弃用,所以我想知道:这是一种我可以使用代码中的内容等待响应的方法吗?

【问题讨论】:

  • 不,你总是不想等待。无论谁调用您的 sendPOSTRequest 方法,都应该采用与此处完全相同的异步模式(例如完成块等)。我知道,如果你把它做成一个只返回值的同步方法,感觉会很明智和容易,但它几乎总是与应该做的完全相反。而且,正如您所指出的,您也不想使用已弃用的NSURLConnection。新 API 不提供同步方法是有原因的,因此请采用异步模式。
  • 嗨,@Rob,谢谢你的回答。那么,既然您提到要附加到这个 Asynchornous 模式,是否仍然可以处理块内的一些 UI 交互(当方法被调用时)以便向用户检索信息?
  • 是的,您可以在传递给sendPOSTRequest 的完成处理程序块中执行此操作。唯一的技巧是您只想将该块调度 ivar 和 UI 更新回主队列,例如dispatch_async(dispatch_get_main_queue(), ^{ ... });

标签: ios objective-c cocoa-touch request


【解决方案1】:

你可以像这样使用 GCD 来实现同步请求:

快速代码

public static func requestSynchronousData(request: URLRequest) -> Data? {
    var data: Data? = nil
    let semaphore: DispatchSemaphore = DispatchSemaphore(value: 0)
    let task = URLSession.shared.dataTask(with: request, completionHandler: {
        taskData, _, error -> () in
        data = taskData
        if data == nil, let error = error {print(error)}
        semaphore.signal()
    })
    task.resume()
    _ = semaphore.wait(timeout: .distantFuture)
    return data
}

Objective-C 代码

+ (NSData *)requestSynchronousData:(NSURLRequest *)request {
    __block NSData * data = nil;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable taskData, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"%@", error);
        }
        data = taskData;
        dispatch_semaphore_signal(semaphore);
    }];
    [task resume];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    return data;
}

您可以使用 dispatch_async 处理块内的 UI 交互

DummyModel * dummy = [[DummyModel alloc] init];

__block ResponseModel * result = [[ResponseModel alloc] init];

[HTTPRequest sendPOSTRequest1:dummy withResponse:^(ResponseModel *data) {
    result =  data;
    dispatch_async(dispatch_get_main_queue(), ^{
       // handle some ui interaction
    });
    NSLog(@"data %@",data);
}];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-13
    • 1970-01-01
    • 2018-06-03
    • 2014-04-24
    • 2017-02-22
    • 1970-01-01
    • 2012-12-30
    相关资源
    最近更新 更多