M.S.の技術メモ

NSURLConnectionを使ってデータ送信

NSURLConnectionを使用して非同期でGET / POST送信ができる汎用クラスを作成しました。
アセットパスのファイルのアップロードにも対応しています。

使用するには次のフレームワークをプロジェクトに追加してください。

  • AssetsLibrary.framework
  • MobileCoreService.framework

 

長くなりますので、使用する場合はこちらをダウンロードしてください。

SendDataAsyncronous.zip

 

使い方

#import "SendDataAsyncronous.h"
SendDataAsyncronous *sendAsync = [SendDataAsyncronous alloc] init];

// 送信先を設定
NSURL *url = [NSURL URLWithString:@"http://example.com/test.php"];

// 送信するデータを設定する
NSMutableDictionary *data = [NSMutableDictionary alloc] init];

[data setObject:@"value" objectForKey:@"key"];

// GET送信
NSString *getResponse = [sendAsync sendDataAsyncronous:url sendData:data httpMethod:sendAsync.HTTP_GET];

// POST送信
NSString *postResponse = [sendAsync sendDataAsyncronous:url sendData:data httpMethod:sendAsync.HTTP_POST];

第1引数にNSURL型に変換した送信先のURLを設定します。

第2引数にはNSDictionaryに追加したデータを設定してください。

第3引数は汎用クラスに定義されている定数を指定してください。
GET送信なら HTTP_GET を、POST送信なら HTTP_POST を指定します。

 

汎用クラス: SendDataAsyncronous

SendDataAsyncronous.h

//
//  SendDataAsyncronous.h
//
//  Created by M.S. on 2014/08/27.
//  Copyright (c) 2014ๅนด M.S. All rights reserved.
//

#import <foundation foundation.h>
#import <assetslibrary assetslibrary.h>
#import <mobilecoreservices mobilecoreservices.h>

@interface SendDataAsyncronous : NSObject

@property (copy, nonatomic) NSString *HTTP_GET;
@property (copy, nonatomic) NSString *HTTP_POST;

- (NSString *)sendDataAsyncronous:(NSURL *)url sendData:(NSDictionary *)data httpMethod:(NSString *)method;

@end

 

SendDataAsyncronous.m

//
//  SendDataAsyncronous.m
//
//  Created by M.S. on 2014/08/27.
//  Copyright (c) 2014年 M.S. All rights reserved.
//

#import "SendDataAsyncronous.h"

@implementation SendDataAsyncronous

#pragma mark initialization

- (id)init {
    if (self = [super init]) {
        self.HTTP_GET = @"GET";
        self.HTTP_POST = @"POST";
    }

    return self;
}


#pragma mark public methods

- (NSString *)sendDataAsyncronous:(NSURL *)url sendData:(NSDictionary *)data httpMethod:(NSString *)method {
    NSString *response = @"";

    // GET送信
    if ([method isEqualToString:self.HTTP_GET]) {
        response = [self sendDataByGet:url sendData:data];
    }
    // POST送信
    else {
        response = [self sendDataByPost:url sendData:data];
    }

    return response;
}


#pragma mark private methods

/**
 * @param NSURL 送信先のURL
 * @param NSDictionary 送信するデータ
 * @param NSString レスポンス
 */
- (NSString *)sendDataByGet:(NSURL *)url sendData:(NSDictionary *)data {
    NSMutableArray *paramsArray = [NSMutableArray array];

    for (NSString *key in [data allKeys]) {
        [paramsArray addObject:[NSString stringWithFormat:@"%@=%@", key, [data valueForKey:key]]];
    }

    NSString *params = [paramsArray componentsJoinedByString:@"&"];
    NSURL *requestUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", url, params]];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:requestUrl];

    return [self sendData:request];
}

/**
 * @param NSURL 送信先のURL
 * @param NSDictionary 送信するデータ
 * @param NSString レスポンス
 */
