2012-08-23 6 views
1

"카페"와 같은 툴바 버튼을 한 번 클릭하면 카페가 보이는지도 영역에 표시됩니다. Google Places API에서 데이터를 가져옵니다. 단추를 클릭 한 후 핀이 표시되지 않는 것을 제외하면 모두 잘 작동합니다.MapKit :지도를 스크롤 할 때까지 주석보기가 표시되지 않습니다.

확실한 지연 시간이 예상됩니다. 그러나 백그라운드 대기열에서 페치를 수행하고 기다리는 동안 회전하는 바퀴를 놓고 페칭 및 구문 분석이 완료되면 회전하는 바퀴가 숨겨집니다. 따라서 나는 회전하는 바퀴가 사라지는 순간에 데이터가 있다고 확신합니다. 그러나지도를 스크롤 할 때까지 핀이 나타나지 않습니다.

나는 스크롤 맵이 mapView:regionDidChangeAnimated: 만 트리거한다는 것을 알 수있다. 그러나 나는 그것이 그 문제와 어떻게 관련이 있는지 알 수 없다. 누구든지 도와 줄 수 있습니까?

소스 코드가 ViewController.m인데, 거의 모든 것이 발생합니다.

#import "ViewController.h" 
#import "MapPoint.h" 
#import "MBProgressHUD.h" 

#define kGOOGLE_API_KEY @"AIzaSyCHqbAoY7WCL3l7x188ZM4ciiTixejzQ4Y" 
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 



@interface ViewController() <CLLocationManagerDelegate, MKMapViewDelegate> 
@property (weak, nonatomic) IBOutlet MKMapView *mapView; 
@property (strong, nonatomic) CLLocationManager *locationManager; 
@property int currentDist; 
@property CLLocationCoordinate2D currentCentre; 
@end 

@implementation ViewController 
@synthesize mapView = _mapView; 
@synthesize locationManager = _locationManager; 
@synthesize currentDist = _currentDist; 
@synthesize currentCentre = _currentCentre; 

- (void)viewDidLoad{ 
    [super viewDidLoad]; 
} 


- (void)viewDidUnload{ 
    [self setMapView:nil]; 
    [super viewDidUnload]; 
} 

// set the map region after launching 
-(void)viewWillAppear:(BOOL)animated 
{ 
    //Instantiate a location object. 
    self.locationManager = [[CLLocationManager alloc] init]; 

    //Make this controller the delegate for the location manager. 
    self.locationManager.delegate = self; 

    //Set some parameters for the location object. 
    [self.locationManager setDistanceFilter:kCLDistanceFilterNone]; 
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; 

    // order: latitude(纬度), longitude(经度) 
    CLLocationCoordinate2D center = self.locationManager.location.coordinate; 

    // 单位是degree 
    MKCoordinateSpan span = MKCoordinateSpanMake(0.03, 0.03); 

    MKCoordinateRegion region = MKCoordinateRegionMake(center, span); 

    [self.mapView setRegion:region animated:YES]; 

    // NSLog(@"currentCentre is (%f , %f)", self.currentCentre.latitude, self.currentCentre.longitude); 
} 

// Get place tpye from button title 
// All buttons share this one method 
- (IBAction)toolbarButtonPressed:(id)sender 
{ 
    UIBarButtonItem *button = (UIBarButtonItem *)sender; 
    NSString *buttonTitle = [button.title lowercaseString]; 

    //Use this title text to build the URL query and get the data from Google. 
    [self queryGooglePlaces:buttonTitle]; 

} 

// Parse response JSON data 
-(void)parseData:(NSData *)responseData { 

    NSError* error; 
    NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData 
                 options:kNilOptions 
                 error:&error]; 

    //The results from Google will be an array obtained from the NSDictionary object with the key "results". 
    NSArray* places = [json objectForKey:@"results"]; 
    [self plotPositions:places]; 
    NSLog(@"Plot is done"); 
} 

// Format query string 
-(void) queryGooglePlaces: (NSString *) googleType { 

    // query string 
    NSString *url = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=%@&types=%@&sensor=true&key=%@", self.currentCentre.latitude, self.currentCentre.longitude, [NSString stringWithFormat:@"%i", _currentDist], googleType, kGOOGLE_API_KEY]; 

    //string to URL 
    NSURL *googleRequestURL=[NSURL URLWithString:url]; 

    // Retrieve data from the query URL by GCD 
    dispatch_async(kBgQueue, ^{ 
     NSData* data = [NSData dataWithContentsOfURL: googleRequestURL]; 
     [self parseData:data]; 
     [MBProgressHUD hideHUDForView:self.view animated:YES]; 
    }); 

    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; 
    hud.labelText = @"Please Wait.."; 
} 

