2013-04-08 81 views
1

我有一個自定義的NSObject類我想保存到plist的Trails。我現在正確保存和加載,除了一部分。我有一個自定義的MKOverlay類對象麪包屑,我想保存在該類中。由於麪包屑符合NSCoding,所以不會拋出任何錯誤,但保存並重新打開應用程序後,覆蓋圖不會顯示在地圖上。麪包屑對象不是零,但仍然不顯示。使用NSCoder保存自定義MKOverlay

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

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

@interface CrumbPath : NSObject <MKOverlay, NSCoding> 

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 
+0

,你就沒有任何數據/你的CrumbPath類的屬性?沒有看到任何正在保存的內容。我認爲符合MKOverlay協議的對象需要一個「座標」和一個「boundingMapRect」屬性? – 2013-04-08 20:53:50

+0

是的,我沒有包括每個文件的完整代碼,我已經更新了代碼以顯示完整的CrumbPath.m – Glen 2013-04-08 21:05:00

回答

2

類的encodeWithCoderinitWithCoder的實現是空的。您需要保存所有屬性/ ivars,與您爲Trails對象所做的一樣。所有對象都負責保存與NSCoding相關的屬性/ ivars。

只需添加 - 您不能直接將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"]; 

,然後解碼/ init'ing時,你必須重新構建它:

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); 
+0

非常感謝您的明確答案完美的工作! :) – Glen 2013-04-09 02:45:30

+0

很高興我可以幫助 - 請不要忘記接受答案。 – 2013-04-09 02:54:33

相關問題