19

私は Core Data を初めて使用するので、間違いを犯しているかどうかわかりません。REST API からいくつかのデータをダウンロードしましたが、JSON応答が正常にディスクに保存されます。Core Data を使用してデータを処理し、永続的に保存しようとしています。

NSLog(@"inserted objects: %@", [managedObjectContext insertedObjects]);
    [managedObjectContext performBlockAndWait:^{
        NSError *error = nil;
        if (![managedObjectContext save:&error]) {
            NSLog(@"Unable to save context for class %@", className);
        } else {
            NSLog(@"saved all records!");
        }
    }];

を正常に処理し、JSONに追加しましたNSManagedObjectContext。最初の行では、2 つのオブジェクトの挿入に成功したことが示されています。

inserted objects: {(
    <User: 0xa259af0> (entity: User; id: 0xa259b70 <x-coredata:///User/t44BB97D0-C4B4-4BA6-BD25-13CEFDAE665F3> ; data: {
    email = "vishnu@vishnuprem.com";
    experience = "2013-07-20";
    "first_name" = Vishnu;
    id = 2;
    "job_title" = Developer;
    "last_name" = Prem;
    location = "";
    "phone_number" = "+6590091516";
    "profile_pic" = "";
    "thumbnail_profile_pic" = "";
    "user_id" = 2;
}),
    <User: 0xa25e460> (entity: User; id: 0xa25e4c0 <x-coredata:///User/t44BB97D0-C4B4-4BA6-BD25-13CEFDAE665F2> ; data: {
    email = "sanchitbareja@gmail.com";
    experience = "2013-07-20";
    "first_name" = Sanchit;
    id = 1;
    "job_title" = Developer;
    "last_name" = Bareja;
    location = "";
    "phone_number" = "+15106127328";
    "profile_pic" = "";
    "thumbnail_profile_pic" = "";
    "user_id" = 1;
})
)}

を試みた[managedObjectContext save:&error]ところ、正常に実行され、期待どおりに「保存されたすべてのレコード」が出力されました。ただし、アプリケーション.sqliteファイルに移動して追加されたオブジェクトを確認すると、データベースにオブジェクトが追加されていないことがわかります。

アプリを再起動すると、データベースに既に存在するオブジェクトのリストが出力され、まだ保存されていないことが確認されます。

Core Data モデルに保存する必要がある「ユーザー」オブジェクトを正常に作成したように見えても、何が起こっているのか、なぜデータを永続的に保存できないのか、誰にもわかりません。

編集:

ここに私が作成する場所がありますNSPersistentStoreCoordinator

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"RTModel.sqlite"];

    NSError *error = nil;
    NSLog(@"Test 1");
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSLog(@"Test 2");

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        /*
         Replace this implementation with code to handle the error appropriately.

         abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

         Typical reasons for an error here include:
         * The persistent store is not accessible;
         * The schema for the persistent store is incompatible with current managed object model.
         Check the error message to determine what the actual problem was.


         If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.

         If you encounter schema incompatibility errors during development, you can reduce their frequency by:
         * Simply deleting the existing store:
         [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]

         * Performing automatic lightweight migration by passing the following dictionary as the options parameter:
         [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

         Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.

         */
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _persistentStoreCoordinator;
}

私は3つのコンテキストを持っています。

  • masterManagedObjectContext

  • backgroundManagedObjectContext

  • newManagedObjectContext

master は background と new の両方の親です。次のようにコンテキストを照会すると:

    NSError *error = nil;
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"User"];
    [request setSortDescriptors:[NSArray arrayWithObject:
                                 [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:YES]]];
    [request setReturnsObjectsAsFaults:NO];
    NSArray *testArray = [[[RTCoreDataController sharedInstance] newManagedObjectContext] executeFetchRequest:request error:&error];

    for (User *obj in testArray) {
        NSLog(@"obj.id %@", obj.id);
    }

    NSLog(@"query records: %@",testArray);

