2012年8月22日水曜日

【iPhone&iPad】サーバから取得した配列データをMKMapViewに配置したアノテーションにセットする

MapViewにアノテーション(マーカー)を設置していると、サーバから取得した位置情報データ配列を
アノテーションに割当し、タップした際に自由にその配列データを取り出したくなってきたので
いろいろ参考にして下記のように実装した。

サーバからは

[
    "35.732584",
    "139.704271",
    "東京豊島区西池袋5丁目12番",
    "山田太郎さん"
]

というような配列を取得している。(受け取っているのは下のコードの中の「-(void)requestDone:(ASIHTTPRequest *)request」にて。)




/*

アノテーションのカスタムクラス MyAnnotation.h と MyAnnotation.m
*/


///////////MyAnnotation.h/////////////////////////////////////////////////////////



@interface MyAnnotation : MKPointAnnotation 
{
    BOOL _isStart;
}
@property (nonatomic, assign) BOOL isStart;
@property (nonatomic, assign) int current_num;   ////IMPORTANT!!!!!!!!!!
@end

///////////MyAnnotation.h/////////////////////////////////////////////////////////




///////////MyAnnotation.m/////////////////////////////////////////////////////////



#import "MyAnnotation.h"

// MyAnnotation」クラスの実装
@implementation MyAnnotation

// プロパティとメンバー変数の設定
@synthesize isStart = _isStart;
@synthesize current_num;

// イニシャライザ
- (id)init
{
    self = [super init];
    if (self)
    {
        // メンバー変数を初期化する
        _isStart = NO;
    }
    return self;
}

@end

///////////MyAnnotation.m/////////////////////////////////////////////////////////







/*

非同期通信でサーバから位置情報を取得(getAroundPoint)し、
requestDoneで取得したデータをpoints_arrayという配列にセットする。
このpoints_arrayの位置情報データが
・マップ上のピン画像切り替え
・表示タイトル/サブタイトルだけでなく、その他の付随データなど
として使用される。
*/


//現在地周辺のユーザの位置情報を取得する処理
-(void)getAroundPoint:(float)latitude lon:(float)longitude{
    if (![self queue]) {
        [self setQueue:[[[NSOperationQueue alloc] init] autorelease]];
    }
    
    //current location
    NSString *lat = [NSString stringWithFormat:@"%f",latitude];
    NSString *lon = [NSString stringWithFormat:@"%f",longitude];
    
    NSArray *keys        = [NSArray arrayWithObjects:   //JSONの「キー」
                            @"latitude",                //1.緯度
                            @"longitude",               //2.経度
                            nil];
    
    NSArray *objects     = [NSArray arrayWithObjects:   //JSONの「バリュー」
                            lat,                        //1.緯度
                            lon,                        //2.経度
                            nil];
    
    NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
    
    NSString *jsonString = [jsonDictionary JSONRepresentation];
    
    //target server    
    NSString *URLValue   = @"http://<<your-domain>>/get_locations";
    NSURL *url = [NSURL URLWithString:URLValue];

    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
    [request addRequestHeader:@"User-Agent" value:@"ASIHTTPRequest"];
    [request addRequestHeader:@"Content-Type" value:@"application/json"];
    [request appendPostData:[jsonString  dataUsingEncoding:NSUTF8StringEncoding]];
    [request setDelegate:self];
    [request setShowAccurateProgress:YES];
    [request setDownloadProgressDelegate:self];
    [request setDidFinishSelector:@selector(requestDone:)];
    [request setDidFailSelector:@selector(requestWentWrong:)];
    [request setTimeOutSeconds:15];
    [[self queue] addOperation:request]; //queue is an NSOperationQueue
}


