How to store CLLocationCoordinate2D?
Asked Answered
D

3

7

I'm attempting to build an application that builds and saves routes similar to map my run. I'm using the Breadcrumb sample code, specifically the CrumbPath and CrumbPathView as the base of my routes, from Apple. Two questions:

  1. If I try to access the MKMapPoint *points object of the CrumbPath like so:

    [_route lockForReading];
    NSLog(@"%@", _route.points);
    NSLog(@"%d", _route.pointCount);
    [_route unlockForReading];
    

    my app crashes, saying:

    Thread 1: EXC_BAD_ACCESS (code: 1, address: 0x9450342d)
    

    Which I have a hard time understanding, because within the CrumbPath.m file, the folks at apple write to the "array" by explicitly acquiring the write lock, and then unlocking it, but if I acquire the read lock and attempt to read from it, it crashes.

  2. The reason I attempt to access the points is in an attempt to get the MKMapPoints, convert them to CLLocationCoordinate2D objects, and save them so I can redraw the polyline at the user's request. Since I cannot get access to the points, I attempt to save the CLLocationCoordinate2D objects from my locationManager that I send to the _route in an array to upload to my Parse backend, but I always get an error saying:

    Sending 'CLLocationCoordinate2D' to parameter of incompatible type 'id'
    

    Which isn't making this any easier. Does anybody have any insight to why I'm getting these errors?

Location Manager Delegate

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    if (_userLocation.longitude != manager.location.coordinate.longitude
        && _userLocation.latitude != manager.location.coordinate.latitude) {
        _userLocation = manager.location.coordinate;
    }

    if (_isRecording) {
        if (!_route) {
            NSLog(@"lat: %f, lng: %f", _userLocation.latitude, _userLocation.longitude);
            _route = [[CrumbPath alloc] initWithCenterCoordinate:_userLocation];
            [_mapView addOverlay:_route];

            MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(_userLocation, 2000, 2000);
            [_mapView setRegion:region animated:YES];
        }else {
            MKMapRect updateRect = [_route addCoordinate:_userLocation];

            if (!MKMapRectIsNull(updateRect)) {
                MKZoomScale currentZoomScale = (CGFloat)(_mapView.bounds.size.width / _mapView.visibleMapRect.size.width);
                CGFloat lineWidth = MKRoadWidthAtZoomScale(currentZoomScale);
                updateRect = MKMapRectInset(updateRect, -lineWidth, -lineWidth);
                [_routeView setNeedsDisplayInMapRect:updateRect];
            }
        }
        [_routePoints addObject:_userLocation];

        [_route lockForReading];
        NSLog(@"%d", _route.pointCount);
        NSLog(@"%@", _route.points);
        [_route unlockForReading];
    }
}

Stop Recording Logic

    //stop recording
    NSLog(@"STOP");
    if (_route) {
        NSLog(@"There is a route");
        //Show route options toolbar
        [_route lockForReading];

        NSLog(@"%@", _route);
        NSLog(@"%d", _route.pointCount);
        NSLog(@"%@", _route.points);

        PFObject *routeToSave = [PFObject objectWithClassName:@"Routes"];
        //[routeToSave setObject:_route forKey:@"routePoints"];

        [_route unlockForReading];

        [routeToSave saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
            if (!error) {
                NSLog(@"%c", succeeded);
            }else {
                NSLog(@"%@", error);
            }
        }];
    }
Domash answered 14/1, 2013 at 22:44 Comment(6)
NSLog(@"%@", _route.pointCount); is this an integer? Then you should use %dGamete
well, yeah. sorry, I typed this up real quick. It still doesn't work.Domash
Is it crashing even after that? and how are you calling the method with CLLocationCoordinate2D objects? Can you post that code?Gamete
MKMapPoint is a C struct, not an Objective-C class.Sabella
correction, the pointCount worked. adding code to OP nowDomash
@HighFlyingFantasy, Good to know that. Please check my answer for the second issue.Gamete
G
10

Regarding your first issue, the crash was because of this:

NSLog(@"%@", _route.pointCount);

It should be:

NSLog(@"%d", _route.pointCount);

As mentioned in my comments, %d should be used for count and %@ will cause a crash.

Regarding your second issue, you cannot add a c struct to an NSArray. You should wrap it in NSValue before adding it to an array. CLLocationCoordinate2D is a c-struct. Check the documentation here.

Change this:

[_routePoints addObject:_userLocation];

to:

NSValue *aValue = [NSValue valueWithMKCoordinate:_userLocation];
[_routePoints addObject:aValue];

To get the coordinate back from NSValue, you can use,

[aValue MKCoordinateValue];

As mentioned in your error message, you were trying to add CLLocationCoordinate2D to an array which expects an object.

Gamete answered 14/1, 2013 at 23:0 Comment(8)
The crash was not caused by the initial NSLog(@"%@", _route.pointCount); because the NSLog(@"%@", _route.points); line was before it, I reordered it after realizing that it was never getting to the _route.pointCount line. But I was ignorant enough to use %@ before you corrected me. And my initWithCenterCoordinate: method says exactly that.Domash
It would have crashed if you used it as shown in question. For second issue, are you sure you are using (CLLocationCoordinate2D) and not (CLLocationCoordinate2D *)?Gamete
Yes, I haven't deviated from the Apple sample code. I took the actual files and dropped them in my project, only adding NSLog() statements.Domash
@HighFlyingFantasy, Got the issue. Updated the answer with the solution for that.Gamete
Much nicer than creating a useless wrapper class. Thank you.Domash
Yup. NSValue itself is a wrapper class and you dont need a new one just for this. Thanks for accepting. Glad to help.Gamete
[NSValue valueWithMKCoordinate:..] is available from iOS 6 and upEdgebone
You also need to #import <MapKit/MapKit.h> do be able to do this.Legion
N
1

Whatever api you're using to talk to parse is expecting an id which is a pointer to any object. A cllocationcoordinate2d is a c-struct of two doubles and not an object if I'm not mistaken. You should probably create a little wrapper object to save those two doubles and convert them to/from CLLocationCoordinate2d items.

Nonmoral answered 14/1, 2013 at 22:52 Comment(1)
Yes. The wrapper should probably be PFGeoPoint.Deathblow
C
0

1:

Line: NSLog(@"%@", _route.points); is wrong

_route.points is not a String, and you are using the NSStrig formating symbol "%@".

Further:

Since CLLocationCoordinate2D is a C-Sruct and not an Objective-C Object, you probaly want to create an own GeoPoint class.

Calliope answered 14/1, 2013 at 22:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.