#pragma mark - Map View Delegate 

// called many times when map scrolling or zooming 
// Use this to get currentCentre and currentDist (radius) 

-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { 
    //Get the east and west points on the map so you can calculate the distance (zoom level) of the current map view. 
    MKMapRect mRect = self.mapView.visibleMapRect; 
    MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), MKMapRectGetMidY(mRect)); 
    MKMapPoint westMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMidY(mRect)); 

    //Set your current distance instance variable. 
    self.currentDist = MKMetersBetweenMapPoints(eastMapPoint, westMapPoint); 

    //Set your current center point on the map instance variable. 
    self.currentCentre = self.mapView.centerCoordinate; 

    // NSLog(@"currentCentre is (%f , %f)", self.currentCentre.latitude, self.currentCentre.longitude); 

} 

// Setup annotation objects 
-(void)plotPositions:(NSArray *)data { 
    // 1 - Remove any existing custom annotations but not the user location blue dot. 

    for (id<MKAnnotation> annotation in self.mapView.annotations) { 
     if ([annotation isKindOfClass:[MapPoint class]]) { 
      [self.mapView removeAnnotation:annotation]; 
     } 
    } 
    // 2 - Loop through the array of places returned from the Google API. 
    for (int i=0; i<[data count]; i++) { 
     //Retrieve the NSDictionary object in each index of the array. 
     NSDictionary* place = [data objectAtIndex:i]; 
     // 3 - There is a specific NSDictionary object that gives us the location info. 
     NSDictionary *geo = [place objectForKey:@"geometry"]; 
     // Get the lat and long for the location. 
     NSDictionary *loc = [geo objectForKey:@"location"]; 
     // 4 - Get your name and address info for adding to a pin. 
     NSString *name=[place objectForKey:@"name"]; 
     NSString *vicinity=[place objectForKey:@"vicinity"]; 
     // Create a special variable to hold this coordinate info. 
     CLLocationCoordinate2D placeCoord; 
     // Set the lat and long. 
     placeCoord.latitude=[[loc objectForKey:@"lat"] doubleValue]; 
     placeCoord.longitude=[[loc objectForKey:@"lng"] doubleValue]; 

     // 5 - Create a new annotation. 
     MapPoint *placeObject = [[MapPoint alloc] initWithName:name address:vicinity coordinate:placeCoord]; 
     [self.mapView addAnnotation:placeObject]; 
    } 
    NSLog(@"addAnnotation is done"); 

} 

// Setup annotation view 
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { 
    // Define your reuse identifier. 
    static NSString *identifier = @"MapPoint"; 

    if ([annotation isKindOfClass:[MapPoint class]]) { 
     MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier]; 

     if (annotationView == nil) { 
      annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]; 
     } else { 
      annotationView.annotation = annotation; 
     } 
     annotationView.enabled = YES; 
     annotationView.canShowCallout = YES; 
     annotationView.animatesDrop = YES; 


     // NSLog(@"annotation view is added"); 

     return annotationView; 

    } 
    return nil; 
} 

@end 

답변

5

몇 가지 :

는 UI 스레드에서 실행되도록 removeAnnotation 및 addAnnotation 코드를 이동

, 예컨대 :

dispatch_async (dispatch_get_main_queye(),^
{ 
[self.mapView addAnnotation:placeObject]; 
}); 

의 viewDidLoad로 viewWillAppear 초기화 코드를 이동합니다. viewWillAppear은 뷰 컨트롤러의 수명 동안 여러 번 호출 될 수 있습니다.

+0

감사합니다. 문제가 쭈그러 들었습니다 :) 주 스레드에서 실행되는 코드를 수정 해 넣으십시오. – Philip007

+0

아마도 메인 스레드에서 plotPositions를 호출하고 더 깨끗하게 만들 수 있습니다. – CSmith

+0

맞습니다. 이를 위해 NSArray를 @property로 추가하여 응답 데이터를 저장합니다. 따라서 plotPositions와 parseData는 중첩되는 대신 서로 분리 될 수 있습니다. 그런 다음 배경 큐에 parseData를 배치하고 주 큐에 plotPositions를 배치했습니다. 훨씬 깨끗해 보입니다. 귀하의 소중한 조언에 감사드립니다. – Philip007

관련 문제