//非同期通信が完了した際に呼ばれるデリゲートメソッド
-(void)requestDone:(ASIHTTPRequest *)request {
    //NSLog(@"################################Connection success###################");
    //NSString *response = [request responseString];
    // Use when fetching binary data
    NSData *responseData = [request responseData];
    NSMutableString *string = [[NSMutableString alloc] initWithData:responseData 
                                                                                           encoding:NSUTF8StringEncoding];
    NSDictionary *jsonDictionaryResponse = [string JSONValue];    
    //サーバ側から返ってくるJSONのキーを指定して、その値を取得する
    NSString *status   = [jsonDictionaryResponse objectForKey:@"status"];   //ステータス
    NSArray *pointsdata = [jsonDictionaryResponse objectForKey:@"pointsdata"];  //位置情報(配列)
    NSLog(@"##############status %@",status);
    if([status isEqualToString:@"ok"]){
        if([pointsdata count]>0){
            points_array = [pointsdata mutableCopy];
            for(int i=0;i<[points_array count];i++){
                NSString *latitude = [[pointsdata objectAtIndex:i]objectAtIndex:0];
                NSString *longitude = [[pointsdata objectAtIndex:i]objectAtIndex:1];
                float tmp_lat = [latitude floatValue];
                float tmp_long = [longitude floatValue];
                CLLocation *tmp_location = [[CLLocation alloc] initWithLatitude: tmp_lat
                                                                                                      longitude: tmp_long];
                
                // アノテーションを作成する(カスタムクラス)
                MyAnnotation *annotation;
                annotation = [[MyAnnotation alloc] init];
               
                // 位置を設定する
                [annotation setCoordinate:tmp_location.coordinate];
                [tmp_location release];
                
                // ビューに追加する
                annotation.title = [NSString stringWithFormat:@"%@",[[points_array objectAtIndex:i]objectAtIndex:3]];
                annotation.subtitle = [NSString stringWithFormat:@"電波強度: %@",[[points_array objectAtIndex:i]objectAtIndex:4]];
                annotation.current_num = i;
                [self.mapView addAnnotation:annotation];
                //[self.mapView selectAnnotation:annotation animated:NO];
                [annotation release];
            }
        }
    }
}



//アノテーションを装飾するデリゲートメソッド
//addAnnotationをするとviewForAnnotationが呼び出される
- (MKAnnotationView*)mapView:(MKMapView*)map_View viewForAnnotation:(id <MKAnnotation>)annotation {
    if (annotation == mapView.userLocation) {
        return nil; //現在地の場合はスルー
    }
    MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier: @"my_annotation"];
    if (annotationView == nil) {
        annotationView = [[[MKPinAnnotationView alloc] initWithAnnotation: annotation reuseIdentifier: @"my_annotation"] autorelease];
    } else {
        annotationView.annotation = annotation;
    }
    
    //どのピンがタップされたのかを判定するためにそのアノテーションビューに仕込んでおいた配列番号を取得する
    MyAnnotation *MyAnn = (MyAnnotation *)annotationView.annotation;
    int array_num = MyAnn.current_num;
    NSString *carrier_name = [[points_array objectAtIndex:array_num]objectAtIndex:3];
    
    if([carrier_name isEqualToString:@"E-Mobile(3G)"]){
        [annotationView setPinColor:MKPinAnnotationColorRed];
    }else if([carrier_name isEqualToString:@"E-Mobile(LTE)"]){
        [annotationView setPinColor:MKPinAnnotationColorPurple];
    }else if([carrier_name isEqualToString:@"WiMax"]){
        [annotationView setPinColor:MKPinAnnotationColorGreen];
    }
    
    [annotationView setCanShowCallout:YES];
    [annotationView setAnimatesDrop:YES];
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    return annotationView;
}




//上の「アノテーションを装飾するデリゲートメソッド」で生成した「UIButtonTypeDetailDisclosure」をタップした際に実行されるメソッド
- (void)mapView:(MKMapView*)map_View
 annotationView:(MKAnnotationView*)annotationView
calloutAccessoryControlTapped:(UIControl*)control{
    MyAnnotation *MyAnn = (MyAnnotation *)annotationView.annotation;
    NSLog(@"###################: %d",MyAnn.current_num);
    
    /*
    上の「MyAnn.current_num」を使用して、points_array配列の中のデータを自由に取り出すことができる。
    NSString *username = [[points_array objectAtIndex:MyAnn.current_num]objectAtIndex:4];


    */
}

2012年8月18日土曜日

【iPhone】UINavigationControllerをrootViewControllerにしている状態でUITabBarController+UINavigationControllerに切り替える方法

UINavigationControllerをrootViewControllerにしている状態で、
UITabBarController+UINavigationControllerに切り替える方法

-(IBAction)goToTopMenuView:(id)sender{
  UITabBarController *tabBarController = [[UITabBarController alloc] init];
  //FirstViewController(inherited UIViewController)をUINavigationControllerのルートにセットする
  FirstViewController* vc1 = [[FirstViewController alloc] init];
  UINavigationController* navController1 = [[UINavigationController alloc]initWithRootViewController:vc1];

  //SecondViewController(inherited UIViewController)をUINavigationControllerのルートにセットする
  SecondViewController* vc2 = [[SecondViewController alloc] init];
  UINavigationController* navController2 = [[UINavigationController alloc]initWithRootViewController:vc2];

  //ThirdViewController(inherited UIViewController)をUINavigationControllerのルートにセットする
  ThirdViewController* vc3 = [[ThirdViewController alloc] init];
  UINavigationController* navController3 = [[UINavigationController alloc]initWithRootViewController:vc3];

  //FourthViewController(inherited UIViewController)をUINavigationControllerのルートにセットする
  FourthViewController *vc4 = [[FourthViewController alloc]init];
  UINavigationController* navController4 = [[UINavigationController alloc]initWithRootViewController:vc4];

  NSArray* controllers = [NSArray arrayWithObjects:
            navController1,
            navController2,
            navController3,
            navController4,
            nil];

  tabBarController.viewControllers = controllers;


  // アプリケーションのキーウィンドウを取得して、そのルートビューコントローラーを置き換える
  [UIApplication sharedApplication].keyWindow.rootViewController = tabBarController;
}

【JavaScript】フルAjaxで月間カレンダー

フルAjaxで月間カレンダー。
データベースに保存されている予定があれば取得してカレンダー上にも表示できるようにするためゼロから書いた。
/monthからのresponseにJSONオブジェクト



が返ってくる想定。

今月は「getMonthCalendar('now');」で
前の月は「getMonthCalendar('minus');」、
次の月は「getMonthCalendar('plus');」で取れる。



