signal SIGABRT, when trying to get distance to annotations - objective-c

I'm trying to calulate the distance between the userLocation and my annotations (from plist), But every time im run the mapView im getting signal SIGABRT error.
I'm doing the calculate in my mapViewController.m and want to show the calculated values in my tableViewController.
In my Annotations.h
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface Annotation : NSObject <MKAnnotation>
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, assign) CLLocationDistance distance;
#property (nonatomic, copy) NSString * title;
#property (nonatomic, copy) NSString * subtitle;
#property (nonatomic, copy) NSString * sculptureIdKey;
#end
I'm synthesize distance = _distance; in my Annotations.m file.
In my mapViewController.m im doing the calculations
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
for (Annotation *annotation in self.mapView.annotations)
{
CLLocationCoordinate2D coord = [annotation coordinate];
CLLocation *annLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
annotation.distance = [annLocation distanceFromLocation:newLocation];
CLLocationDistance calculatedDistance = [annLocation distanceFromLocation:newLocation];
annotation.distance = calculatedDistance;
NSLog(#"Calculated Distance:%.2f m\n", calculatedDistance);
}
}
And in my tableViewController.h
#import "mainViewController.h"
#import "mapViewController.h"
#import "Annotation.h"
#interface ListViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, CLLocationManagerDelegate>
#property (readonly) CLLocationCoordinate2D selectedCoordinate;
#property (nonatomic, assign) CLLocationDistance distance;
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) CLLocation *userLocation;
#property (nonatomic, strong) NSArray *locationsArray;
#end
And tableViewController.m
#import "ListViewController.h"
#import "customCell.h"
#interface ListViewController ()
#end
#implementation ListViewController
#synthesize locationsArray = _locationsArray;
#synthesize locationManager = _locationManager;
#synthesize selectedCoordinate = _selectedCoordinate;
#synthesize distance = _distance;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.locationsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
customCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell)
{
cell = [[customCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.customTitle.text = [[self.locationsArray objectAtIndex:indexPath.row] valueForKey:#"sculptureNameKey"];
cell.customSubTitle.text = [[self.locationsArray objectAtIndex:indexPath.row] valueForKey:#"sculptureAddressKey"];
cell.distanceLabel.text = [NSString stringWithFormat:#"Nice distance:%f m\n", _distance];
return cell;
}
My output in log is as follow
2013-02-15 11:05:50.769 TalkingSculpture[11639:c07] Calculated Distance:83971.36 m
2013-02-15 11:05:50.770 TalkingSculpture[11639:c07] Calculated Distance:83406.16 m
2013-02-15 11:05:50.771 TalkingSculpture[11639:c07] Calculated Distance:86002.30 m
2013-02-15 11:05:50.771 TalkingSculpture[11639:c07] -[MKUserLocation setDistance:]: unrecognized selector sent to instance 0xee4f080
2013-02-15 11:05:50.772 TalkingSculpture[11639:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MKUserLocation setDistance:]: unrecognized selector sent to instance 0xee4f080'
*** First throw call stack:
(0x1b44012 0x1460e7e 0x1bcf4bd 0x1b33bbc 0x1b3394e 0x3ef8 0x3637e 0x3593f 0x339c5 0x2f175 0x1b03920 0x1ac6d31 0x1aeac51 0x1ae9f44 0x1ae9e1b 0x1a9e7e3 0x1a9e668 0x3a4ffc 0x43ed 0x2535)
libc++abi.dylib: terminate called throwing an exception

In your for-loop where you set the annotation distance, you need to check that the annotation is not MKUserLocation since it is one of self.mapView.annotations. Otherwise, "annotation.distance" will apply to MKUserLocation, which doesn't have a distance property. Here's the update to your code:
for (Annotation *annotation in self.mapView.annotations)
{
if (![annotation isKindOfClass:[MKUserLocation class]]) //<-- Need this check
{
CLLocationCoordinate2D coord = [annotation coordinate];
CLLocation *annLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
annotation.distance = [annLocation distanceFromLocation:newLocation];
CLLocationDistance calculatedDistance = [annLocation distanceFromLocation:newLocation];
annotation.distance = calculatedDistance;
NSLog(#"Calculated Distance:%.2f m\n", calculatedDistance);
}
}

Related

Problems with Location Manager

I've been stuck on this problem for ages and I'm sure the reason is that I don't know enough about objective-c. I've only just started using coding with it!
Anyway I'm trying to design an app that tracks the current distance travelled and also displays the route that have been taken using MKPolyLine. I've got MKPolyLine sorted now but the problem I;m having is with getting the current distance. I think the code is OK but I think i'm doing something funny with location manager.
I've done a bit of debugging and found that my second locationManager method does not get called.
Here is the code below, if someone can take a quick look and just point me in the right direct it would be greatly appreciated.
Many Thanks.
.m :
#interface StartCycleViewController ()
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (strong, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic, strong) UIView *containerView;
#property (nonatomic, strong) CLLocationManager *distanceManager;
#end
#implementation StartCycleViewController
static double totalDistanceBetween;
#synthesize cycleLocation = _cycleLocation;
#synthesize currentCycleLocation = _currentCycleLocation;
#synthesize mapView;
- (void)viewDidLoad
{
[super viewDidLoad];
[self startCycleLocation];
[mapView setDelegate:self];
self.locations = [NSMutableArray array];
}
- (void)dealloc
{
self.locationManager.delegate = nil;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - startCycleLocation
- (void)startCycleLocation{
if (!_cycleLocation){
_cycleLocation = [[CLLocationManager alloc]init];
_cycleLocation.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_cycleLocation.distanceFilter = 5;
_cycleLocation.delegate = self;
_startLocation = nil;
}
[_cycleLocation startUpdatingLocation];
}
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"%#",error);
if ( [error code] != kCLErrorLocationUnknown ){
[self stopLocationManager];
}
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
if (location.horizontalAccuracy < 0)
return;
[self.locations addObject:location];
NSUInteger count = [self.locations count];
if (count > 1) {
// only both to add new location if distance has changed by more than 5 meters
[self.locations addObject:location];
count = [self.locations count];
CLLocationCoordinate2D coordinates[count];
for (NSInteger i = 0; i < count; i++) {
coordinates[i] = [(CLLocation *)self.locations[i] coordinate];
}
MKPolyline *oldPolyline = self.polyline;
self.polyline = [MKPolyline polylineWithCoordinates:coordinates count:count];
[self.mapView addOverlay:self.polyline];
if (oldPolyline)
[self.mapView removeOverlay:oldPolyline];
}
NSLog(#"didUpdateToLocation2: %#", location);
}
- (void) stopLocationManager {
[self.cycleLocation stopUpdatingLocation];
}
#pragma mark - MKMapViewDelegate
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
NSLog(#"PolyLine Started");
if ([overlay isKindOfClass:[MKPolyline class]])
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
[self.mapView setVisibleMapRect:overlay.boundingMapRect animated:YES];
renderer.strokeColor = [[UIColor redColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 3;
return renderer;
NSLog(#"MKPolyline Rendering");
}
return nil;
}
- (IBAction)stopActivity:(id)sender {
[self stopLocationManager];
NSLog(#"Stopped");
}
-(void)distanceManager:(CLLocationManager *)manager didUpdateLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"Current Distance Started");
if (self.startLocation == nil)
{
totalDistanceBetween = 0;
_startLocation = newLocation;
}
CLLocationDistance distanceBetween = [newLocation distanceFromLocation:_startLocation ];
self.startLocation = newLocation;
totalDistanceBetween += distanceBetween;
NSString *cycleDistanceString = [[NSString alloc]
initWithFormat:#"%f",
totalDistanceBetween];
_CurrentDistance.text = cycleDistanceString;
NSLog(#"cycleDistance is %#", cycleDistanceString);
}
#end
.h :
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "ViewController.h"
#import <MapKit/MapKit.h>
#import <AVFoundation/AVFoundation.h>
#interface StartCycleViewController : UIViewController <NSXMLParserDelegate, CLLocationManagerDelegate, MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet UILabel *longitudeLabel;
#property (weak, nonatomic) IBOutlet UILabel *latitudeLabel;
#property (nonatomic,strong) CLLocation *currentCycleLocation;
#property (nonatomic,strong) CLLocationManager *cycleLocation;
#property (nonatomic,strong) CLLocation *startLocation;
#property (strong, nonatomic) IBOutlet UILabel *CurrentDistance;
- (IBAction)stopActivity:(id)sender;
#property(nonatomic, strong) MKPolyline *polyline;
#property (nonatomic,strong) NSMutableArray *locations;
#property (nonatomic,strong) NSNumber *currentSpeed;
#property (nonatomic,strong) NSMutableArray *locationHistory;
- (void) stopLocationManager;
#end

UITableView isn't working

Im trying to make a comments UITableView inside a UIViewController but I'm having problems. If I set the text directly, it shows up (cell.username.text) but if I try to fill it with a PFQuery (parse.com) nothing shows up
//DetailViewController.h
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#interface DetailViewController : UIViewController{
}
#property (strong, nonatomic) PFObject *place;
#property (strong, nonatomic) IBOutlet PFImageView *userPhoto;
#property (strong, nonatomic) IBOutlet UILabel *username;
#property (strong, nonatomic) IBOutlet UILabel *message;
#property (strong, nonatomic) IBOutlet UILabel *distance;
#property (strong, nonatomic) IBOutlet UILabel *checkCount;
#property (strong, nonatomic) IBOutlet PFImageView *photo;
#property (strong, nonatomic) IBOutlet UIScrollView *scroller;
#property (strong, nonatomic) IBOutlet UITableView *commentsTableView;
- (IBAction)checkMarkButton:(UIButton *)sender;
#end
//DetailViewController.m
#import "DetailViewController.h"
#import "CommentsViewController.h"
#interface DetailViewController (){
CommentsViewController *test;
}
#end
#implementation DetailViewController
#synthesize place;
#synthesize userPhoto, message, username, checkCount, photo, scroller, commentsTableView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
test = [[CommentsViewController alloc] init];
self.commentsTableView.delegate = test;
self.commentsTableView.dataSource = test;
[test commentsQuery:place];
}
//CommentsViewController.h
#import <Parse/Parse.h>
#interface CommentsViewController : UITableViewController{
}
#property (strong, nonatomic) PFObject *place;
- (void)commentsQuery:(PFObject *)object;
#end
//CommentsViewController.m
#import "CommentsViewController.h"
#import "DetailViewController.h"
#import "CommentsCell.h"
#interface CommentsViewController (){
NSArray *commentsArray;
}
#end
#implementation CommentsViewController
#synthesize place;
- (void)commentsQuery:(PFObject *)object {
place = object;
PFQuery *query1 = [PFQuery queryWithClassName:#"activity"];
[query1 whereKey:#"type" equalTo:#"comment"];
[query1 whereKey:#"place" equalTo:place];
[query1 orderByDescending:#"createdAt"];
[query1 findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error){
commentsArray = [[NSArray alloc]initWithArray:objects];
NSLog(#"%lu", (unsigned long)[commentsArray count]);
}
}];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [commentsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
static NSString *CellIdentifier = #"Cell";
CommentsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[CommentsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
PFObject *tempObj = [commentsArray objectAtIndex:indexPath.row];
cell.username.text = #"username";
cell.comment.text = [tempObj objectForKey:#"content"];
cell.userThumbnail.file = [tempObj objectForKey:#"userThumbnail"];
[cell.userThumbnail loadInBackground];
return cell;
}
#end
My problem was calling reloadData. I followed the answer here and it works UITableView delegate and datasource in a separate class after parsing

checking which map view annotation is tapped on mkmapview

I am having problem in knowing which annotation is tapped on MKMapView.
let me explain my problem, there is a simple view controller on which map view is loaded.
my annotation class "MapViewAnnotation.h" is as follows
#interface MapViewAnnotation : NSObject <MKAnnotation>
{
NSString *title;
CLLocationCoordinate2D coordinate;
NSString *sID;
NSString *zipCode;
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString *sID;
#property (nonatomic, retain) NSString *zipCode;
- (id)initWithTitle:(NSString *)titleOfPin andStoreId:(NSString *)storeIdForDetails andCoordinate:(CLLocationCoordinate2D)coordinateOfPin andZipCode:(NSString *)zip;
here is my "MapViewAnnotation.m" file.
#import "MapViewAnnotation.h"
#import <MapKit/MapKit.h>
#implementation MapViewAnnotation
#synthesize title, coordinate,storeId,zipCode;
- (id)initWithTitle:(NSString *)titleOfPin andStoreId:(NSString *)storeIdForDetails andCoordinate:(CLLocationCoordinate2D)coordinateOfPin andZipCode:(NSString *)zip
{
[super init];
title = titleOfPin;
coordinate = coordinateOfPin;
sID = storeIdForDetails;
zipCode = zip;
return self;
}
-(void)dealloc
{
[title release];
[super dealloc];
}
#end
and this is my viewcontroller.m file
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
//I want to access the sID property of that annotation here. PLEASE HELP ME HOW CAN I DO THAT
if (!storeDetailControllerObject) {
storeDetailControllerObject = [[StoreDetailController alloc]init];
}
// storeDetailControllerObject.storeId = [view.annotation storeId];
[self.navigationController pushViewController:storeDetailControllerObject animated:YES];
From the MKMapViewDelegate protocol reference:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view;
If you handle the event in this method you may know which annotation was selected.
You have to set the MKMapView's delegate and to declare that you class implements the MKMapViewDelegate.
This should work:
MapViewAnnotation *mapViewAnnotation = (MapViewAnnotation*)view.annotation;
if( [mapViewAnnotation isKindOfClass:[MapViewAnnotation class]] ){
storeDetailControllerObject.storeId = mapViewAnnotation.storeId;
}

viewForAnnotation throws error when returning nil

So I have implemented my viewForAnnotation as such
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
static NSString *identifier = #"id";
if ([annotation isKindOfClass:[infl8Node class]]) {
NSLog(#"Creating a pin");
MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else {
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
return annotationView;
}
return nil;
}
However I am still running into this error:
2012-11-18 22:12:35.608 Infl8[5960:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[infl8Node coordinate]: unrecognized selector sent to instance 0x846f460'
Does anyone know what could be causing this error? I have traced it to the case where the annotation is of the class MKUserLocation.
EDIT:
Here is the infl8Node.h file:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface infl8Node : NSObject <MKAnnotation>
#property (nonatomic, strong) NSString *accountName;
#property (nonatomic, strong) NSString *status;
#property (nonatomic, strong) CLLocation *location;
#property (nonatomic, strong) NSDictionary *address;
- (id) initWithDictionary:(NSDictionary *)dict;
- (MKMapItem *) mapItem;
#end
A class that implements the MKAnnotation protocol must implement the coordinate property.
The infl8Node class does not appear to do that which is why you are getting that unrecognized selector error.
At a minimum, the class will need to implement a coordinate method which returns the coordinate associated with its location.

Custom curent location Annotation pin not updating with core location

Trying to add a custom pin for current location, However the location does not update. Even after setting setShowsUserLocation = YES;
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if ([[annotation title] isEqualToString:#"Current Location"]) {
self.image = [UIImage imageNamed:[NSString stringWithFormat:#"cursor_%i.png", [[Session instance].current_option cursorValue]+1]];
}
However, if I set to return nil; everything works fine, but I lose the custom image. I really want to get this to work. Any help would be greatly appreciated.
As you've seen the setShowsUserLocation flag only shows the current location using the default blue bubble.
What you need to do here listen for location updates from the phone and manually reposition your annotation yourself. You can do this by creating a CLLocationManager instance and remove and replace your annotation whenever the Location Manager notifies its delegate of an update:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// update annotation position here
}
To reposition the coordinates, I have a class, Placemark, that conforms to the protocol MKAnnotation:
//--- .h ---
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface Placemark : NSObject <MKAnnotation> {
}
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString *strSubtitle;
#property (nonatomic, retain) NSString *strTitle;
-(id)initWithCoordinate:(CLLocationCoordinate2D) coordinate;
- (NSString *)subtitle;
- (NSString *)title;
#end
//--- .m ---
#implementation Placemark
#synthesize coordinate;
#synthesize strSubtitle;
#synthesize strTitle;
- (NSString *)subtitle{
return self.strSubtitle;
}
- (NSString *)title{
return self.strTitle;
}
-(id)initWithCoordinate:(CLLocationCoordinate2D) c {
self.coordinate = c;
[super init];
return self;
}
#end
Then in my mapview controller I place the annotation with:
- (void) setPlacemarkWithTitle:(NSString *) title andSubtitle:(NSString *) subtitle forLocation: (CLLocationCoordinate2D) location {
//remove pins already there...
NSArray *pins = [mapView annotations];
for (int i = 0; i<[pins count]; i++) {
[mapView removeAnnotation:[pins objectAtIndex:i]];
}
Placemark *placemark=[[Placemark alloc] initWithCoordinate:location];
placemark.strTitle = title;
placemark.strSubtitle = subtitle;
[mapView addAnnotation:placemark];
[self setSpan]; //a custom method that ensures the map is centered on the annotation
}