简体   繁体   English

使用NSCoder保存自定义MKOverlay

[英]Using NSCoder to save custom MKOverlay

I have a custom NSObject class Trails that I want to save to a plist. 我有一个要保存到plist的自定义NSObject类Trail。 I have it correctly saving and loading now, with the exception of one part. 我已经正确地保存和加载了,除了一部分。 I have a custom MKOverlay class object Crumbs in that class that I want to save as well. 我也想保存该类中的自定义MKOverlay类对象Crumbs。 No error is thrown since crumbs conforms to NSCoding however the overlay does not display on the map after saving and reopening the app. 由于面包屑符合NSCoding,因此不会引发任何错误,但是在保存并重新打开应用程序后,叠加层不会显示在地图上。 The crumb object is not nil, but still does not display. 面包屑对象不是nil,但仍然不显示。

Trails.h Trails.h

@interface Trails : NSObject <NSCoding>
{
    @public
    int topSpeed;
    float avgSpeed;
}
@property (nonatomic, strong) NSString *miles;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) NSString *time;
@property (nonatomic, strong) CrumbPath *crumbs;
- (NSString *)displayDate;
- (NSString *)displayStartTime;
- (void)addTopSpeed: (int)top withAvgSpeed:(float)avg;
@end

Trails.m Trails.m

- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:miles forKey:@"miles"];
    [coder encodeObject:date forKey:@"date"];
    [coder encodeObject:time forKey:@"time"];
    [coder encodeObject:crumbs forKey:@"crumbs"];
    [coder encodeFloat:avgSpeed forKey:@"avgSpeed"];
    [coder encodeInt:topSpeed forKey:@"topSpeed"];

}


- (id)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if( self != nil )
    {
        miles = [coder decodeObjectForKey:@"miles"];
        date = [coder decodeObjectForKey:@"date"];
        time = [coder decodeObjectForKey:@"time"];
        crumbs = [coder decodeObjectForKey:@"crumbs"];
        avgSpeed = [coder decodeFloatForKey:@"avgSpeed"];
        topSpeed = [coder decodeIntForKey:@"topSpeed"];
    }
    return self;
}

Crumbs.h Crumbs.h

@interface CrumbPath : NSObject <MKOverlay, NSCoding>

Crumbs.m Crumbs.m

#import "CrumbPath.h"

#define INITIAL_POINT_SPACE 1000
#define MINIMUM_DELTA_METERS 10.0

@implementation CrumbPath

@synthesize points, pointCount;

- (id)initWithCenterCoordinate:(CLLocationCoordinate2D)coord
{
    self = [super init];
    if (self)
    {
        // initialize point storage and place this first coordinate in it
        pointSpace = INITIAL_POINT_SPACE;
        points = malloc(sizeof(MKMapPoint) * pointSpace);
        points[0] = MKMapPointForCoordinate(coord);
        pointCount = 1;

        // bite off up to 1/4 of the world to draw into.
        MKMapPoint origin = points[0];
        origin.x -= MKMapSizeWorld.width / 8.0;
        origin.y -= MKMapSizeWorld.height / 8.0;
        MKMapSize size = MKMapSizeWorld;
        size.width /= 4.0;
        size.height /= 4.0;
        boundingMapRect = (MKMapRect) { origin, size };
        MKMapRect worldRect = MKMapRectMake(0, 0, MKMapSizeWorld.width, MKMapSizeWorld.height);
        boundingMapRect = MKMapRectIntersection(boundingMapRect, worldRect);

        // initialize read-write lock for drawing and updates
        pthread_rwlock_init(&rwLock, NULL);
    }
    return self;
}

- (void)dealloc
{
    free(points);
    pthread_rwlock_destroy(&rwLock);
}

- (CLLocationCoordinate2D)coordinate
{
    return MKCoordinateForMapPoint(points[0]);
}

- (MKMapRect)boundingMapRect
{
    return boundingMapRect;
}

- (void)lockForReading
{
    pthread_rwlock_rdlock(&rwLock);
}

- (void)unlockForReading
{
    pthread_rwlock_unlock(&rwLock);
}

- (MKMapRect)addCoordinate:(CLLocationCoordinate2D)coord
{
    // Acquire the write lock because we are going to be changing the list of points
    pthread_rwlock_wrlock(&rwLock);

    // Convert a CLLocationCoordinate2D to an MKMapPoint
    MKMapPoint newPoint = MKMapPointForCoordinate(coord);
    MKMapPoint prevPoint = points[pointCount - 1];

    // Get the distance between this new point and the previous point.
    CLLocationDistance metersApart = MKMetersBetweenMapPoints(newPoint, prevPoint);
    MKMapRect updateRect = MKMapRectNull;

    if (metersApart > MINIMUM_DELTA_METERS)
    {
        // Grow the points array if necessary
        if (pointSpace == pointCount)
        {
            pointSpace *= 2;
            points = realloc(points, sizeof(MKMapPoint) * pointSpace);
        }    

        // Add the new point to the points array
        points[pointCount] = newPoint;
        pointCount++;

        // Compute MKMapRect bounding prevPoint and newPoint
        double minX = MIN(newPoint.x, prevPoint.x);
        double minY = MIN(newPoint.y, prevPoint.y);
        double maxX = MAX(newPoint.x, prevPoint.x);
        double maxY = MAX(newPoint.y, prevPoint.y);

        updateRect = MKMapRectMake(minX, minY, maxX - minX, maxY - minY);
    }

    pthread_rwlock_unlock(&rwLock);

    return updateRect;
}

//Conform to NSCoding
- (void)encodeWithCoder:(NSCoder *)coder {
    //I think I need to do something here?
}


- (id)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if( self != nil )
    {
        //I think I need to do something here?
    }
    return self;
}

@end

Your implementations of encodeWithCoder and initWithCoder for the CrumbPath class are empty. CrumbPath类的encodeWithCoderinitWithCoderCrumbPath为空。 You need to save all properties/ivars, same as you did for the Trails object. 您需要保存所有属性/值,与对Trails对象所做的一样。 All objects are responsible for saving their own properties/ivars with regards to NSCoding. 所有对象都有责任保存关于NSCoding的自身属性/值。

Just to add - you can't directly write CLLocationCoordinate2D and CGRect to disk. 仅添加-您不能直接将CLLocationCoordinate2D和CGRect写入磁盘。 You'll have to break them up and reconstitute them. 您必须将它们分解并重构它们。 For example, with CGRect, you would have to encode as follows: 例如,对于CGRect,您将必须进行以下编码:

 [aCoder encodeFloat:rect.origin.x forKey:@"x"];
 [aCoder encodeFloat:rect.origin.y forKey:@"y"];
 [aCoder encodeFloat:rect.size.width forKey:@"width"];
 [aCoder encodeFloat:rect.size.height forKey:@"height"];

and then when decoding/init'ing, you have to reconstitute it: 然后在解码/初始化时,必须重新构造它:

 CGFloat x = [aDecoder decodeFloatForKey:@"x"];
 CGFloat y = [aDecoder decodeFloatForKey:@"y"];
 CGFloat width = [aDecoder decodeFloatForKey:@"width"];
 CGFloat height = [aDecoder decodeFloatForKey:@"height"];

 self.rect = CGRectMake(x,y,width,height);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM