mapItemForCurrentLocation does not find my current location - ios

I am working on the mapkit in ios where I have to trace my route from my current location.
Now, I had assigned my current location i.e. latitude and longitude using the simulator(Debug->location->custom location) but when I try to trace my source I get my source location as nil and due to which I am not able to get the route.
[directionsRequest setSource:[MKMapItem mapItemForCurrentLocation]];
Can any one suggest the possible solution for my problem
Code
MKDirectionsRequest *directionsRequest = [[MKDirectionsRequest alloc] init];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:thePlacemark];
[directionsRequest setSource:[MKMapItem mapItemForCurrentLocation]];
[directionsRequest setDestination:[[MKMapItem alloc] initWithPlacemark:placemark]];
directionsRequest.transportType = MKDirectionsTransportTypeAutomobile;
MKDirections *directions = [[MKDirections alloc] initWithRequest:directionsRequest];

If you are using MapView then there is one delegate method in which you will get your current location without using CLLocationManager.
-(void)viewDidLoad
{
mapView.delegate=self;
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
`enter code here` //Here MKUserLocation will give you current Location and every time will method will call when the location is change...'
}
and if you want only user location then use
MKUserLocation *userlocation=mapView.userlocation

I think you are getting nil location because you are testing it in simulator please run it on real device

https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKMapItem_class/ states mapItemForCurrentLocation does not contain coordinate data for privacy reasons, but here is a simple workaround if you are using a map view and showsUserLocation true:
MKUserLocation* userLocation = self.mapView.userLocation;
MKMapItem* mapItemForCurrentLocation;
if(userLocation.isUpdating && userLocation.isBeingUpdated){
mapItemForCurrentLocation = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:userLocation.location.coordinate addressDictionary:nil]];
mapItemForCurrentLocation.name = #"Current Location";
}

Related

IOS/MapKit: Launch Native Map App by Clicking on MKPlacemark

IOS newb just learning Mapkit. I load a map in my app using MKPlacemark. However some users may want to use more advanced features such as driving directions and for this, I think, they would be better off launching the native app on top of mine (with my app still open in the background when they finish with the regular map app)
I know how to launch the native app from my app using MKMapItem. However, s there a way to launch the native app only after the user touches the place mark.
Here is code I am using.
-(void) geoCodeAndMapIt {
NSString* location = #"156 University Ave, Palo Alto, CA 94301";
NSLog(#"going to map this address: %#",location);
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc]
initWithPlacemark:topResult];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(placemark.coordinate, 5000, 5000);//5000 is meters
region.span.longitudeDelta /= 8.0;
region.span.latitudeDelta /= 8.0;
[self.mapView setRegion:region animated:YES];
[self.mapView addAnnotation:placemark];
// The following MKMapItem class launches the full blown native app. Commenting it out causes the map to load in the app. Otherwise, it fires up the native map app immediately in place of the previous app.
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:placemark];
mapItem.name = self.contact.first;
mapItem.phoneNumber = self.contact.tel;
NSDictionary *options = #{
MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsMapTypeKey:
[NSNumber numberWithInteger:MKMapTypeSatellite],
MKLaunchOptionsShowsTrafficKey:#YES
};
[mapItem setName:#"Name of your location"];
[mapItem openInMapsWithLaunchOptions:options];*/
}
}
];
[mapItem openInMapsWithLaunchOptions:options];
}
Thanks for any suggestions.
You should call the openInMaps only when the MKMapViewDelegate is called on didSelectAnnotation: for ex.
https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKMapViewDelegate_Protocol/index.html#//apple_ref/occ/intf/MKMapViewDelegate
To open the Maps app you could also build the URL yourself with the following:
UIApplication.sharedApplication().openURL(...)
Check this documentation here for the rest:
https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html

CLRegionStateUnknown Until Map Refresh

