如何在Core Data中存储来自NSMutable Array的数据? [英] How do you store data from NSMutable Array in Core Data?

查看:295
本文介绍了如何在Core Data中存储来自NSMutable Array的数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的应用程序根据 CLLocationManager 的用户坐标绘制折线 NSMutableArray



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



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

  (IBAction)didClickLoadCoordinates:(id)sender {
//获取对appDelegate的引用,以便您可以访问全局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;
intct = 0;
for(CLLocation * loc in coordinates){
NSLog(@location%d:%@,ct ++,loc);


}


//将数组复制到mutableArray
_locationsArray = [coordinates mutableCopy];

}

NSInteger numberOfSteps = _locationsArray.count;

//转换为坐标数组以构造折线

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



首先,使用transformable属性(数组)和一个data属性创建模型。



img src =https://i.imgur.com/DjiCVnw.jpgalt =model>



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







Polyline + TransformableAttributes.h

  #importPolyline.h 

@interface Polyline(TransformableAttributes)

#pragma mark transformables

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

@end

Polyline + TransformableAttributes.m

  @implementation Polyline(TransformableAttributes)

#pragma mark转换器
- (NSArray *)坐标{
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:@ManagedObjectContext :self.managedObjectContext];
Polyline * polyline =(Polyline *)object;
[polyline setCoordinates:@ [@a,@b,@c]];
NSError * error;
if([self.managedObjectContext save:& error]){
NSLog(@Saved);
}
else {
NSLog(@Error:%@,error);
}
}

请让我知道如果它适用于你。如果需要,我会更新我的答案,以便它可以是有用的。我不记得在哪里,我最初发现这个模式,但它是一个非常有帮助和高度upvoted



编辑1:添加了一个gps视图



这是我添加的一个新控制器:





GPSViewController.h:

  #import< UIKit / UIKit.h> 
#import< CoreLocation / CoreLocation.h>
#importPolyline + 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];
//在加载视图之后执行任何其他设置。

_locationsArray = [NSMutableArray array];
}

当您点击GPS按钮, locationManager是类的实例变量。

   - (IBAction)didClickStartGPS:(id)sender {
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager startUpdatingLocation];
}

这将坐标保存到折线并保留。注意:使用此代码,我不会做任何特定的搜索描述符,因此,如果您单击保存多次,您将在核心数据中获得一堆折线,并且可能每次只加载第一个。

   - (IBAction)如果您将某个ID或日期添加到折线对象中, )didClickSaveCoordinates:(id)sender {
/ *
NSInteger numberOfSteps = _locationsArray.count;
//你不需要将它转换为坐标数组。
CLLocationCoordinate2D coordinates [numberOfSteps];
for(NSInteger index = 0; index< numberOfSteps; index ++){
CLLocation * location = [_locationsArray objectAtIndex:index];
CLLocationCoordinate2D coordinate2 = location.coordinate;
coordinates [index] = coordinate2;
}
* /

//获取对appDelegate的引用,以便您可以访问全局managedObjectContext
AppDelegate * appDelegate = [UIApplication sharedApplication] .delegate;

//当应用程序进入后台时创建一个新的折线对象,并将其存储到核心数据中。
if(!polyLine){
NSManagedObject * object = [NSEntityDescription insertNewObjectForEntityForName:@PolylineinManagedObjectContext:appDelegate.managedObjectContext];
polyLine =(Polyline *)object;
}

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

这会从核心数据加载第一个折线对象,它进入你的_locationArray CLLocations。我不对你可以从他们获得的CLLocationCoordinate2D做任何事情。

   - (IBAction)didClickLoadCoordinates: 
//获取对appDelegate的引用,以便您可以访问全局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;
intct = 0;
for(CLLocation * loc in coordinates){
NSLog(@location%d:%@,ct ++,loc);
}

//将数组复制到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);

//存储存储磁道阵列中的最新位置;
[_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]; //假设你写了如何将polyline.coordinates返回为CLLocationCoordinate2D []
[mapView addOverlay:line];
}

[mapView reloadData];


The app i'm making draws a Polyline based on the users coordinates from CLLocationManager (these are all kept in an NSMutableArray)

When the app closes, the current polyline disappears. How can I store the array of points in CoreData to be retrieved when the app starts up? All of the past 'routes' that the user has taken since initiating the app should be recovered and overlaid on the map (which may be quite a lot, so CoreData seems the best option from what i've gathered).

This is the code I use to create an MKPolyline from the loaded coordinates

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

解决方案

I've created a simple class that saves a polyline with an array when the app closes, and queries core data for all polylines when the app returns. I assume you know how to set up core data and managed object contexts. This pattern allows you to directly set and get NSArray objects into the core data object. The basic principle behind it is here: https://coderwall.com/p/mx_wmq

First, create the model with a transformable attribute (your array) and a data attribute to go with it.

Next, create a category on the polyline object.

You should now have these items in your file browser

Polyline+TransformableAttributes.h

#import "Polyline.h"

@interface Polyline (TransformableAttributes)

#pragma mark transformables

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

@end

Polyline+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);
    }
}

Please let me know if it works for you. I'll update my answer if needed, so that it can be useful. I can't remember where I originally found this pattern but it was a really helpful and highly upvoted

Edit 1: Added a gps view

Here is a new controller I added:

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;

The code in my GPSViewController.m:

Initialize the array to store my coordinates.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    _locationsArray = [NSMutableArray array];
}

When you click the GPS button, it goes here. locationManager is an instance variable of the class.

-(IBAction)didClickStartGPS:(id)sender {
    locationManager = [[CLLocationManager alloc] init];
    [locationManager setDelegate:self];
    [locationManager startUpdatingLocation];
}

This saves the coordinates into a polyline and persists it. Note: with this code, I don't do any specific search descriptors, so if you click save multiple times, you'll get a bunch of polylines in your core data, and it'll probably only load the first one each time. You can do stuff like search through them for a certain id or date if you add that to the polyline object.

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

This loads the first polyline object from core data and converts it into your _locationArray of CLLocations. I don't do anything with the CLLocationCoordinate2D you can get from them.

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

This code is updated on my github:

github.com/bobbyren/StackOverflowTest.git

Edit: To add a new MKPolyline for each Polyline:

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中存储来自NSMutable Array的数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