Didload でMap 生成後にピン表示とかさせたいメモ
MAPを表示した後、ピンを立てたり、現在地を表示させる という時、
単純に - (void)viewDidLoad の中で、ピン表示用の住所から緯度経度取得→ピンセット
とさせてみたけど、うまくいかない。
デバッグすると、そもそも 緯度経度変換の処理で、緯度経度が取得できてない
という悲しさ。直接、緯度経度をセットしてあげるとできるんだけど、
なぜか、データ取得処理とかすると、うまくいかない…orz
想像するに、MkMapが生成される前に、緯度経度取得処理をしようとするから
ダメじゃね? と思って、探してみた。
わからん。なら、本家本元のガイド見てみる。
☆Location Awareness Programming Guide
https://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/LocationAwarenessPG/Introduction/Introduction.html
そうね、多分、MAPのDelegateメソッドのリファレンスよね てことで、
☆MKMapViewDelegate Protocol Reference
https://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapViewDelegate_Protocol/MKMapViewDelegate/MKMapViewDelegate.html#//apple_ref/doc/uid/TP40008204
お!MAPデータがロードされた時ってある!(名前的に)
Loading the Map Data
– mapViewWillStartLoadingMap:
– mapViewDidFinishLoadingMap: ーーーー>コレ!
– mapViewDidFailLoadingMap:withError:
でも、コレじゃダメみたいだった…orz
どうやら、位置情報取得処理(Geocode)が別スレッドで走って、ピンを立てる処理が先に
走ってしまい、位置情報が無いのでピンが立たない ということらしい。
for (ピンを立てたい住所分ループ) { 1) 住所の有無チェック 2) 位置情報取得 3) ピンを立てる }
2) の処理が終わってないのに、3) の処理が実行されるので、
位置情報が無い=ピンが立たない ってこと。
調べてみると、処理が終わったよ という通知処理を行なって、
通知を受け取ったら、処理を実行する という機能があるんだって!!
ほー!NSNotification という機能。
☆iPhone開発虎の巻
http://iphone-tora.sakura.ne.jp/nsnotification.html
☆通知と通知センター
http://www15.plala.or.jp/NovemberKou/programming/columnHome/column/whatIsNotification.html
要するに、2) の処理が終わったよ という通知を受け取ったら、3) の処理を行う
という形に変えたら良いわけね。
1) NSNotificationCenter に登録時、通知を受信した時の処理(メソッド)を指定する。
// Noticifation登録用オブジェクト生成
NSNotificationCenter* center = [NSNotificationCenter defaultCenter]
// "KEY_GEOCODE_OK"という名前の通知が来たら、"addPlacemark:"という処理を実行してね と登録。
[center addObserver:self selector:@selector(addPlacemark:)
name:KEY_GEOCODE_OK object:nil];
2) 通知の実施処理
// NSNotificationを作成する
NSNotification* notification = [NSNotification notificationWithName:sResult
object:self userInfo:dicPlaceObj];
// NSNotificationCenterを取得する
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
// 通知を行う
[center postNotification:notification];
3) 通知受け取った時の処理
– (void) addPlacemark:(id)sendor
{
〜
}
ということで、以下のようにしたら 成功!
MapViewController.m
@synthesize mapView; CLPlacemark *antPlacemark; #define KEY_GEOCODE_OK @"geoCodeOk" #define KEY_GEOCODE_NG @"geoCodeNg" #define KEY_PLACEMARK @"placemark" - (void)viewDidLoad { [super viewDidLoad]; // 位置情報取得通知登録 [self entryNotificationGeocode]; // 位置情報の利用有無チェック [self checkMapLocation]; // 初期画面設定 [self setInitView]; // selector内で指定した時間後に住所データから、地図にピン表示を行う [self performSelectorOnMainThread:@selector(createVisitAndLocation) withObject:nil waitUntilDone:YES]; } #pragma mark - DidLoad // 位置情報取得通知の登録 - (void) entryNotificationGeocode { // NSNotificationCenterを取得 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; // 位置情報取得完了(OK)をObserverとして登録 [center addObserver:self selector:@selector(addPlacemark:) name:KEY_GEOCODE_OK object:nil]; // 位置情報取得完了(NG)をObserverとして登録 [center addObserver:self selector:@selector(alertPlacemark:) name:KEY_GEOCODE_NG object:nil]; } // 位置情報取得の通知 - (void) notificateGeocodeDone:(NSString *)sResult:(NSMutableDictionary *)dicPlaceObj { // NSNotificationを作成する NSNotification* notification = [NSNotification notificationWithName:sResult object:self userInfo:dicPlaceObj]; // NSNotificationCenterを取得する NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; // 通知を行う [center postNotification:notification]; } // 通知により受け取った位置情報で、Annotationを追加する。 - (void) addPlacemark:(NSNotification *)notification { // Annotation追加患者データ NSMutableDictionary *dicPatient = [notification userInfo]; // Mapにピン設定 [self setAnnotation:dicPatient]; } // ログイン取得データから訪問予定住所の取得と位置情報取得 - (void) createVisitAndLocation { // 指定時間スリープ(3秒) [NSThread sleepForTimeInterval:3]; // 住所情報の取得 [self setAddrData]; // NSMutableDictionary *dicPatient に、key=@"住所" のValueをセット。 self.mapView.showsUserLocation = YES; // 位置情報取得と通知 [self geocodeAddrAndNortificate]; } - (void) checkMapLocation { // locationManager = [[CLLocationManager alloc] init]; // 位置情報サービスが利用できるかどうかをチェック if ([CLLocationManager locationServicesEnabled]) { locationManager.delegate = self; // 測位開始 [locationManager startUpdatingLocation]; NSLog(@"Location services OK"); } else { NSLog(@"Location services not available."); } } // 住所の緯度経度取得&終了通知 - (void) geocodeAddrAndNortificate { for (int i = 0; i < [patientArray count]; i++) { // NSMutableDictionary *dicPatient = obj; NSMutableDictionary *dicPatient = [patientArray objectAtIndex:i]; // 住所データ有りの場合 if (([dicPatient.allKeys containsObject:@"住所"]) && (![[dicPatient objectForKey:@"住所"] isEqual:[NSNull null]])) { // 位置情報取得後、完了通知 [self geocode:dicPatient]; } } } // 住所から経度緯度を算出(dicPatient = @"住所"有りのみ) - (void) geocode:(NSMutableDictionary *)dicPatient { // 住所 NSString *addressString = [dicPatient objectForKey:@"住所"]; // ロケーション生成 CLGeocoder *geocoder = [[CLGeocoder alloc] init]; [geocoder geocodeAddressString:addressString completionHandler:^(NSArray* placemarks, NSError* error) { // 位置情報取得OK if ((placemarks != nil) && ([placemarks count] > 0)) { // 取得した位置情報を追加(先頭データ) CLPlacemark *placemark = [placemarks objectAtIndex:0]; [dicPatient setValue:placemark forKey:KEY_PLACEMARK]; // 位置情報取得完了を通知 [self notificateGeocodeDone:KEY_GEOCODE_OK :dicPatient]; } else { // 位置情報取得完了を通知 [self notificateGeocodeDone:KEY_GEOCODE_NG :dicPatient]; } }]; }
長かった…
※GCは、Autoモードにしてるので、記述してないです。
今後…