I've got an issue. I'm using a MKMapView for displaying some annotations. I initialize a map view with default zoom. And it displays some map.
but when i try zooming, tiles not loaded, and map becomes empty. Like this.
I create my Map View via interface builder.
#property (nonatomic, weak) IBOutlet MKMapView* mapView;
What am I doing wrong? Is there any mandatory methods for implementation, that affect on this functional? And yes, there is an internet connection on my device.
Generally this can happens due to internet connection. If you have slow internet connection than it takes time to load map tiles.
About methods i recommended to override below method.
Override MKMapView delegate method -
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
Will call every time you zoom in/out and load map tiles.
PS - provide MKMapViewDelegate to your view controller.
I had the same loading problem till I got the problem working by googling!
Note: Effective ios 8 & later, we need to add a value NSLocationWhenInUseUsageDescription in Info.plist file with our own value as description. This is because showsUserLocation property of **MKMapView** doesn't work straight away. More info here !!!!
//This should be declared in .h file
#property(nonatomic, strong) CLLocationManager *locationManager;
- (void)viewDidLoad {
self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
self.locationManager.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER) {
[self.locationManager requestWhenInUseAuthorization];
}
#endif
[self.locationManager startUpdatingLocation];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) {
self.mapView.showsUserLocation = YES;
}
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region;
region.center = self.locationView.userLocation.coordinate;
MKCoordinateSpan span;
span.latitudeDelta = 0.015; ->Adjust this value to zoom as per your requirement
span.longitudeDelta = 0.015;
region.span = span;
[self.mapView setRegion:region animated:YES];
}
I firmly believe this will yield the expected result without fail, i.e. MKMapView zoom to the current user location.
Related
I need to pick coordinates of current marker position on Google maps. It should update coordinates as marker is moving on map.
I'm using GoogleMaps , GooglePlaces and GooglePlacePicker API's. I can get nearby places using GooglePlacePicker API but I want to pick exact coordinates of location where marker is present.
It is already done in Uber?
Use this,
.h
#interface ViewController : UIViewController <CLLocationManagerDelegate> {
GMSMapView *mapView_;
GMSMarker *marker_;
float currentLatitude;
float currentLongitude;
}
#property(nonatomic,retain) CLLocationManager *locationManager;
#property (nonatomic)CLLocationCoordinate2D coordinate;
.m
- (void)viewDidLoad {
[super viewDidLoad];
_locationManager = [[CLLocationManager alloc] init];
[_locationManager setDelegate:self];
[_locationManager setDistanceFilter:kCLDistanceFilterNone];
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
if (IS_OS_8_OR_LATER) {
if ([_locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[_locationManager requestWhenInUseAuthorization];
}
}
[_locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(#"%#",locations);
CLLocation *currentLoc=[locations objectAtIndex:0];
NSLog(#"CurrentLoc : %#",currentLoc);
_coordinate=currentLoc.coordinate;
currentLatitude = currentLoc.coordinate.latitude;
currentLongitude = currentLoc.coordinate.longitude;
}
-(void)plotMarkerForLatitude:(float)latitude andLongitude:(float)longitude {
// Now create maker on current location
if (marker_ == NULL) {
marker_ = [[GMSMarker alloc] init];
}
CLLocationCoordinate2D target =
CLLocationCoordinate2DMake(latitude, longitude);
marker_.position = target;
marker_.title = #"title";
marker_.appearAnimation = kGMSMarkerAnimationPop;
NSLog(#"%f %f",latitude,longitude);
marker_.icon = [UIImage imageNamed:#"marker"];
marker_.snippet = #"Address";
marker_.map = mapView_;
}
In Plist :
<key>NSLocationWhenInUseUsageDescription</key>
<string>Allow access to get your current location</string>
This can possibly be done by implementing the GMSMapViewDelegate protocol. See the guide to events and the list of methods on the GMSMapViewDelegate.
As mentioned in the documentation,
Applications can use this event to trigger a refresh of markers or other content being displayed on the GMSMapView, rather than, for example, reloading the content on every camera change.
You may also check Google Maps SDK for iOS for more information on what other APIs you can use along with Maps iOS SDK to build location-relevant apps and sites.
Using iOS 8 and have NSLocationAlwaysUsageDescription set.
Here is my code:
#import "GeoLocation.h"
#import "AppDelegate.h"
#implementation GeoLocation
- (id)init
{
self = [super init];
if (self)
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 5; //in meters
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
self.numberOfUpdates = 0;
[self.locationManager startUpdatingLocation];
}
return self;
}
// Wait for location callbacks
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"Location Updated: %#", [locations lastObject]);
}
- (float) getLatitude
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSLog(#"getLatitude: %f", self.locationManager.location.coordinate.latitude);
appDelegate.gMyProfile.latitude = self.locationManager.location.coordinate.latitude;
return self.locationManager.location.coordinate.latitude;
}
- (float) getLongitude
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSLog(#"getLongitude: %f", self.locationManager.location.coordinate.longitude);
appDelegate.gMyProfile.longitude = self.locationManager.location.coordinate.longitude;
return self.locationManager.location.coordinate.longitude;
}
- (float) getAltitude
{
return self.locationManager.location.altitude;
}
When the user logs in, I instantiate a GeoLocation object, which turn on starts updating the location.
If I use
self.locationManager.distanceFilter = 5;
and walk around my house, didUpdateLocations won't fire.
However, if I get rid of
self.locationManager.distanceFilter = 5;
didUpdateLocations will fire every second.
Anything you guys see that I am not. I would love for this to update when the user moves 5 meters.
Adding a distance filter will most likely cause iOS to take the horizontalAccuracy into account.
Since you are inside you will be unlikely to get location with a horizontalAccuracy of 5 which is the best accuracy.
Without the distance filter you are probably just getting the same location or another location within the distance in horizontalAccuracy.
Generally you will only get an accuracy of 5m meters when you are outside in clear view of the satellites above you and not next to tall buildings that can reflect and obscure the signal.
My question is as follows:
When is the location updated when using Location Services? When I called startUpdatingLocation I expected to already have a location returned so I can retrieve latitude and longitude for my iOS project. These are required parameters for a web service as well but it seems they are returned as nil.
The interface conforms to CLLocationManagerDelegate protocol and I have implemented the methods for it. Anyway here is my code:
- (void)viewDidLoad
{
super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
if([self.parentViewController isKindOfClass:[BTMainViewController class]])
{
BTMainViewController *parent = (BTMainViewController *)self.parentViewController;
self.sessionKey = parent.session;
NSLog(#"URL is %# ", self.sessionKey);
}
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// also set the URL
self.serviceURL = [apiURL stringByAppendingString:#"/get_employee_closestlocations"];
// set tableview delegate and data source
self.tableView.delegate = self;
self.tableView.dataSource = self;
// adjust for EdgeInset with navigation bar.
self.tableView.contentInset = UIEdgeInsetsMake(64.0f, 0.0f, 0.0f, 0.0f);
// fetch the locations here
[locationManager startUpdatingLocation];
[self fetchLocations];
}
didUpdateToLocation implementation
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = [locationManager location];
[locationManager stopUpdatingLocation];
if(currentLocation != nil)
{
[self setLongitude:[NSNumber numberWithDouble: currentLocation.coordinate.longitude]];
[self setLatitude:[NSNumber numberWithDouble: currentLocation.coordinate.latitude]];
}
}
Any suggestions would be welcome and thanks in advance!
The delegate method you are using is deprecated. You should use locationManager:didUpdateLocations: and then access the location update from the end of the array -
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *currentLocation = (CLLocation *)[locations lastObject];
...
}
It can take some time to get a location fix, particularly as you have specified kCLLocationAccuracyBest - iOS may need to start up the GPS receiver if it hasn't been used recently and then the GPS needs to obtain a fix - if the device is inside or has bad GPS reception this can further delay the acquisition of a location. You can get an idea of the time to obtain a fix by restarting your device, starting the maps application and tapping the location "arrow" and waiting until the blue location circle collapses down to the blue & white marker.
I would suggest that you invoke your [self fetchLocations]; from the didUpdateLocations method
Also, the Core Location documentation states -
When requesting high-accuracy location data, the initial event
delivered by the location service may not have the accuracy you
requested. The location service delivers the initial event as quickly
as possible. It then continues to determine the location with the
accuracy you requested and delivers additional events, as necessary,
when that data is available.
So, there is a risk that when you do access the location, it may not be particularly accurate. You can look at the horizontalAccuracy property of the CLLocation and decide whether you want to accept this location or wait for a more accurate location (bearing in mind that it may not arrive if the device is inside or has poor reception)
You need to do in viewDidLoad like this
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
mapView.delegate = self;
mapView.showsUserLocation = YES; // Enable it when we want to track user's current location.
}
after doing this the below delegate method will automatically called.
- (void)mapView:(MKMapView *)mapView
didUpdateUserLocation:
(MKUserLocation *)userLocation
{
self.mapView.centerCoordinate = userLocation.location.coordinate;
}
I init my mapviewControler like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstShow=TRUE;
self.mapView.delegate=self;
self.mapView.showsUserLocation=YES;
self.cllmng=[[CLLocationManager alloc]init];
self.cllmng.delegate=self;
self.cllmng.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
self.cllmng.distanceFilter=50;
[self.cllmng startUpdatingLocation];
}
and I make mapviewControler implement CLLocationManagerDelegate, and implement - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations in my code.
The problem I have is that I want to init map view centred on current user location with a proper scale. I intend to do this by
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation * currentLoci=[locations lastObject];
MKCoordinateRegion r;
MKCoordinateSpan span;
span.latitudeDelta = 1;
span.longitudeDelta = 1;
r.span = span;
CLLocationCoordinate2D c;
c.longitude=currentLoci.coordinate.longitude;
c.latitude=currentLoci.coordinate.latitude;
r.center = c;
[self.mapView setRegion:r animated:YES];
}
But sometimes, after [self.cllmng startUpdatingLocation] called in the -(void) viewDidload, I cannot get a call of - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations immediately. Thus, the map view just init showing user location but showing the whole Australia. How can I set the scale/span in the init of map view even didUpdateLocations is not triggered? THX!
INstead of modifying the region yourself using a CLLocation manager you could just set the trackingMode of the mapView and it'll center and zoom in on your position automatically. It will be possible for the user to disable the tracking mode if they start dragging the map around, but you can disable user interaction if you really want them to have no control. Here is how to do it
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
ref: https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html#//apple_ref/occ/instm/MKMapView/setUserTrackingMode:animated:
iOS 11.x Swift 4.0 Craigs answer, updated.
mapView.showsUserLocation = true
Not so obvious I fear.
I'm getting an error in my IOS application. I've searched in the google and here, but the specific solution was not found!
I have a viewController called mapView that I use in two moments in my app, this view contains a MKMapView and the code.
In my mapView.h there is:
#property (strong, nonatomic) IBOutlet MKMapView *mapSpot;
And in my mapView.m there is:
- (void)viewDidLoad {
[super viewDidLoad];
[mapSpot setShowsUserLocation:YES];
}
- (void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([userLocation coordinate], 500, 500);
[mapSpot setRegion:region animated:YES];
}
So, in the first moment I load the mapView into other ViewController using:
#property (strong, nonatomic) ViewMap *mapView;
mapView = [[ViewMap alloc] initWithNibName:#"ViewMap" bundle:nil];
[self.view addSubview:[mapView view]];
I unload that ViewController and in another ViewController in other moment I load the MapView again, but in this moment the method: - (void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation not is called.
I verify if the first ViewController was unloaded and that was.
When I load the second ViewController there is a new instace of MapView, but not call the delegate method.
Anyone know something about that?
Thanks
==================================================================================
EDIT AND SOLVED:
the problem is in the way you are adding the view, in this line
[self.view addSubview:[mapView view]];
if you only add the view the controller code is not executed, instead of that you has to present the mapView, for example:
[self presentViewController:mapView animated:YES completion:nil];
The problem above, maybe happen because I'm using simulator to test app, and how the simulator not change the position map not get didUpdateUserLocation:
That's the unique explanation that I could have after the review the code, organize the classes read documentation and get error again.
Now, I'm using CLLocationManager to get position, after getting first time the position I stop it.
In the future I'll implement a system that track the user path, so using CLLocationManager is inevitable.
The mapView.m code after changes:
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation *loc = [locations lastObject];
// store the location to use in any moment, it needs to be checked because the first time when get the coordinate not pass infos to load places according the current position
if (!location.latitude) {
location = [loc coordinate];
// set center the map at the current position
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(location, 500, 500);
[mapSpotView setRegion:region animated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"loadPlaces" object:nil];
[locationManager stopUpdatingLocation];
}
}
if someone has a better solution, please, post here!
That's it!