core-data - 你如何将 NSMutableArray 中的数据存储在 Core Data 中?

标签 core-data nsmutablearray store polyline persist

我正在制作的应用程序绘制了一个 Polyline基于来自 CLLocationManager 的用户坐标(这些都保存在 NSMutableArray 中)

当应用程序关闭时,当前折线消失。如何在应用程序启动时将要检索的点数组存储在 CoreData 中?用户自启动应用程序以来所采取的所有过去“路线”都应该被恢复并覆盖在 map 上(这可能很多,所以从我收集的信息来看,CoreData 似乎是最好的选择)。

这是我用来从加载的坐标创建 MKPolyline 的代码

-(IBAction)didClickLoadCoordinates:(id)sender {
// get a reference to the appDelegate so you can access the global managedObjectContext
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Route"];
NSError *error;
id results = [appDelegate.managedObjectContext executeFetchRequest:request error:&error];

if ([results count]) {
    polyLine = (Route *)(results[0]);
    NSArray *coordinates = polyLine.coordinates;
    int ct = 0;
    for (CLLocation *loc in coordinates) {
        NSLog(@"location %d: %@", ct++, loc);


    }


    // this copies the array to your mutableArray
    _locationsArray = [coordinates mutableCopy];

}

NSInteger numberOfSteps = _locationsArray.count;

//convert to coordinates array to construct the polyline

CLLocationCoordinate2D clCoordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
    CLLocation *location = [_locationsArray objectAtIndex:index];
    CLLocationCoordinate2D coordinate2 = location.coordinate;
    clCoordinates[index] = coordinate2;
}

MKPolyline *routeLine = [MKPolyline polylineWithCoordinates:clCoordinates count:numberOfSteps];
[_mapView addOverlay:routeLine];

最佳答案

我创建了一个简单的类,它在应用程序关闭时用数组保存多段线,并在应用程序返回时查询所有多段线的核心数据。我假设您知道如何设置核心数据和托管对象上下文。这种模式允许您直接将 NSArray 对象设置和获取到核心数据对象中。其背后的基本原理在这里:https://coderwall.com/p/mx_wmq

首先,创建具有可转换属性(您的数组)和与之配套的数据属性的模型。

model

接下来,在折线对象上创建一个类别。

category

您现在应该在文件浏览器中拥有这些项目

files

折线+TransformableAttributes.h

#import "Polyline.h"

@interface Polyline (TransformableAttributes)

#pragma mark transformables

-(NSArray *)coordinates;
-(void)setCoordinates:(id)coordinates;

@end

折线+TransformableAttributes.m
@implementation Polyline (TransformableAttributes)

#pragma mark Transformables
-(NSArray *)coordinates {
    if (!self.coordinates_data)
        return nil;

    return [NSKeyedUnarchiver unarchiveObjectWithData:self.coordinates_data];
}

-(void)setCoordinates:(id)coordinates {
    NSData *coordinates_data = [NSKeyedArchiver archivedDataWithRootObject:coordinates];
    [self setValue:coordinates_data forKey:@"coordinates_data"];
}

@end

Appdelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Polyline"];
    NSError *error;
    id results = [self.managedObjectContext executeFetchRequest:request error:&error];
    Polyline *polyline = (Polyline *)(results[0]);
    NSArray *coordinates = polyline.coordinates;

}

- (void)applicationWillResignActive:(UIApplication *)application
{
    NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@"Polyline" inManagedObjectContext:self.managedObjectContext];
    Polyline *polyline = (Polyline *)object;
    [polyline setCoordinates:@[@"a", @"b", @"c"]];
    NSError *error;
    if ([self.managedObjectContext save:&error]) {
        NSLog(@"Saved");
    }
    else {
        NSLog(@"Error: %@", error);
    }
}

请让我知道它是否适合您。如果需要,我会更新我的答案,以便它有用。我不记得我最初在哪里找到这个模式,但它真的很有帮助并且得到了高度赞扬

编辑 1:添加了 GPS View

这是我添加的一个新 Controller :

enter image description here

GPSViewController.h:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "Polyline+TransformableAttributes.h"

@interface GPSViewController : UIViewController <CLLocationManagerDelegate>
{
    NSMutableArray *_locationsArray;
    Polyline *polyLine;
    CLLocationManager *locationManager;
}

