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];


    */
}

0 件のコメント:

コメントを投稿