Ios 使用NSURLSession等待HTTP请求的响应-目标C

Ios 使用NSURLSession等待HTTP请求的响应-目标C,ios,objective-c,cocoa-touch,request,Ios,Objective C,Cocoa Touch,Request,现在我正在开发一个小类,它有一个发送POST请求的方法。此方法用于返回ResponseModel(基本上有两个IVAR:代码、消息),此模型将从response映射。 我正在使用dataTaskWithRequest:urlRequest completionHandler:方法。像这样: + (void)sendPOSTRequest1:(id)data withResponse:(void (^) (ResponseModel * data) )taskResponse { NSEr

现在我正在开发一个小类,它有一个发送POST请求的方法。此方法用于返回ResponseModel(基本上有两个IVAR:代码、消息),此模型将从response映射。 我正在使用
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,因为它有一种执行同步请求的方法,但现在它已被弃用,所以我一直在想:这是一种我可以使用代码中的内容等待响应的方法吗?

您可以使用GCD实现如下同步请求:

swift代码

public static func requestSynchronousData(请求:URLRequest)->数据?{
var数据:数据?=nil
让信号量:DispatchSemaphore=DispatchSemaphore(值:0)
让task=URLSession.shared.dataTask(with:request,completionHandler:{
中的taskData,错误->()
数据=任务数据
如果data==nil,则让error=error{print(error)}
信号量
})
task.resume()
_=信号量。等待(超时:.distantFuture)
返回数据
}
目标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\u 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);
}];

不,你总是不想等待。无论谁调用您的
sendPOSTRequest
方法,都应该采用与此处完全相同的异步模式(例如,完成块等)。我知道,如果你把它变成一个只返回值的同步方法,感觉会非常明智和简单,但它几乎总是与你应该做的完全相反。而且,正如您所指出的,您也不想使用不推荐的
NSURLConnection
。新API不提供同步方法是有原因的,所以接受异步模式。嗨,@Rob,谢谢你的回答。那么,既然您提到了附加到这个异步模式,是否仍然可以在块内处理一些UI交互(当调用方法时),以便向用户检索信息?是的,您可以在传递给
sendPOSTRequest
的完成处理程序块中这样做。唯一的技巧是,您只想阻止将ivar和UI更新发送回主队列,例如
dispatch\u async(dispatch\u get\u main\u queue(),^{…})