-(IBAction)didClickStartGPS:(id)sender;
-(IBAction)didClickSaveCoordinates:(id)sender;
-(IBAction)didClickLoadCoordinates:(id)sender;

我的 GPSViewController.m 中的代码:

初始化数组以存储我的坐标。
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    _locationsArray = [NSMutableArray array];
}

当您单击 GPS 按钮时,它会转到此处。 locationManager 是类的实例变量。
-(IBAction)didClickStartGPS:(id)sender {
    locationManager = [[CLLocationManager alloc] init];
    [locationManager setDelegate:self];
    [locationManager startUpdatingLocation];
}

这会将坐标保存到折线中并保留它。注意:对于这段代码,我没有做任何特定的搜索描述符,所以如果你多次点击保存,你会在核心数据中得到一堆折线,而且每次可能只会加载第一个。如果将某个 ID 或日期添加到折线对象中,则可以执行诸如在它们中搜索特定 ID 或日期之类的操作。
-(IBAction)didClickSaveCoordinates:(id)sender {
    /*
     NSInteger numberOfSteps = _locationsArray.count;
     // you don't need to convert it to a coordinates array.
     CLLocationCoordinate2D coordinates[numberOfSteps];
     for (NSInteger index = 0; index < numberOfSteps; index++) {
     CLLocation *location = [_locationsArray objectAtIndex:index];
     CLLocationCoordinate2D coordinate2 = location.coordinate;
     coordinates[index] = coordinate2;
     }
     */

    // get a reference to the appDelegate so you can access the global managedObjectContext
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;

    // creates a new polyline object when app goes into the background, and stores it into core data.
    if (!polyLine) {
        NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@"Polyline" inManagedObjectContext:appDelegate.managedObjectContext];
        polyLine = (Polyline *)object;
    }

    [polyLine setCoordinates:_locationsArray];
    NSError *error;
    if ([appDelegate.managedObjectContext save:&error]) {
        NSLog(@"Saved");
    }
    else {
        NSLog(@"Error: %@", error);
    }
}

这将从核心数据加载第一个折线对象并将其转换为 CLLocations 的 _locationArray。我不会对您可以从他们那里获得的 CLLocationCoordinate2D 做任何事情。
-(IBAction)didClickLoadCoordinates:(id)sender {
    // get a reference to the appDelegate so you can access the global managedObjectContext
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;

    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Polyline"];
    NSError *error;
    id results = [appDelegate.managedObjectContext executeFetchRequest:request error:&error];

    if ([results count]) {
        polyLine = (Polyline *)(results[0]);
        NSArray *coordinates = polyLine.coordinates;
        int ct = 0;
        for (CLLocation *loc in coordinates) {
            NSLog(@"location %d: %@", ct++, loc);
        }

        // this copies the array to your mutableArray
        _locationsArray = [coordinates mutableCopy];
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    CLLocation *currentLocation = [locations lastObject];
    CLLocationDegrees latitude = currentLocation.coordinate.latitude;
    CLLocationDegrees longitude = currentLocation.coordinate.longitude;
    CLLocationCoordinate2D locationCoordinates = CLLocationCoordinate2DMake(latitude, longitude);

    //store latest location in stored track array;
    [_locationsArray addObject:currentLocation];
}

此代码在我的 github 上更新:

github.com/bobbyren/StackOverflowTest.git

编辑:为每条折线添加一个新的 MKPolyline:
NSArray *polylines = [fetchedResultsController allObjects];
for (Polyline *polyline in polylines) {
    MKPolyline *mkPolyline = [MKPolyline polylineWithCoordinates:polyline.coordinates count:ct]; // assuming you have written out how to return polyline.coordinates as a CLLocationCoordinate2D[]
    [mapView addOverlay:line];
}

[mapView reloadData];

关于core-data - 你如何将 NSMutableArray 中的数据存储在 Core Data 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25416132/

相关文章:

objective-c - 如何按字母顺序对 NSMutableArray 中的自定义对象字段进行排序?

javascript - 创建 extjs 存储数据记录失败

android - 访问 Android 首选项键的最佳方式

iphone - CoreData 对多对多关系排序

ios - 使用嵌套上下文时如何自动设置核心数据关系

ios - 漂亮的核心数据对象id

xcode - 访问我的自定义对象中的 NSMutableArray

ios - 同时将数据写入和读取到NSMutableArray

javascript - Vuex:功能范围模块中的未知 setter/getter

iphone - 加载到CoreData