- (NSString *)sendDataByPost:(NSURL *)url sendData:(NSDictionary *)data {
    NSMutableData *sendData = [[NSMutableData alloc] init];
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    NSString *fileKey = @"";
    NSString *TWO_HYPHENS = @"--";
    NSString *EOL = @"\r\n";
    NSString *BOUNDARY = [NSString stringWithFormat:@"%X", ((arc4random() % 10000) + 1) * 10000];

    for (NSString *key in [data allKeys]) {
        NSString *val = [data valueForKey:key];

        // ファイルパスは後でデータを付け足すために保持しておく
        if ([fileManager fileExistsAtPath:val isDirectory:NO] || [val hasPrefix:@"assets-library://"]) {
            fileKey = key;
        }
        // テキストデータ
        else {
            [sendData appendData:[self string2Data:[NSString stringWithFormat:@"%@%@%@", TWO_HYPHENS, BOUNDARY, EOL]]];
            [sendData appendData:[self string2Data:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"%@", key, EOL]]];
            [sendData appendData:[self string2Data:EOL]];
            [sendData appendData:[self string2Data:val]];
            [sendData appendData:[self string2Data:EOL]];
        }
    }

    // ファイル情報のセット
    [sendData appendData:[self string2Data:[NSString stringWithFormat:@"%@%@%@", TWO_HYPHENS, BOUNDARY, EOL]]];

    if ([fileKey length] > 0) {
        __block NSString *filePath = [data valueForKey:fileKey];
        __block NSString *mimeType = @"";
        __block NSData *fileData = [[NSData alloc] init];

        if ([filePath hasPrefix:@"assets-library://"]) {
            ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
            CFRunLoopRef rl = CFRunLoopGetCurrent();

            [assetsLibrary assetForURL:[NSURL URLWithString:filePath] resultBlock:^(ALAsset *asset) {
                ALAssetRepresentation *representation = [asset defaultRepresentation];

                filePath = [representation filename];
                mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass ((__bridge CFStringRef)[representation UTI], kUTTagClassMIMEType);


                // ファイルの取得
                Byte *buf = (Byte *)malloc((NSUInteger)[representation size]);
                NSUInteger iSize = [representation getBytes:buf fromOffset:0.0 length:(NSUInteger)[representation size] error:nil];

                fileData = [NSData dataWithBytesNoCopy:buf length:iSize freeWhenDone:YES];

                CFRunLoopStop(rl);
            } failureBlock:^(NSError *error) {
                NSLog(@"error: %@", error);
            }];
            CFRunLoopRun();
        } else {
            CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[filePath pathExtension], NULL);

            mimeType = (NSString*)CFBridgingRelease(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
            fileData = [NSData dataWithContentsOfFile:filePath];
        }


        [sendData appendData:[self string2Data:[NSString stringWithFormat:
                                                @"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"%@",
                                                fileKey, filePath, EOL]]];
        [sendData appendData:[self string2Data:[NSString stringWithFormat:@"Content-Type: %@%@", mimeType, EOL]]];
        [sendData appendData:[self string2Data:EOL]];
        [sendData appendData:fileData];
        [sendData appendData:[self string2Data:EOL]];
    }
    // ファイルなし
    else {
        [sendData appendData:[self string2Data:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"\"; filename=\"\"%@", EOL]]];
        [sendData appendData:[self string2Data:[NSString stringWithFormat:@"Content-Type: application/octet-stream%@", EOL]]];
    }
    [sendData appendData:[self string2Data:EOL]];
    [sendData appendData:[self string2Data:[NSString stringWithFormat:@"%@%@%@%@%@", EOL, TWO_HYPHENS, BOUNDARY, TWO_HYPHENS, EOL]]];

    
    // リクエストデータの生成
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];

    [request setHTTPMethod:@"POST"];
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", BOUNDARY] forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:sendData];

    return [self sendData:request];
}


/**
 * 非同期でデータを送信してそのレスポンスを返す
 * @param NSURLRequest HTTPリクエスト
 * @return NSString レスポンス
 */
- (NSString *)sendData:(NSURLRequest *)request {
    __block NSString *responseBody = @"";
    CFRunLoopRef rl = CFRunLoopGetCurrent();

    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        // 接続エラー
        if (connectionError) {
            NSLog(@"error: %@", connectionError);
        }
        else {
            int httpStatusCode = ((NSHTTPURLResponse *)response).statusCode;

            // HTTP OK
            if (httpStatusCode == 200) {
                responseBody = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            }
            else {
                NSLog(@"HTTP ERROR: %d", httpStatusCode);
            }
        }

        CFRunLoopStop(rl);
    }];
    CFRunLoopRun();

    return responseBody;
}


/**
 * NSStringをNSDataへ変換する
 * @param NSString 変換する文字列
 * @return NSData 文字列から変換されたデータ
 */
- (NSData *)string2Data:(NSString *)data {
    return [data dataUsingEncoding:NSUTF8StringEncoding];
}

@end

“NSURLConnectionを使ってデータ送信” への2件のフィードバック

  1. Terrific post but I was wanting to know if you could write a litte more on this topic? I’d be very grateful if you could elaborate a little bit further. Many thanks!

  2. parola uggiosa より:

    Your style is very unique compared to other folks I’ve read stuff from. Thanks for posting when you’ve got the opportunity, Guess I will just book mark this site.

ugg classic tall leather へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*