Domanda

I am writing an iOS application to record your travel path and then storing it so that it can be retrieved later. Most of the code for drawing the path is based on the sample code Breadcrumb.

Now I am adding features to save the drawn overlay. What is best way to do it? I can use CoreData but I am not looking to do much to the drawn overlay rather than retrieving it later again. I have currently tried a simple NSArray. I convert the CrumbPath object into NSData and store it in the array. Later I retrieve it and convert it back to CrumbPath. However, I seem to be doing something wrong.

@interface CrumbPath : NSObject <MKOverlay>
{
    MKMapPoint *points;
    NSUInteger pointCount;
    NSUInteger pointSpace;

    MKMapRect boundingMapRect;

    pthread_rwlock_t rwLock;
}

- (id)initWithCenterCoordinate:(CLLocationCoordinate2D)coord;
- (MKMapRect)addCoordinate:(CLLocationCoordinate2D)coord;

@property (readonly) MKMapPoint *points;
@property (readonly) NSUInteger pointCount;

@end

I save a CrumbPath object "crumbs" like this:

NSData *pointData = [NSData dataWithBytes:crumbs.points length:crumbs.pointCount * sizeof(MKMapPoint)];
[patternArray addObject:pointData];
[timeArray addObject:date];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// Create the full file path by appending the desired file name
NSString *patternFile = [documentsDirectory stringByAppendingPathComponent:@"patterns.dat"];
NSString *timeFile = [documentsDirectory stringByAppendingPathComponent:@"times.dat"];

//Save the array
[patternArray writeToFile:patternFile atomically:YES];
[timeArray writeToFile:timeFile atomically:YES];

And retrieve it later like this to show in a table:

NSData *pointData = [appDelegate.patternArray objectAtIndex:indexPath.row];
MKMapPoint *points = malloc(pointData.length);
(void)memcpy([pointData bytes], points, sizeof(pointData));

And construct the path again:

crumbs = [[CrumbPath alloc] initWithCenterCoordinate:MKCoordinateForMapPoint(points[0])];
for (int i = 1; i <= pointCount; i++) {
    [crumbs addCoordinate:MKCoordinateForMapPoint(points[i])];
}    
[map addOverlay:crumbs];

However, I get an error: 'NSInvalidArgumentException', reason: '-[NSConcreteData isEqualToString:]: unrecognized selector sent to instance

È stato utile?

Soluzione

Personally, I'd be inclined to do it as follows:

  1. First, I'd be inclined to save the C array of CLLocationCoordinate2D coordinates that I pass to MKPolygon instance method polygonWithCoordinates (rather than a MKMapPoint C array). You can adapt this code if you'd rather use MKMapPoints, but I prefer a format which I can examine externally and make sense of (namely the latitude and longitude values of CLLocationCoordinate2D). So, let's assume that you make your MKPolygon with a line of code like so:

    MKPolygon* poly = [MKPolygon polygonWithCoordinates:coordinates count:count];
    

    You could, therefore save the coordinates like so:

    [self writeCoordinates:coordinates count:count file:filename];
    

    Where writeCoordinates:count:filename: is defined as follows:

    - (void)writeCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count file:(NSString *)filename
    {
        NSData *data = [NSData dataWithBytes:coordinates length:count * sizeof(CLLocationCoordinate2D)];
        [data writeToFile:filename atomically:NO];
    }
    

    You could then make the MKPolygon from the file with:

    MKPolygon* poly = [self polygonWithContentsOfFile:filename];
    

    where polygonWithContentsOfFile is defined as:

    - (MKPolygon *)polygonWithContentsOfFile:(NSString *)filename
    {
        NSData *data = [NSData dataWithContentsOfFile:filename];
        NSUInteger count = data.length / sizeof(CLLocationCoordinate2D);
        CLLocationCoordinate2D *coordinates = (CLLocationCoordinate2D *)data.bytes;
    
        return [MKPolygon polygonWithCoordinates:coordinates count:count];
    }
    
  2. Alternatively, you could read and write the array of CLLocationCoordinate2D in a plist format (which renders it in a human readable format), by replacing the two above methods with:

    const NSString *kLatitudeKey = @"latitude";
    const NSString *kLongitudeKey = @"longitude";
    
    - (void)writeCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count file:(NSString *)filename
    {
        NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
    
        for (NSUInteger i = 0; i < count; i++)
        {
            CLLocationCoordinate2D coordinate = coordinates[i];
            [array addObject:@{kLatitudeKey:@(coordinate.latitude), kLongitudeKey:@(coordinate.longitude)}];
        }
    
        [array writeToFile:filename atomically:NO];
    }
    
    - (MKPolygon *)polygonWithContentsOfFile:(NSString *)filename
    {        
        NSArray *array = [NSArray arrayWithContentsOfFile:filename];
        NSUInteger count = [array count];
        CLLocationCoordinate2D coordinates[count];
    
        for (NSUInteger i = 0; i < count; i++)
        {
            NSDictionary *dictionary = array[i];
            coordinates[i].latitude = [dictionary[kLatitudeKey] doubleValue];
            coordinates[i].longitude = [dictionary[kLongitudeKey] doubleValue];
        }
    
        return [MKPolygon polygonWithCoordinates:coordinates count:count];
    }
    

Clearly you'd want to add error checking code to make sure that the writeToFile and the dataWithContentsOfFile (or arrayWithContentsOfFile) succeeded, but hopefully this gives you the idea.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top