トップ «前の日記(2012-04-29) 最新 次の日記(2012-05-01)» 編集

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|

2012-04-30 [iOS][Web]iPhoneアプリケーションとサーバ間の通信(その3)

おそらく、Twitterフレームワークの為だと思うが、iOS5からNSJSONSerializationというJSONを扱うクラスが追加された。

このクラスは非常にシンプルで、用意されているメソッドは以下の5つだけだ。

+ JSONObjectWithData:options:error:
JSONデータを配列(NSArray)/辞書(NSDictionary)に変換して返す。
+ JSONObjectWithStream:options:error:error
ストリームから得られたJSONデータを配列(NSArray)/辞書(NSDictionary)に変換して返す。
+ dataWithJSONObject:options:error:
配列(NSArray)/辞書(NSDictionary)をJSONデータに変換して返す。
+ writeJSONObject:toStream:options:error:
配列(NSArray)/辞書(NSDictionary)をJSONデータに変換してストリームに書き込む。
+ isValidJSONObject:
指定されたFondationのidがJSONデータに変換可能か確認する(だと思う)

ようするに、JSONデータとFondationの配列/辞書に相互に変換するメソッド。JSONデータについては、NSDataとストリームの2種類に対応ということだ。

これで、前回のRESTを使ったアプリケーションをJSON対応に変更できるはずだ。ただ、まだ、NSJSONSerializationを使った情報が世の中には少ないのと、railsアプリケーションが返す結果が、著者が想像していたのと事なってので、試行錯誤はあったが。

以下が、試行錯誤したコードだ。

- (IBAction)sendPost:(id)sender
{
    NSURL   *url = [NSURL URLWithString:@"http://localhost:3000/people.json"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPMethod:@"POST"];
    NSMutableDictionary *person = [NSMutableDictionary dictionary];
    [person setValue:@"MURAKAMI Yukio" forKey:@"name"];
    [person setValue:@"18" forKey:@"age"];
    NSError *error = nil;
    NSData  *content = [NSJSONSerialization dataWithJSONObject:person options:NSJSONWritingPrettyPrinted error:&error];
    [request setHTTPBody:content];
    NSHTTPURLResponse   *response = nil;
    NSData  *data = [NSURLConnection sendSynchronousRequest:request
                                          returningResponse:&response
                                                      error:&error];
    content = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    if (!error) {
        NSString    *s = [[NSString alloc] initWithFormat:@"status code: %d\ndata: %@", [response statusCode], content];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
    else {
        NSString    *s = [[NSString alloc] initWithFormat:@"error: %@", error];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
}
 
- (IBAction)sendGet:(id)sender
{
    NSURL   *url = [NSURL URLWithString:@"http://localhost:3000/people/1.json"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"GET"];
    NSHTTPURLResponse   *response = nil;
    NSError *error = nil;
    NSData  *data = [NSURLConnection sendSynchronousRequest:request
                                          returningResponse:&response
                                                      error:&error];
    NSDictionary    *content = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    if (!error) {
        NSString    *s = [[NSString alloc] initWithFormat:@"status code: %d\ndata: %@", [response statusCode], content];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
    else {
        NSString    *s = [[NSString alloc] initWithFormat:@"error: %@", error];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
}
 
- (IBAction)sendGetList:(id)sender
{
    NSURL   *url = [NSURL URLWithString:@"http://localhost:3000/people.json"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"GET"];
    NSHTTPURLResponse   *response = nil;
    NSError *error = nil;
    NSData  *data = [NSURLConnection sendSynchronousRequest:request
                                          returningResponse:&response
                                                      error:&error];
    NSDictionary    *content = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    if (!error) {
        NSString    *s = [[NSString alloc] initWithFormat:@"status code: %d\ndata: %@", [response statusCode], content];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
    else {
        NSString    *s = [[NSString alloc] initWithFormat:@"error: %@", error];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
}
 
- (IBAction)sendPut:(id)sender
{
    NSURL   *url = [NSURL URLWithString:@"http://localhost:3000/people/1.json"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPMethod:@"PUT"];
    NSMutableDictionary *person = [NSMutableDictionary dictionary];
    [person setValue:@"MURAKAMI Yukio" forKey:@"name"];
    [person setValue:@"81" forKey:@"age"];
    NSError *error = nil;
    NSData  *content = [NSJSONSerialization dataWithJSONObject:person options:NSJSONWritingPrettyPrinted error:&error];
    [request setHTTPBody:content];
    NSHTTPURLResponse   *response = nil;
    NSData  *data = [NSURLConnection sendSynchronousRequest:request
                                          returningResponse:&response
                                                      error:&error];
    content = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    if (!error) {
        NSString    *s = [[NSString alloc] initWithFormat:@"status code: %d\ndata: %@", [response statusCode], content];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
    else {
        NSString    *s = [[NSString alloc] initWithFormat:@"error: %@", error];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
}
 
- (IBAction)sendDelete:(id)sender
{
    NSURL   *url = [NSURL URLWithString:@"http://localhost:3000/people/1.json"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPMethod:@"DELETE"];
    NSHTTPURLResponse   *response = nil;
    NSError *error = nil;
    NSData  *data = [NSURLConnection sendSynchronousRequest:request
                                          returningResponse:&response
                                                      error:&error];
    NSDictionary    *content = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    if (!error) {
        NSString    *s = [[NSString alloc] initWithFormat:@"status code: %d\ndata: %@", [response statusCode], content];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
    else {
        NSString    *s = [[NSString alloc] initWithFormat:@"error: %@", error];
        self.textView.text = s;
        NSLog(@"%@", self.textView.text);
    }
}

JSONのContent-Typeは、application/jsonなのですね。RESTの時のapplication/xmlのままにしていたら、railsアプリケーションの方でXMLとして処理をしようとして、エラーになってしまった。

また、成功したら、HTTPステータスは200だと思っていたら、そうではなかった。それは、railsアプリケーションのpeople_controller.rbで以下のように記述しているからだと思う。

  # POST /people
  # POST /people.json
  def create
    @person = Person.new(params[:person])
respond_to do |format| if @person.save format.html { redirect_to @person, :notice => 'Person was successfully created.' } format.xml { render :xml => @person, :status => :created, :location => @person } format.json { render :json => @person, :status => :created, :location => @person } else format.html { render :action => "new" } format.xml { render :xml => @person.errors, :status => :unprocessable_entity } format.json { render :json => @person.errors, :status => :unprocessable_entity } end end end

Rubyを知らず、仕様も確認しないで当てずっぽうだが、POSTの場合、:statusを:createdに設定しているのでHTTPステータスは201(created)を返す。

  # PUT /people/1
  # PUT /people/1.json
  def update
    @person = Person.find(params[:id])
respond_to do |format| if @person.update_attributes(params[:person]) format.html { redirect_to @person, :notice => 'Person was successfully updated.' } format.xml { head :no_content } format.json { head :no_content } else format.html { render :action => "edit" } format.xml { render :xml => @person.errors, :status => :unprocessable_entity } format.json { render :json => @person.errors, :status => :unprocessable_entity } end end end

PUTの場合、:statusを:no_contentに設定しているので、HTTPステータスは204(no content)を返すようだ。何故、エラーとなるのか、少し、驚いてしまった。

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/JSON - GitHub

トップ «前の日記(2012-04-29) 最新 次の日記(2012-05-01)» 編集