不推荐使用iOS9 sendSynchronousRequest

时间:2015-09-18 03:10:05

标签: ios swift

  

警告:不推荐使用'sendSynchronousRequest(_:returningResponse :)'   在iOS 9.0中:使用[NSURLSession dataTaskWithRequest:completionHandler:]   (见NSURLSession)

urlData = try NSURLConnection.sendSynchronousRequest(request, returningResponse:&response)

关于如何摆脱这种警告的任何想法?我刚从Swift 1.2升级到Swift 2

更新:Fonix被标记为我的最佳答案。如果您尝试添加try语句,我修改了他的答案如下:

urlData = try NSURLSession.dataTaskWithRequest(<#request: NSURLRequest#>, completionHandler: <#((NSData!, NSURLResponse!, NSError!) -> Void)?##(NSData!, NSURLResponse!, NSError!) -> Void#>)

7 个答案:

答案 0 :(得分:37)

使用NSURLSession代替如下,

对于Objective-C

NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:londonWeatherUrl]
          completionHandler:^(NSData *data,
                              NSURLResponse *response,
                              NSError *error) {
            // handle response

  }] resume];

对于Swift,

var request = NSMutableURLRequest(URL: NSURL(string: "YOUR URL"))
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"

var params = ["username":"username", "password":"password"] as Dictionary<String, String>

var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")

var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
    println("Response: \(response)")})

task.resume()

答案 1 :(得分:24)

我为实际需要阻止当前线程执行的同步请求的情况编写了以下解决方案。我使用此代码在复杂的解决方案中从NSURLConnection迁移到NSURLSession,只需更改为非同步方法,非常麻烦。使用此解决方案,迁移只是方法名称替换。

注意:如果您的案例很简单,请使用接受的答案。

- (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
{

    NSError __block *err = NULL;
    NSData __block *data;
    BOOL __block reqProcessed = false;
    NSURLResponse __block *resp;

    [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable _data, NSURLResponse * _Nullable _response, NSError * _Nullable _error) {
        resp = _response;
        err = _error;
        data = _data;
        reqProcessed = true;
    }] resume];

    while (!reqProcessed) {
        [NSThread sleepForTimeInterval:0];
    }

    *response = resp;
    *error = err;
    return data;
}

用法(简单地将NSURLConnection替换为此方法):

//NSData *data = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&resp error:&err];
NSData *data = [self sendSynchronousRequest:theRequest returningResponse:&resp error:&err];

答案 2 :(得分:14)

如果您需要阻止当前线程(如Mike Keskinov的回答),最好使用gdc信号量而不是[NSThread sleepForTimeInterval:0]。 e.g。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:londonWeatherUrl]
          completionHandler:^(NSData *data,
                              NSURLResponse *response,
                              NSError *error) {
            // handle response
            dispatch_semaphore_signal(semaphore);

  }] resume];

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

答案 3 :(得分:5)

我已经修改了Nilesh Patel的代码,所以你可以使用旧的调用,只需更改类名。

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error {
__block NSData *blockData = nil;
@try {

        __block NSURLResponse *blockResponse = nil;
        __block NSError *blockError = nil;

        dispatch_group_t group = dispatch_group_create();
        dispatch_group_enter(group);

        NSURLSession *session = [NSURLSession sharedSession];
        [[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable subData, NSURLResponse * _Nullable subResponse, NSError * _Nullable subError) {

            blockData = subData;
            blockError = subError;
            blockResponse = subResponse;

            dispatch_group_leave(group);
        }] resume];

        dispatch_group_wait(group,  DISPATCH_TIME_FOREVER);

        *error = blockError;
        *response = blockResponse;

    } @catch (NSException *exception) {

        NSLog(@"%@", exception.description);
    } @finally {
        return blockData;
    }
}

答案 4 :(得分:4)

Swift 4 / Xcode 9

如果您确实希望请求与已弃用的语义一样是同步的,则可以在完成处理程序设置为true的条件下使用空循环来阻止主线程:

let request = URLRequest(url: URL(string: "YOUR_URL")!)
let session = URLSession.shared
var gotResp = false

let task = session.dataTask(with: request,
            completionHandler: { data, response, error -> Void in
                // do my thing...
                gotResp = true
            })
task.resume()

// block thread until completion handler is called
while !gotResp {
    // wait
}

print("Got response in main thread")
...

编辑:或者如果您更喜欢使用Obj-C中的信号量,那就是Nick H247答案:

let request = URLRequest(url: URL(string: "YOUR_URL")!)
let session = URLSession.shared
let ds = DispatchSemaphore( value: 0 )    
let task = session.dataTask(with: request,
            completionHandler: { data, response, error -> Void in
                // do my thing..., then unblock main thread
                ds.signal()
            })
task.resume()

// block thread until semaphore is signaled
ds.wait()

print("Got response in main thread")
...

答案 5 :(得分:2)

您可以使用以下代码在输入指令之间编写您的方法,并在您的项目中隐藏警告。

#pragma GCC diagnostic push 
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- (void)yourMethodToCallNSURLConnection {
//use deprecated stuff
}
#pragma GCC diagnostic pop

答案 6 :(得分:0)

这里是我的完整版本,带有dispatch_semaphore_t,并且返回响应和错误,而没有块分配警告。感谢@Nick H247和@Mike Keskinov。

- (NSData*)sendSynchronousRequest:NSURLRequest *urlRequest
                returningResponse:(NSURLResponse **)outResponse
                            error:(NSError **)outError
{

    NSError __block *err = NULL;
    NSData __block *data;
    BOOL __block reqProcessed = false;
    NSURLResponse __block *resp;

//    data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:response error:error];

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    NSURLSession *session = _session;
    [[session dataTaskWithRequest:urlRequest
            completionHandler:^(NSData *_data,
                                NSURLResponse *_response,
                                NSError *_error) {
                // handle response
                data = _data;
                resp = _response;
                err = _error;

                reqProcessed = true;

                dispatch_semaphore_signal(semaphore);

            }] resume];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    if (reqProcessed) {
        if(outResponse != NULL) {
            *outResponse = resp;
        }

        if (outError != NULL) {
            *outError = err;
        }

    }

    return data;
}