COMPANY SERVICE STAFF BLOG NEWS CONTACT

STAFF BLOG

スタッフブログ

TECHNICAL

テクログ

2014.06.10

Objective-C | 非同期通信 JSONで送信バージョン

テクログ

Mac,iPhone,Objective-C 全て利用歴6ヶ月の新米プログラマーが送る

自分が使って役立ったmethod&Tips集

元ネタはありますが単なるコピペを紹介してるわけではありません。

ちゃんと自前で作ってます。(謎のアピール)

実務で通信するなら、AFNetworking 2.0 使った方がいいです。

変な取り回しも無いし世界中で使われているので間違いありません。

その上でご覧ください

シリーズ第14弾です。

非同期通信 メッセージ通知バージョンの改良でJSON送信を追加です。

Objective-CでPOST通信すると改行コード(N)がPHPでうまく受け取れないようでして悩んだあげく、JSON使って送るとうまく送信出来る事がわかりました。

Androidだとそんなまどろっこしい事しなくてもいいのですが、iPhoneでもPOSTで送るいいやり方があるのでしょうか?

サーバープログラムそのままで動きませんが、元のソースをラップすることとで置換だけで簡単に対応可能です

main_procを呼ぶ際に 単純にmain_proc($_POST);とすると、json 使わないバージョンが完成します

処理の切り分けが必要な際にどうぞ

blogasync2_json.php

//-------------------------------------
$json_string = file_get_contents("php://input"); ##今回のキモ
$json_array = json_decode($json_string, true);

main_proc($json_array);
return;


//-------------------------------------
// blogasync1.phpのソースを関数化した
//$_POST->$dataに変えた
function main_proc($data){
?if(empty($data["input"])){
??$ar = NULL;
?} else {
??$data["input"];
??// 受け取った値とステータスを返す
??$ar[]=array("input"=>$data["input"],"ret"=>"OK");
??$ar[]=array("input"=>$data["input"],"ret"=>"OK-2");
?}

header("Content-Type: application/json; charset=utf-8"); //JSONファイルの出力
echo json_encode($ar, JSON_UNESCAPED_UNICODE); //JSON形式にして返す

}

前回のソースを流用してます。

続いてiOS側。Xcodeでフォームに配置したボタンをAction接続してあります

NSURLConnectionDelegate も利用します

外部ライブラリでくるくる回る画像を利用してます。 https://github.com/samvermette/SVProgressHUD をダウンロードして FinderからSVProgressHUDディレクトリを自分のプロジェクトにポイっと入れて下さい

ここから新しいところ。

「// json 変更箇所」で、検索して貰うと修正箇所がわかります。(void)getJson しか変えてません

ViewController.h

#import 

@interface ViewController : UIViewController
- (IBAction)async:(id)sender;

@end

ViewController.m

#import "ViewController.h"
#import "SVProgressHUD.h"

@interface ViewController (){
    NSString       *connectStatus_;
    NSMutableData  *mData_;    // json
    NSMutableArray *cellList_;
}

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
?// Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark svr connection
// 非同期通信でgroup 1record 取得
- (void)getJson
{
    // 通信中表示
    //[SVProgressHUD showWithStatus:@"ユーザー情報取得" maskType: SVProgressHUDMaskTypeBlack];
    [SVProgressHUD showWithMaskType: SVProgressHUDMaskTypeClear];
    connectStatus_ = @"start";

// json 変更箇所
//    NSString *query = [NSString stringWithFormat:@"input=%@", @"test-test"];
//    NSData *queryData = [query dataUsingEncoding:NSUTF8StringEncoding];
    //-- json you syori ---
    //送信するパラメータの組み立て
    NSMutableDictionary *mutableDic = [NSMutableDictionary dictionary];
    [mutableDic setValue:@"test-json"   forKey:@"input"]; // 送る値が複数ある場合、キーを変えて複数記述すればOK
// json 変更箇所-end

    NSError* error = nil;
    NSData *queryData = [NSJSONSerialization dataWithJSONObject:mutableDic options:kNilOptions error:&error];
    
    // 自分のサーバーにPHPソースを置く
    NSString *url = @"http://localhost/blogasync2_json.php";
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
    [request setTimeoutInterval:30]; //タイムアウトを30秒に設定
    [request setURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"POST"];
// json 変更箇所
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    // NSDataは NSUIntegerでカウントするので %dを unsigned longに変更
    [request setValue:[NSString stringWithFormat:@"%lu",
                       (unsigned long)[queryData length]] forHTTPHeaderField:@"Content-Length"];
// json 変更箇所-end
    [request setHTTPBody:queryData];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    [NSURLConnection connectionWithRequest:request delegate:self];
    NSLog(@"async connection");
    
    // loop やめる
    //通知登録
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self selector:@selector(FinishMethod) name:@"end" object:nil];
    //通信開始
    [NSURLConnection connectionWithRequest:request delegate:self];
    //NSLog(@"async connection-grpsch");
    // loop やめる

    /*
    while ([connectStatus_ isEqualToString:@"start"]) {
        // while 内で一旦 NSRunLoop へ制御戻してやる。runUntilDateはモードとしてNSDefaultRunLoopModeを用いる
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]]; //0.5sec
    }
    */
    /* 以降の処理を分割しないとすぐに処理が実行されてしまう
    if ([connectStatus_ isEqualToString: @"OK"]) {
        NSError *error = nil;
        //NSDictinaryがNSArrayになって返ってきます(id の中に入る)
        id json = [NSJSONSerialization JSONObjectWithData:mData_ options:NSJSONReadingAllowFragments error:&error];
        if(!error) {
            if (json == [NSNull null]) {
                return;
            }
            cellList_     = [NSMutableArray array];
            NSUInteger cnt = [json count];
            for (int idx=0; idx<cnt; idx++)="" {<br="">                [cellList_ addObject:json[idx][@"input"]];
                [cellList_ addObject:json[idx][@"ret"]];
            }
        }
    }
    // 通信中表示を消す
    [SVProgressHUD dismiss];
     */
}