It seems that I'm running into a delegate issue when using regions with CLLocationManager. When I first run the project, I add various regions to the manager and call requestStateForRegion: to determine if I'm currently within any of them. The manager then calls my didDetermineState: function (rather quickly it seems) but all of the passed CLRegionStates are unknown.
When I go into the Maps app and find my current location, then relaunch my application within a few minutes, the states are found correctly.
I've set about 10 regions where one of which is my hard-coded current location, but my current location still shows as unknown. Any ideas?
manager = [[CLLocationManager alloc] init];
manager.delegate = self;
if ([manager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[manager requestAlwaysAuthorization];
}
for (CLRegion *monitored in [manager monitoredRegions]) {
[manager stopMonitoringForRegion:monitored];
}
NSArray *events = ...;
for (Event *event in events) {
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(latitude, longitude);
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:coord radius:50.0 identifier:[NSString stringWithFormat:#"%#", event.eventID]];
[manager startMonitoringForRegion:region];
}

Annotation along route in MapKit

I'm using MapKit to display directions between locations, and I'm looking for a way to add an annotation that works similarly to the route annotation in the Apple Maps app, where annotations are showing each route's travel time (as shown in the image below). I am already drawing the directions correctly, the problem at hand is how to calculate a pair of coordinates along the route. That is, where to drop the annotation.
I thought about somehow using the MKDirection (which contains complete directions, step by step) but I am not sure how I would generate a pair of coordinates that are somewhere in the middle of the route.
I have not been able to find any kind of support for this in the MapKit documentation. Any ideas?
This is how I generate the route and display it.
- (void)generateRoute {
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = self.destinationMapItem;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle Error
} else {
[self showRoute:response];
}
}];
}
- (void)showRoute:(MKDirectionsResponse *)response {
[self.mapView removeOverlays:self.mapView.overlays];
for (MKRoute *route in response.routes)
{
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
[self fitRegionToRoute];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.strokeColor = [UIColor blueColor];
renderer.alpha = 0.7;
renderer.lineWidth = 4.0;
return renderer;
}
Questioner's edit:
Finally made it work with the help of this answer. I added this to the code below, where it says Here do the magic:
MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint)];
Original answer:
I don't know whether this will work or not. Just my idea on your question.
I guess you would have created the routes as following
(Check my inline comments)
MKDirectionsRequest *request =
[[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = _destination;
request.requestsAlternateRoutes = NO;
MKDirections *directions =
[[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
} else {
for (MKRoute *route in response.routes)
{
[_routeMap addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
//Here do the magic
//MKPolyline confronts to MKOverlay so you can get the coordinate like
//route.polyline.coordinate once you get the coordinate then you can build
//a annotation. A annotation is nothing but a coordinate with some title.
//According to MKOverlay coordinate property it justs gives you the
//center point of the overlay area
[self createAndAddAnnotationForCoordinate:route.polyline.coordinate]
}
}
}];
Adding Annotation
-(void) createAndAddAnnotationForCoordinate : (CLLocationCoordinate2D) coordinate{
MyAnnotation* annotation= [[MyAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = #"Any Title";
annotation.subtitle = #"Any Subtitle";
[yourMap addAnnotation: annotation];
}
If you want to know the middle for swift you can use the following code :
MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
Exemple of use :
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if error == nil {
self.showRoute(response!)
}
else{
print("some error")
}
})
func showRoute(response:MKDirectionsResponse){
for route in response.routes {
self.map.addOverlay(route.polyline, level: MKOverlayLevel.AboveRoads)
self.map.setCenterCoordinate(route.polyline.coordinate, animated: true)
self.map.setRegion(MKCoordinateRegionMakeWithDistance(route.polyline.coordinate, route.distance*0.75, route.distance*0.75), animated: true)
let routeAnnotation = MKPointAnnotation()
routeAnnotation.coordinate = MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
map.addAnnotation(routeAnnotation)
}
}
Perhaps not the most efficient way, but should still likely be quick, would be to calculate the midpoint of your start and end points (i.e., average their lats and longs). Then, iterate through your polyline points checking the distance from each to that midpoint. Take the closest match.
Even if the line is wildly curved, the midpoint will be directly between the ends. Some point on the wild curve is the closest to that external midpoint and is likely a good place to put the annotation.
Once you have an MKRoute, the approximate centre-point can be found using:
route.polyline.coordinate
This returns a CLLocationCoordinate2D that you can use to centre your annotation.
Appreciate this is an old question but I'd been searching for something like this for a while and ended up calculating the centre manually. Turns out it's very straightforward since iOS 8.
I suggest you see this , Integrated with routing.

iOS Google maps giving error

In my App it is possible to tap an button and then in the Google maps app it shows the route from your current location to the destination. It was working till some internal data structures changed and now it is not ;)
The error I get is:
Error Domain=kCLErrorDomain Code=8 "The operation couldn’t be completed. (kCLErrorDomain error 8.)"
Which I looked up in the documentation means (I think):
kCLErrorGeocodeFoundNoResult
The geocode request yielded no result.
Available in iOS 5.0 and later.
Declared in CLError.h.
Currently this is my code: (I'm using hardcoded location for testing right now):
+ (void) showRouteInMapsFromCurrentToLocation:(NSString *) location{
Class mapItemClass = [MKMapItem class];
if (mapItemClass && [mapItemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]){
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:#"Kardingerweg 48, Groningen"
completionHandler:^(NSArray *placemarks, NSError *error) {
if(!error){
CLPlacemark *geocodedPlacemark = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc]
initWithCoordinate:geocodedPlacemark.location.coordinate
addressDictionary:geocodedPlacemark.addressDictionary];
if(placemark && geocodedPlacemark){
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:geocodedPlacemark.name];
NSDictionary *launchOptions = #{MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving};
MKMapItem *currentLocationMapItem = [MKMapItem mapItemForCurrentLocation];
[MKMapItem openMapsWithItems:#[currentLocationMapItem, mapItem] launchOptions:launchOptions];
}
}else{
NSLog(#"%#", [error description]);
}
}];
}
}
Error Code 8 is "kCLErrorGeocodeFoundNoResult", so I suspect you're searching for something with no results,
You are searching for 'Kardingerweg 48, Groningen' it is also not searching in apple map, try with different location.'Kardingerweg,Groningen'.
Thanks to the answer of Viruss mca, I now have the correct form which is:
Kardingerweg 48, NL-2165 VS Groningen

