17
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

NSURLConnection から NSURLSession への移行例

はじめに

iOS 9 より NSURLConnection が DEPRECATED となってしまったので、既存コードを NSURLSession に移行する場合について考察。

Delegateを使っていない場合

非同期処理

非同期処理(+ sendAsynchronousRequest:queue:completionHandler:)の場合は、特に何も考えずにBlocksの中身をそのまま使うことができます。

NetworkManager.m
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        if (connectionError) {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"LoadDataFailed" object:nil];
            return;
        }
        NSInteger statusCode = [(NSHTTPURLResponse *)respnse statusCode];
        if (statusCode != 200) {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"LoadDataFailed" object:nil];
            return;
        }

        [[NSNotificationCenter defaultCenter] postNotificationName:@"LoadDataSuccess" object:data];
    }];

    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&respnse error:&error];

上のようなコードの場合だと、下のように completionHandler: をほぼそのまま流用することができます。

NetworkManager.m
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // connectionError -> error
        if (error) {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"LoadDataFailed" object:nil];
            return;
        }
        NSInteger statusCode = [(NSHTTPURLResponse *)respnse statusCode];
        if (statusCode != 200) {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"LoadDataFailed" object:nil];
            return;
        }

        [[NSNotificationCenter defaultCenter] postNotificationName:@"LoadDataSuccess" object:data];
    }];
    [task resume];

ただ、別スレッドで処理されているため、Viewの操作をする場合は注意が必要です。

同期処理

同期処理(+ sendSynchronousRequest:returningResponse:error:)の場合は、 NSURLSessionTask が非同期処理であるため、このままでは都合が悪いです。
GCD のディスパッチセマフォという仕組みを利用し、非同期処理を同期処理にすることで対応します。

NetworkManager.m
- (NSString *)connectionSyncRequest:(NSString *)targetUrl
{
    NSURL *url = [NSURL URLWithString:targetUrl];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];

    NSURLResponse *response = nil;
    NSError *error = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];

    if (error) {
        NSLog(@"%@", error);
        return nil;
    }

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    if (httpResponse.statusCode != 200) {
        return nil;
    }

    NSString *receivedMessage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    return receivedMessage;
}

上のようなコードの場合では、下のようにディスパッチセマフォを利用して、同期処理にします。

NetworkManager.m
- (NSString *)sessionSyncRequest:(NSString *)targetUrl
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    NSURL *url = [NSURL URLWithString:targetUrl];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];

    __block NSString *receivedMessage = nil;
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"did finish download.\n%@", response.URL);
        if (error) {
            NSLog(@"%@", error);
            dispatch_semaphore_signal(semaphore);
            return;
        }

        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode != 200) {
            dispatch_semaphore_signal(semaphore);
            return;
        }
        receivedMessage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        dispatch_semaphore_signal(semaphore);

    }];
    [task resume];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    return receivedMessage;
}

Delegateを使っている場合

Delegate を使っている場合も、わりとすんなり移行することができます。

NetworkManager.m
- (void)sessionAsyncRequest:(NSString *)targetUrl
{
    NSURL *url = [NSURL URLWithString:targetUrl];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];

    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"did finish download.\n%@", response.URL);
        if (error) {
            NSLog(@"%@", error);
            [self connection:nil didFailWithError:error];
            return;
        }

        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode != 200) {
            [self connection:nil didFailWithError:nil];
            return;
        }

        self.receivedData = [NSMutableData dataWithData:data];
        [self connectionDidFinishLoading:nil];
    }];
    [task resume];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // 正常終了時の処理
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    // エラー時の処理
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
17
Help us understand the problem. What are the problem?