master と background はどちらも NSLog で正しい obj.id を返し、@"query records" に対して以下の出力を提供します

   (
    "<User: 0xa3811d0> (entity: User; id: 0xa381230 <x-coredata:///User/t92BCED2D-CD17-49CC-9EBA-DF8F52F06A002> ; data: {\n    email = \"sanchitbareja@gmail.com\";\n    experience = \"2013-07-20\";\n    \"first_name\" = Sanchit;\n    id = 1;\n    \"job_title\" = Developer;\n    \"last_name\" = Bareja;\n    location = \"\";\n    \"phone_number\" = \"+15106127328\";\n    \"profile_pic\" = \"\";\n    \"thumbnail_profile_pic\" = \"\";\n    \"user_id\" = 1;\n})",
    "<User: 0xa382170> (entity: User; id: 0xa3820b0 <x-coredata:///User/t92BCED2D-CD17-49CC-9EBA-DF8F52F06A003> ; data: {\n    email = \"vishnu@vishnuprem.com\";\n    experience = \"2013-07-20\";\n    \"first_name\" = Vishnu;\n    id = 2;\n    \"job_title\" = Developer;\n    \"last_name\" = Prem;\n    location = \"\";\n    \"phone_number\" = \"+6590091516\";\n    \"profile_pic\" = \"\";\n    \"thumbnail_profile_pic\" = \"\";\n    \"user_id\" = 2;\n})"
)

ただし、「new」は(null)obj.id に対してNSLog返され、次のように返されます@"query records"

(
    "<User: 0xa2b08a0> (entity: User; id: 0x95aebe0 <x-coredata:///User/tBFCC6C5F-7D2C-4AA0-BA96-B806EE360A762> ; data: <fault>)",
    "<User: 0xa2b0910> (entity: User; id: 0xa4b9780 <x-coredata:///User/tBFCC6C5F-7D2C-4AA0-BA96-B806EE360A763> ; data: <fault>)"
)
4

8 に答える 8

13

コードとコメントから、マスター コンテキストを保存していないようです。必ず電話してください

[managedObjectContext save:&error]; 

データを保存するすべての子コンテキストで、その後マスター コンテキストでも。

于 2013-08-17T22:22:23.010 に答える
10

本質的に同じ問題に頭をぶつけてしまいました。UITableViewController は NSManagedObjectContext から NSManagedObject のサブクラスをフェッチし、属性が nil かどうかをチェックし、データがダウンロードされた場合はその属性を設定し、NSManagedObjectContext を保存しました。このようなもの:

MyManagedObject *mgObject = //get object from NSFetchResultsController
NSManagedObjectContext *mgObContext = mgObject.managedObjectContext;
if (!mgObject.data)
{
    mgObject.data = [NSData dataWithContentsOfURL:urlWithData];
    [mgObContext performBlock ^{
        NSError *saveError = nil;
        BOOL saveResult = [mgObContext save:&saveError];
        if (saveError || !saveResult)
        {
            NSLog(@"Save not successful..");
        }
    }];
}
//do something with myObject.data

保存関数は YES ブール値を返し、saveError は nil のままでしたが、アプリを終了して再起動すると、Core Data が NSManagedObject サブクラスをロードしたとき、データ属性は nil であり、この UITableViewController が戻ってきたとき、それはデータを再度ダウンロードします。

これに対する解決策はどこにも見つかりませんでした… Core Data のドキュメントを読んでも役に立ちませんでした。上記のコードと、基本的には NSManagedObject サブクラスのファクトリ メソッドで属性を設定するコードとの違いを検討したときに、解決策が思い浮かびました。

MyManagedObject *mgObject = [NSEntityForDescription insertNewObjectForEntityName:@"MyManagedObject" inManagedContext:mgObContext];
mgObject.attribute1 = some value
mgObject.attribute2 = another value

唯一の違いは、[mgObContext performBlock:] 内からファクトリ メソッドを呼び出していることです。

したがって、修正されたコードは次のとおりです。

MyManagedObject *mgObject = //get object from NSFetchResultsController
NSManagedObjectContext *mgObContext = mgObject.managedObjectContext;
if (!mgObject.data)
{
    [mgObContext performBlock: ^{
        mgObject.data = [NSData dataWithContentsOfURL:urlWithData];
        NSError *saveError = nil;
        BOOL saveResult = [mgObContext save:&saveError];
        if (saveError || !saveResult)
        {
            NSLog(@"Save not successful..");
        }
    }];
}
//do something with myObject.data

これまでのところ、これは完全に機能しています。したがって、NSManagedObjects の属性を変更するときはいつでも、NSManagedObjectContext のスレッドで行う必要があると思います。

于 2014-03-09T03:04:58.447 に答える
8

また、同様の問題を抱えている可能性のある人々にいくつかの情報を追加すると考えました。

私の経験では、十分なフィールドが入力されていないオブジェクトを保存しようとしても、保存時に持続しないようであり、その場合でもエラーはスローされないようです。保存が開始される前に、フィールドが期待どおりに入力されていることを常に再確認してください。

この種の問題を見るもう 1 つの方法は、問題をひっくり返すことです。オブジェクトが実際に保存された可能性がありますが、実際に保存されたことを確認する方法が間違っています。多くの場合、特定の基準を使用してレコードの CoreData をクエリすることで、これを行うことができます。基準が正しいこと、およびクエリが実際に期待どおりに返されていることを再確認してください。

期待した結果が返されない場合は、エラーが原因である可能性がありますが、結果を格納する配列が正しく格納されていない可能性もあります。NSArray以前に、配列名に関する何かが参照の問題を引き起こし、配列が期待した結果を指すことができなかったため、名前を変更しなければならなかったケースに遭遇しました。乾杯。

于 2015-10-27T22:32:29.510 に答える
4

データを保存した後、これを追加します。

NSError *error = nil;
if (![managedObjectContext save:&error]) {
    NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
}
于 2016-10-13T08:12:09.143 に答える
3

これはOPが尋ねたことに対する答えではないことは知っていますが、他の誰かに役立つ場合に備えて、同じ主題に関する私の経験を共有したいと思いました.

データを永続的に保存する際にいくつかの問題がありましたが、それを修正するのに役立つように思えました。構造は非常に単純で、1 つのフィールドと 1 つの関係 (対多) を持つエンティティです。NSMutableOrderedSetの代わりに、生成されたクラスにいくつかの変更を加えましたNSOrderedSet

私はマルチスレッドなどを行っていませんでした。関係に要素を追加しただけです。アプリケーションを保存して再起動した後、データが消えました (関係に要素が追加されました)。

私はupdatedというプロパティがあることを発見しました。リレーションシップに新しい要素を追加した後、このプロパティの値が変更されたかどうかを確認しました。そうではありませんでした。そのため、この関係に要素を追加した後にエンティティを強制的に保存できるようにするために、エンティティにブール値の別のフィールドを作成する必要がありました。

entity.addObject(..)
entity.forceUpdate = true // without this line, it won't update
managedContext.save(..)

だから、私はそれを正しく保存していないと思っていたので、同じ問題を抱えている人に役立つことを願っています..

于 2015-03-03T09:10:39.910 に答える
2

私は iOS の初心者ですが、CoreData を使用してユーザー情報を保存する例をいくつか作成しました。

まず、エンティティを使用してモデルを作成する必要があります (すでに行っていると思います)。私の例では、私のエンティティは「ユーザー」と呼ばれています。

まず、これに似たプロパティを追加します

NSManagedObjectContext *context;

ViewController クラスに。

次に、viewDidLoad メソッドに次の 2 行を追加します。

AppDelegate *appdelegate = [[UIApplication sharedApplication]delegate];
context = [appdelegate managedObjectContext];

そして 3 番目に、情報を保存します。

NSEntityDescription *entitydesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context];
NSManagedObject *newUser = [[NSManagedObject alloc]initWithEntity:entitydesc insertIntoManagedObjectContext:context];
[newUser setValue:(NSString *)[dictionary objectForKey:@"name"] forKey:@"name"];
[newUser setValue:(NSString *)[dictionary objectForKey:@"surname"] forKey:@"surname"];
...

NSError *error;
[context save:&error];

(辞書と呼ばれる NSDictionary からプロパティを取得します)

あなたの情報を読むには:

AppDelegate *appdelegate = [[UIApplication sharedApplication]delegate];
context = [appdelegate managedObjectContext];
NSEntityDescription *entitydesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:entitydesc];

//NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NULL"];
[request setPredicate:nil];

NSError *error;
NSArray *matchingData = [context executeFetchRequest:request error:&error];
//NSArray *matchingData = [context executeFetchRequest:nil error:&error];

// If the user is not logged in previously
if (matchingData.count <=0 ){
    //self.displaylabel.text = @"No person find";
} else {
// If the user is already logged in
    for (NSManagedObject *obj in matchingData) {
        AppDataModel *appDataModel=[AppDataModel getInstance];
        appDataModel.appUserInfo = [User alloc]; 
        appDataModel.appUserInfo.name = [obj valueForKey:@"name"];
        appDataModel.appUserInfo.surname = [obj valueForKey:@"surname"];
    }
}
于 2013-08-19T14:39:07.777 に答える