Showing label next to MKPolyline [duplicate]

I'm using MapKit to display directions between locations, and I'm looking for a way to add an annotation that works similarly to the route annotation in the Apple Maps app, where annotations are showing each route's travel time (as shown in the image below). I am already drawing the directions correctly, the problem at hand is how to calculate a pair of coordinates along the route. That is, where to drop the annotation.
I thought about somehow using the MKDirection (which contains complete directions, step by step) but I am not sure how I would generate a pair of coordinates that are somewhere in the middle of the route.
I have not been able to find any kind of support for this in the MapKit documentation. Any ideas?
This is how I generate the route and display it.
- (void)generateRoute {
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = self.destinationMapItem;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle Error
} else {
[self showRoute:response];
}
}];
}
- (void)showRoute:(MKDirectionsResponse *)response {
[self.mapView removeOverlays:self.mapView.overlays];
for (MKRoute *route in response.routes)
{
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
[self fitRegionToRoute];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
renderer.strokeColor = [UIColor blueColor];
renderer.alpha = 0.7;
renderer.lineWidth = 4.0;
return renderer;
}
Questioner's edit:
Finally made it work with the help of this answer. I added this to the code below, where it says Here do the magic:
MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint)];
Original answer:
I don't know whether this will work or not. Just my idea on your question.
I guess you would have created the routes as following
(Check my inline comments)
MKDirectionsRequest *request =
[[MKDirectionsRequest alloc] init];
request.source = [MKMapItem mapItemForCurrentLocation];
request.destination = _destination;
request.requestsAlternateRoutes = NO;
MKDirections *directions =
[[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
} else {
for (MKRoute *route in response.routes)
{
[_routeMap addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
//Here do the magic
//MKPolyline confronts to MKOverlay so you can get the coordinate like
//route.polyline.coordinate once you get the coordinate then you can build
//a annotation. A annotation is nothing but a coordinate with some title.
//According to MKOverlay coordinate property it justs gives you the
//center point of the overlay area
[self createAndAddAnnotationForCoordinate:route.polyline.coordinate]
}
}
}];
Adding Annotation
-(void) createAndAddAnnotationForCoordinate : (CLLocationCoordinate2D) coordinate{
MyAnnotation* annotation= [[MyAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = #"Any Title";
annotation.subtitle = #"Any Subtitle";
[yourMap addAnnotation: annotation];
}
If you want to know the middle for swift you can use the following code :
MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
Exemple of use :
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if error == nil {
self.showRoute(response!)
}
else{
print("some error")
}
})
func showRoute(response:MKDirectionsResponse){
for route in response.routes {
self.map.addOverlay(route.polyline, level: MKOverlayLevel.AboveRoads)
self.map.setCenterCoordinate(route.polyline.coordinate, animated: true)
self.map.setRegion(MKCoordinateRegionMakeWithDistance(route.polyline.coordinate, route.distance*0.75, route.distance*0.75), animated: true)
let routeAnnotation = MKPointAnnotation()
routeAnnotation.coordinate = MKCoordinateForMapPoint(route.polyline.points()[route.polyline.pointCount/2])
map.addAnnotation(routeAnnotation)
}
}
Perhaps not the most efficient way, but should still likely be quick, would be to calculate the midpoint of your start and end points (i.e., average their lats and longs). Then, iterate through your polyline points checking the distance from each to that midpoint. Take the closest match.
Even if the line is wildly curved, the midpoint will be directly between the ends. Some point on the wild curve is the closest to that external midpoint and is likely a good place to put the annotation.
Once you have an MKRoute, the approximate centre-point can be found using:
route.polyline.coordinate
This returns a CLLocationCoordinate2D that you can use to centre your annotation.
Appreciate this is an old question but I'd been searching for something like this for a while and ended up calculating the centre manually. Turns out it's very straightforward since iOS 8.
I suggest you see this , Integrated with routing.

Resources