//月間カレンダーデータを取得するメソッド
function getMonthCalendar(status){
  var today = new Date();
  var trunkcode = "{{items['trunkcode']}}";
  var recid = "{{items['user_record_id']}}";
  var department = $('#month_selected_dep').val();
  var my_department = '{{items["my_department"]}}';
  var selected_department = "";
  if(department!=""&&department!=null){
    selected_department = department;
  }else{
    selected_department = my_department;
  }
  var year,month = "";
  if(calendar_month==""||calendar_year==""){
    year = today.getFullYear();
    month = today.getMonth()+1;
    calendar_month = month;
    calendar_year = year;
  }else{
    if(status=='now'){
      year = today.getFullYear();
      month = today.getMonth()+1;
      calendar_month = month;
      calendar_year = year;
    }else if(status=='minus'){
      calendar_month-=1
      if(Number(calendar_month)==0){
        calendar_month = 12;
        calendar_year -=1;
      }
    }else if(status=='plus'){
      calendar_month+=1
      if(Number(calendar_month)==13){
        calendar_month = 1;
        calendar_year +=1;
      }
    }
  }
  
  //指定された年月の1日の末日を取得する
  var firstday = new Date(calendar_year,calendar_month-1,1);
  var lastday = new Date(calendar_year,calendar_month,0);
  var compdate = lastday.getDate() - firstday.getDate() + 1;
  var json = '{"trunkcode":"'+trunkcode+'","year":"'+calendar_year+'","month":"'+calendar_month+'","record_id":"'+recid+'","department":"'+selected_department+'"}';
  $.post(
    '/month',
    json,
    function(response){
      $('#schedule_tbody_month').empty();
      monthCalLabel(calendar_year,calendar_month);  //月間カレンダーの表示期間を表示するメソッド
      
      //カレンダーテーブルを生成
      var cal_table = $('<table>');
      var table_head_week = $('<tr>');
      table_head_week.append($('<td>').attr('style','background-color:#FF4747;color:white;text-align:center;').append("日"));
      table_head_week.append($('<td>').attr('style','background-color:#666;color:white;text-align:center;').append("月"));
      table_head_week.append($('<td>').attr('style','background-color:#666;color:white;text-align:center;').append("火"));
      table_head_week.append($('<td>').attr('style','background-color:#666;color:white;text-align:center;').append("水"));
      table_head_week.append($('<td>').attr('style','background-color:#666;color:white;text-align:center;').append("木"));
      table_head_week.append($('<td>').attr('style','background-color:#666;color:white;text-align:center;').append("金"));
      table_head_week.append($('<td>').attr('style','background-color:#1975FF;color:white;text-align:center;').append("土"));
      
      
      //先月分を生成する必要があるかどうか、当月の1日の曜日(f_date.getDay()が0じゃない場合)を見て判断する
      var f_date = new Date(calendar_year,calendar_month-1,1);
      if(f_date.getDay()!=0){
        var l_tr = $('<tr>');
        var l_date = new Date(calendar_year,calendar_month-1,0);
        for(var s=0;s<=l_date.getDay();s++){
          lc_date = new Date(calendar_year,calendar_month-1,0-s);
          var l_td = $('<td>').append(lc_date.getDate());
          l_tr.prepend(l_td);
        }
        //当月分のカレンダーを生成
        for(var i=1;i<=compdate;i++){
          var c_date = new Date(calendar_year,calendar_month-1,i);
          var c_td = $('<td>').append(c_date.getDate());
          if(c_date.getDay()==0){
            $('#schedule_tbody_month').append(l_tr);
            l_tr = $('<tr>');
            l_tr.append(c_td);
          }else{
            l_tr.append(c_td);
          }
        }
        
        //来月分のカレンダーを生成
        //alert(lastday.getDay());
        if(lastday.getDay()!=6){
          for(var s=1;s<=7;s++){
            var ll_check_day = new Date(calendar_year,calendar_month,s);
            if(ll_check_day.getDay()==6){
              var ll_td = $('<td>').append(s);
              l_tr.append(ll_td);
              break;
            }else{
              var ll_td = $('<td>').append(s);
              l_tr.append(ll_td);
            }
          }
        }
        $('#schedule_tbody_month').append(l_tr);
      }else{
        //当月分のカレンダーを生成
        for(var i=1;i<=compdate;i++){
          var c_date = new Date(calendar_year,calendar_month-1,i);
          var c_td = $('<td>').append(c_date.getDate());
          if(c_date.getDay()==0){
            $('#schedule_tbody_month').append(l_tr);
            l_tr = $('<tr>');
            l_tr.append(c_td);
          }else{
            l_tr.append(c_td);
          }
        }
        
        //翌月の1週目を生成する必要があるかチェックする
        //alert(lastday.getDay());
        if(lastday.getDay()!=6){
          for(var s=1;s<=7;s++){
            var ll_check_day = new Date(calendar_year,calendar_month,s);
            if(ll_check_day.getDay()==6){
              var ll_td = $('<td>').append(s);
              l_tr.append(ll_td);
              break;
            }else{
              var ll_td = $('<td>').append(s);
              l_tr.append(ll_td);
            }
          }
        }
        $('#schedule_tbody_month').append(l_tr);
      }
      $('#schedule_tbody_month').prepend(table_head_week);
    }
  );
}

2012年8月4日土曜日

【iPhone&iPad】デバイスの向きと回転した際の対応方法


【ViewController.h】

@interface ViewController : UIViewController<ModalViewDelegate>{
    IBOutlet UIButton *expBtn;
    IBOutlet UIButton *demoBtn;
    IBOutlet UIView *mainContentView;
}





【ViewController.m】

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    mainContentView.center = CGPointMake(self.view.frame.size.width/2,self.view.frame.size.height/2);
    
}


- (void)viewDidLoad
{
    [super viewDidLoad];
    //デバイス回転通知
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(didRotate:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];
}

//デバイス回転通知時の命令
- (void) didRotate:(NSNotification *)notification {
    mainContentView.center = CGPointMake(self.view.frame.size.width/2,self.view.frame.size.height/2);
}