//通信開始時に呼ばれる
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"receive response");
    
    mData_ = [NSMutableData data];
}

//通信中常に呼ばれる
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSError *jsonError;
    NSMutableArray *returnedData = [[NSMutableArray alloc] init];
    returnedData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];
    NSLog(@"%@", returnedData);
    
    //通信したデータを入れていきます
    [mData_ appendData:data];
}

//通信終了時に呼ばれる
- (void)connectionDidFinishLoading: (NSURLConnection *)connection
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    NSLog(@"finish connection");
    
    connectStatus_ = @"OK";
    // loop やめる
    // 通知を作成する
    NSNotification *n = [NSNotification notificationWithName:@"end" object:self];
    // 終了通知を実行して関数を呼ぶ
    [[NSNotificationCenter defaultCenter] postNotification:n];
    
    //    NSError *error = nil;
    //    //NSDictinaryがNSArrayになって返ってきます(id の中に入る)
    //    id json = [NSJSONSerialization JSONObjectWithData:self.mData options:NSJSONReadingAllowFragments error:&error];
    //    if(!error) {
    //        //NSLog(@"%@",json);
    //        connectStatus_ = @"OK";
    //    } else {
    //        NSLog(@"json error-1");
    //        connectStatus_ = @"NG";
    //    }
}

//通信エラー時に呼ばれる
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    //エラー処理を書く
    NSLog(@"err %@",[error localizedDescription]);
    // 通信中表示を消す
    [SVProgressHUD showErrorWithStatus:@"接続に失敗しました"];
    connectStatus_ = @"NG";
    
    // エラー情報を表示する。
    // objectForKeyで指定するKeyがポイント
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
    
    // loop やめる
    // 終わったら通知を消す
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"end" object:nil];
}
// loop やめる
//ループで待機させてたその後の処理
- (void)FinishMethod {
    if ([connectStatus_ isEqualToString: @"OK"]) {
        NSError *error = nil;
        //NSDictinaryがNSArrayになって返ってきます(id の中に入る)
        id json = [NSJSONSerialization JSONObjectWithData:mData_ options:NSJSONReadingAllowFragments error:&error];
        if(!error) {
            if (json == [NSNull null]) {
                return;
            }
            cellList_     = [NSMutableArray array];
            NSUInteger cnt = [json count];
            for (int idx=0; idx<cnt; idx++)="" {<br="">                [cellList_ addObject:json[idx][@"input"]];
                [cellList_ addObject:json[idx][@"ret"]];
            }
        }
    }
    // 通信中表示を消す
    [SVProgressHUD dismiss];
}

- (IBAction)async:(id)sender
{
    [self getJson];
}
@end
</cnt;></cnt;>

サーバーから帰ってくる値がnullになる場合は、サーバーに置いてあるphpファイルがうまく参照出来ないとおもわれます。参照権限を確認して下さい

そのほかのObjective-C関連の記事をお探しならコチラをどうぞ

弊社から出している拙作スケジュールのアプリです。
スケジュールというかちょっとした予定を入力して、社長、同僚、家族がどこ行った??っていうときに第三者が確認するためのアプリです
是非ダウンロードして感想をお聞かせ下さい。

『Team Scheduler』 概要
▼アプリ価格: 無料
▼対応OS: iOS(iPhone/iPod Touch)、Android
▼カテゴリ: 仕事効率化(App Store)、ビジネス(Google Play)
▼対応言語: 日本語
▼推奨環境:
iOS版: iPhone4以降、iOS6. 0以降
Android版: Android OS 2. 3以降
▼ダウンロード:
App Storeからダウンロード
Google playで手に入れよう

この記事を書いた人

core-corp

入社年

出身地

業務内容

特技・趣味

テクログに関する記事一覧

TOP