Использование NSCoder для сохранения пользовательского MKOverlay

У меня есть собственный класс Trails NSObject, который я хочу сохранить в plist. У меня сейчас правильно сохраняется и загружается, за исключением одной части. У меня есть пользовательский объект класса MKOverlay Crumbs в этом классе, который я также хочу сохранить. Никакой ошибки не возникает, поскольку крошки соответствуют NSCoding, однако наложение не отображается на карте после сохранения и повторного открытия приложения. Объект крошки не равен нулю, но все равно не отображается.

Тропы.ч

@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

Трассы.м

- (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;
}

Крошки.ч

@interface CrumbPath : NSObject <MKOverlay, NSCoding>

Крошки.м

#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

person Glen    schedule 08.04.2013    source источник
comment
У вас нет данных/свойств в вашем классе CrumbPath? Не вижу ничего сохраняемого. Я думал, что объекты, соответствующие протоколу MKOverlay, нуждаются в свойствах coordinate и boundingMapRect?   -  person Jai Govindani    schedule 09.04.2013
comment
Да, я не включил полный код каждого файла, я обновил код, чтобы показать полный CrumbPath.m   -  person Glen    schedule 09.04.2013


Ответы (1)


Ваши реализации encodeWithCoder и initWithCoder для класса CrumbPath пусты. Вам нужно сохранить все свойства/параметры, так же, как вы сделали для объекта Trails. Все объекты несут ответственность за сохранение своих собственных свойств/параметров в отношении NSCoding.

Просто добавлю - вы не можете напрямую записать CLLocationCoordinate2D и CGRect на диск. Вам придется разбить их и восстановить их. Например, с 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"];

а затем при декодировании/инициализации вы должны восстановить его:

 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);
person Jai Govindani    schedule 08.04.2013
comment
Большое спасибо за четкий ответ, теперь все работает идеально! :) - person Glen; 09.04.2013
comment
Рад, что смог помочь - пожалуйста, не забудьте принять ответ. - person Jai Govindani; 09.04.2013