归档和取消归档数据/模型对象

时间:2014-01-17 10:06:00

标签: objective-c cocoa-touch cocoa

我正在遵循MVCS范例,用于保存,然后在与更新映射数据相关的测试应用中加载数据对象的实例。

BNRMapPoint.h

 #import <Foundation/Foundation.h>
 #import <MapKit/MapKit.h>
 #import <CoreLocation/CoreLocation.h>
 @interface BNRMapPoint : NSObject<MKAnnotation, NSCoding>
 {
     double latitude;
     double longitude;
     @public NSArray *mapPoints;
 }
-(id) initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subTitle:(NSString *)st;

 //this is required property in MKAnnotation Protocol
 @property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

 //this is an optional property in MKAnnotation Protocol
 @property (nonatomic, copy) NSString *title;
 //this is an optional property in MKAnnotation Protocol
 @property (nonatomic,readonly,copy) NSString *subTitle;
 @end

BNRMapPoint.m(型号)

#import "BNRMapPoint.h"

@implementation BNRMapPoint
@synthesize coordinate=_coordinate;
@synthesize title=_title;
@synthesize subtitle=_subtitle;

-(void)encodeWithCoder:(NSCoder *)aCoder{
  latitude  = self.coordinate.latitude;
  longitude = self.coordinate.longitude;

  [aCoder encodeObject:self.title forKey:@"title"];
  [aCoder encodeObject:_subTitle forKey:@"subTitle"];
  [aCoder encodeDouble: latitude forKey:@"latitude"];
  [aCoder encodeDouble:longitude forKey:@"longitude"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
   if (self= [super init]) {
      [self setTitle:[aDecoder decodeObjectForKey:@"title"]];
       self->_subTitle= [aDecoder decodeObjectForKey:@"subTitle"];
       latitude= [aDecoder decodeDoubleForKey:@"latitude"];
       longitude= [aDecoder decodeDoubleForKey:@"longitude"];
   }
   return self;
}

-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subTitle:(NSString *)st{
  if (self= [super init]) {
    self.coordinate=c;
    self.title=t;
    _subtitle=st;
   }
   return self;
}
  -(id) init{
    return  [self initWithCoordinate:CLLocationCoordinate2DMake(43.07, -89.32) title:@"Hometown"   subTitle:self.subtitle];
}

@end

WhereamiViewController.h

   #import <UIKit/UIKit.h>
   #import <CoreLocation/CoreLocation.h>
   #import <MapKit/MapKit.h>
   #import "BNRMapPoint.h"
   #import "RootObject.h"
  @interface WhereamiViewController :      UIViewController<CLLocationManagerDelegate,MKMapViewDelegate,UITextFieldDelegate>
   {
        @public RootObject *rootObj;
        CLLocationManager *locationManager;

        IBOutlet MKMapView *worldView;
        IBOutlet UIActivityIndicatorView *activityIndicator;
        IBOutlet UITextField *locationTitleField;
   }
   -(IBAction)buttonDidGetPressed:(id)sender;
   -(BOOL)textFieldShouldReturn:(UITextField *)textField;
    -(void)findLocation;
    -(void)foundLocation:(CLLocation *)loc;

   @end

WhereamiViewController.m(ViewController)

    #import "WhereamiViewController.h"

    @interface WhereamiViewController ()

    @end

    @implementation WhereamiViewController

    -(IBAction)buttonDidGetPressed:(UISegmentedControl *)sender{//Silver challenge
      NSLog(@"%@",NSStringFromSelector(_cmd));
        if([sender selectedSegmentIndex]==0){
           [worldView setMapType:MKMapTypeStandard];
        }
        else if([sender selectedSegmentIndex]==1){
           [worldView setMapType:MKMapTypeHybrid];
        }
        else if([sender selectedSegmentIndex]==2){
            [worldView setMapType:MKMapTypeSatellite];
        }
     }
      -(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
           NSLog(@"%@", NSStringFromSelector(_cmd));
         if (self=[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
             rootObj= [[RootObject alloc] init];
            locationManager= [[CLLocationManager alloc] init];

            [locationManager setDelegate:self];//self is Whereamicontroller. The delegate pointer is of type id<CLLocationManagerDelegate> and is an ivar of CLLocationManager.
            [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];      
          }
          NSLog(@"test");
         return self;
      }

      -(void) viewDidLoad{
          //    [worldView setMapType:MKMapTypeSatellite]; Bronze challenge
           [worldView setShowsUserLocation:YES];
       }
       -(void)findLocation{
           NSLog(@"%@",NSStringFromSelector(_cmd));
          [locationManager startUpdatingLocation];//This calls locationManager:didUpdateLocations:
           NSLog(@"location updated");
            [activityIndicator startAnimating];
            [locationTitleField setHidden:YES];
       }
       -(BOOL)textFieldShouldReturn:(UITextField *)textField{
           NSLog(@"%@",NSStringFromSelector(_cmd));
           [self findLocation];
           [textField resignFirstResponder];
           return YES;
       }

       -(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
           NSLog(@"%@",NSStringFromSelector(_cmd));
            CLLocationCoordinate2D centerCoordinate= [[userLocation location] coordinate]; //get the coordinate of current location.
             MKCoordinateSpan span= MKCoordinateSpanMake(250, 250);//Structure members
             MKCoordinateRegion mapPortionToDisplay= MKCoordinateRegionMakeWithDistance(centerCoordinate, span.latitudeDelta, span.longitudeDelta);//span.latitudeDelta=250 and span.longitudeDelta=250
             [worldView setRegion:mapPortionToDisplay animated:YES];
            //    [worldView setRegion:mapPortionToDisplay];
       }

       -(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{
          NSLog(@"%@",NSStringFromSelector(_cmd));
          NSLog(@"Heading %@",newHeading);
       }
       -(void)foundLocation:(CLLocation *)loc{
            NSLog(@"%@",NSStringFromSelector(_cmd));
            CLLocationCoordinate2D coord= [loc coordinate];

            NSDateFormatter *formatter= [[NSDateFormatter alloc] init];

            NSDate *currentDate= [[NSDate alloc] init];
            [formatter setDefaultDate:currentDate];

             BNRMapPoint *bmp= [[BNRMapPoint alloc] initWithCoordinate:coord title:[locationTitleField text] subTitle:[[formatter defaultDate] description]];
            [rootObj.mapPoints addObject:bmp];

             [worldView addAnnotation:bmp];

             MKCoordinateRegion region= MKCoordinateRegionMakeWithDistance(coord,250,250);
             [worldView setRegion:region animated:YES];

              //RESET the UI
             [locationTitleField setText:@" "];
             [activityIndicator stopAnimating];
             [locationTitleField setHidden:NO];
              [locationManager stopUpdatingLocation];
        }
         -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ //CLLocationManagerDelegate method implementation

           NSLog(@"%@", NSStringFromSelector(_cmd));
        //    NSTimeInterval t0=[[locations lastObject] timeIntervalSinceNow];

          NSLog(@"%@",(CLLocation *)[locations lastObject]);
          NSTimeInterval t= [[(CLLocation *)[locations lastObject] timestamp] timeIntervalSinceNow];

           if (t<-180) {
             return; //No op
           }

           [self foundLocation:[locations lastObject]];

        }

        -(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
             NSLog(@"Could not find location: %@",error);//CLLocationManagerDelegate method implementation
        }


         @end

RootObject.h

       #import <Foundation/Foundation.h>

       @interface RootObject : NSObject
       @property NSMutableArray *mapPoints;
       -(BOOL)saveChanges;
       -(NSString *)dataObjectArchivePath;
       @end

RootObject.m(存储)

      #import "RootObject.h"

       @implementation RootObject
        @synthesize mapPoints;

     -(NSString *)dataObjectArchivePath{
         NSArray *documentDirectories= NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
         NSString *documentDirectory= [documentDirectories objectAtIndex:0];

          NSString *finalPath= [documentDirectory stringByAppendingPathComponent:@"items.archive"];
         return finalPath;
      }
      -(BOOL)saveChanges{
          NSString *path= [self dataObjectArchivePath];
          return [NSKeyedArchiver archiveRootObject:self.mapPoints toFile:path];writing to the file items.archive
      }
      -(id)init{
          if (self=[super init]) {
             NSString *path= [self dataObjectArchivePath];
             self.mapPoints= [NSKeyedUnarchiver unarchiveObjectWithFile:path];//reading from the file items.archive

          if (!self.mapPoints) {
              self.mapPoints= [[NSMutableArray alloc] init];
        }
      }
      return self;
     }
     @end

AppDelegate.m

     - (void)applicationDidEnterBackground:(UIApplication *)application
      {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
         // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        NSLog(@"%@",NSStringFromSelector(_cmd));
         BOOL success= [[BNRItemStore sharedStore] saveChanges];
        if (success) {
           NSLog(@"Saved all of the BNRItems");
        }
        else{
         NSLog(@"Could not save any of the BNRItems");
        }
     }

在上面的代码中,从application:didEnterBackground:调用saveChanges方法。所以我没有为Store(RootObject)创建一个单例对象。但我在viewController的指定初始化程序中实例化它。要归档的数据是BNRMapPoint对象。在进入后台状态时,代码确实成功保存了对象。然而,在重新启动应用程序之后,initWithCoder就会陷入困境。在阅读以前保存的MapPoint对象时,应用程序崩溃了。请帮助..我几乎可以检查。不知道该怎么办。我被卡住了。

1 个答案:

答案 0 :(得分:0)

所以问题是你有:

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; 

你正试图在只读属性上使用setter:

self.coordinate=c;

这就是为什么它说无法识别的选择器是发送的 - 因为它是只读的,所以setter不存在。使用属性这与调用:

相同
[self setCoordinate:c]

只需输入属性