web-dev-qa-db-ja.com

コアデータを事前入力する方法はありますか?

リストアプリを作成し、コアデータでバックアップしています。

ユーザーが最初から始める必要がないように、たとえば10個の空港のアイテムのデフォルトのリストが必要です。

これを行う方法はありますか?

どんな助けも大歓迎です。前もって感謝します。

61
Tanner

これが最良の方法です(SQLの知識は必要ありません):
Listアプリと同じオブジェクトモデルを使用して、簡単なCore Data iPhoneアプリ(またはMacアプリ)を作成します。数行のコードを記述して、ストアに必要なデフォルトの管理対象オブジェクトを保存します。次に、シミュレータでそのアプリを実行します。次に、〜/ライブラリ/ Application Support/iPhone Simulator/User/Applicationsに移動します。 GUIDからアプリケーションを見つけて、sqliteストアをListアプリのプロジェクトフォルダーにコピーします。

次に、CoreDataBooksの例で行うように、そのストアをロードします。

58
Ken Aspeslagh

はい、実際にはCoreDataBooksの例がこれを行います。ここからコードをダウンロードできます。 サンプルコード

通常の手順を使用して内部ストア(データベース)を作成し、他のストアと同じようにストアを初期化します。その後、単純にコードを実行し、CoreDataBooksの例で説明するコードを実行させます(以下のコードスニペット)。ストアを初期化したら、NSManagedObjectContextを作成し、作成した永続ストアで初期化し、必要なすべてのエンティティを挿入し、コンテキストを保存します。

コンテキストが正常に保存されたら、アプリケーションを停止し、Finderに移動してフォルダーに移動できます:~/Library/Developer検索.sqliteを入力し、/ Developerの下を見て、日付でソートすると、コードが実行された時刻に一致する最新の.sqliteデータベースが得られます。その後、このストアを取得して、あなたのプロジェクト。このファイルは、永続ストアコーディネーターによって読み取られます。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (persistentStoreCoordinator) {
    return persistentStoreCoordinator;
}


NSString *storePath = [[self applicationDocumentsDirectory]      stringByAppendingPathComponent: @"CoreDataBooks.sqlite"];
 /*
  Set up the store.
 For the sake of illustration, provide a pre-populated default store.
 */
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
  NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"CoreDataBooks"      ofType:@"sqlite"];
 if (defaultStorePath) {
 [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
 }
}

NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber   numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

 NSError *error;
 if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
  // Update to handle the error appropriately.
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
 exit(-1);  // Fail
}    

return persistentStoreCoordinator;
}

お役に立てば幸いです。

-オスカー

30
Oscar Gomez

この方法を使用すると、個別のアプリを作成したり、SQLの知識を持っている必要はありません。初期データ用のJSONファイルを作成する必要があるだけです。

オブジェクトに解析するJSONファイルを使用し、それらをCore Dataに挿入します。アプリの初期化時にこれを行います。また、コアデータにこの初期データが既に挿入されているかどうかを示す1つのエンティティを作成します。初期データを挿入した後、このエンティティを設定して、次回スクリプトを実行するときに初期データが既に初期化されていることを確認します。

JSONファイルをオブジェクトに読み込むには:

NSString *initialDataFile = [[NSBundle mainBundle] pathForResource:@"InitialData" ofType:@"json"];
NSError *readJsonError = nil;
NSArray *initialData = [NSJSONSerialization
                        JSONObjectWithData:[NSData dataWithContentsOfFile:initialDataFile]
                        options:kNilOptions
                        error:&readJsonError];

if(!initialData) {
    NSLog(@"Could not read JSON file: %@", readJsonError);
    abort();
}

次に、次のようにエンティティオブジェクトを作成できます。

[initialData enumerateObjectsUsingBlock:^(id objData, NSUInteger idx, BOOL *stop) {

    MyEntityObject *obj = [NSEntityDescription
                          insertNewObjectForEntityForName:@"MyEntity"
                          inManagedObjectContext:dataController.managedObjectContext];

    obj.name = [objData objectForKey:@"name"];
    obj.description = [objData objectForKey:@"description"];

    // then insert 'obj' into Core Data

}];

これを行う方法の詳細については、このチュートリアルをご覧ください。 http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-更新済み

11
gitaarik

10アイテムの場合、アプリデリゲートのapplicationDidFinishLaunching:内でこれを行うことができます。

insertPredefinedObjectsなどのメソッドを定義して、空港アイテムの管理を担当するエンティティのインスタンスを作成および入力し、コンテキストを保存します。ファイルから属性を読み取るか、コードに単純に組み込むことができます。次に、applicationDidFinishLaunching:内でこのメソッドを呼び出します。

8
Massimo Cafaro

CoreDataBooksのサンプルコードに従う場合、おそらくiOSデータストレージガイドラインに違反することに注意してください。

https://developer.Apple.com/icloud/documentation/data-storage/

(読み取り専用)事前に入力されたデータベースをドキュメントディレクトリにコピーするためにアプリが拒否されました-iCloudにバックアップされるため-Appleユーザー生成ファイル。

上記のガイドラインはいくつかの解決策を提供しますが、それらは主に次のように要約されます:

  • dBをキャッシュディレクトリに保存し、OSがキャッシュを削除する状況を適切に処理します。DBを再構築する必要があります。

  • dBファイルに「キャッシュしない」属性を設定します。これは、OSバージョンごとに異なる方法で実行する必要があるため、少し難解です。

それほどトリッキーだとは思いませんが、iCloudと一緒にそのサンプルコードを動作させるためにもう少しやることがあることに注意してください...

5
Adrian Bigland

そこで、辞書から(おそらくJSONから)ロードし、データベースにデータを取り込む汎用メソッドを開発しました。 (安全なチャネルからの)信頼できるデータでのみ使用する必要があり、循環参照を処理できず、スキーマの移行が問題になる可能性があります...しかし、私のような単純なユースケースでは問題ありません

ここに行く

- (void)populateDBWithDict:(NSDictionary*)dict
               withContext:(NSManagedObjectContext*)context
{
    for (NSString* entitieName in dict) {

        for (NSDictionary* objDict in dict[entitieName]) {

            NSManagedObject* obj = [NSEntityDescription insertNewObjectForEntityForName:entitieName inManagedObjectContext:context];
            for (NSString* fieldName in objDict) {

                NSString* attName, *relatedClass, *relatedClassKey;

                if ([fieldName rangeOfString:@">"].location == NSNotFound) {
                    //Normal attribute
                    attName = fieldName; relatedClass=nil; relatedClassKey=nil;
                } else {
                    NSArray* strComponents = [fieldName componentsSeparatedByString:@">"];
                    attName = (NSString*)strComponents[0];
                    relatedClass = (NSString*)strComponents[1];
                    relatedClassKey = (NSString*)strComponents[2];
                }
                SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", attName ]);
                NSMethodSignature* signature = [obj methodSignatureForSelector:selector];
                NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
                [invocation setTarget:obj];
                [invocation setSelector:selector];

                //Lets set the argument
                if (relatedClass) {
                    //It is a relationship
                    //Fetch the object
                    NSFetchRequest* query = [NSFetchRequest fetchRequestWithEntityName:relatedClass];
                    query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:relatedClassKey ascending:YES]];
                    query.predicate = [NSPredicate predicateWithFormat:@"%K = %@", relatedClassKey, objDict[fieldName]];

                    NSError* error = nil;
                    NSArray* matches = [context executeFetchRequest:query error:&error];


                    if ([matches count] == 1) {
                        NSManagedObject* relatedObject = [matches lastObject];
                        [invocation setArgument:&relatedObject atIndex:2];
                    } else {
                        NSLog(@"Error! %@ = %@ (count: %d)", relatedClassKey,objDict[fieldName],[matches count]);
                    }


                } else if ([objDict[fieldName] isKindOfClass:[NSString class]]) {

                    //It is NSString
                    NSString* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];
                } else if ([objDict[fieldName] isKindOfClass:[NSNumber class]]) {

                    //It is NSNumber, get the type
                    NSNumber* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];

                }
                [invocation invoke];


            }

            NSError *error;
            if (![context save:&error]) {
                NSLog(@"%@",[error description]);
            }
        }
    }   
}

そして、jsonからロードします...

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"initialDB" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];

NSError* error;
NSDictionary *initialDBDict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                           options:NSJSONReadingMutableContainers error:&error];

[ self populateDBWithDict:initialDBDict withContext: [self managedObjectContext]];

JSONの例

    {
    "EntitieA": [ {"Att1": 1 }, {"Att1": 2} ],
    "EntitieB": [ {"Easy":"AS ABC", "Aref>EntitieA>Att1": 1} ]
    }

そして

{
    "Country": [{"Code": 55, "Name": "Brasil","Acronym": "BR"}],
    "Region": [{"Country>Country>code": 55, "Code": 11, "Name": "Sao Paulo"},
               {"Country>Country>code": 55, "Code": 31, "Name": "Belo Horizonte"}]
}
2
Felizardo

オブジェクトが存在するかどうかを確認し、存在しない場合は、何らかのデータでオブジェクトを作成しますか?

NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Settings"];
_managedObjectSettings = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];

if ([_managedObjectSettings count] == 0) {
    // first time, create some defaults
    NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:@"Settings" inManagedObjectContext:managedObjectContext];

    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"speed"];
    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"sound"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey:@"aspect"];
    [newDevice setValue:[NSNumber numberWithBool: NO  ] forKey: @"useH264"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey: @"useThumbnail"];

    NSError *error = nil;
    // Save the object to persistent store
    if (![managedObjectContext save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
}
2
Md1079

この答えは、

  • アプリに事前に入力されたデータベースを含める
  • 複数のプラットフォーム(iOS、Androidなど)向けのアプリの作成

Androidアプリ用に事前に設定されたSQLiteデータベースを作成しました。その後、アプリのiOSバージョンを作成していたときに、Core Dataを使用するのがベストだと思いました。 Core Dataを学習し、コードを書き直してデータベースに事前入力します両方のプラットフォームですべてのステップを実行する方法を学習するには、多くの研究と試行錯誤が必要でした。

最終的に、Androidプロジェクトから同じSQLiteデータベースを使用することにしました。次に、FMDBラッパーを使用して、iOSのデータベースに直接アクセスしました。利点:

  • 事前に作成されたデータベースを一度作成するだけで済みます。
  • パラダイムシフトを必要としません。 AndroidとFMDBの間の構文は異なりますが、まだかなり似ています。
  • クエリの実行方法をより詳細に制御できます。
  • 全文検索を許可します。

コアデータの学習を後悔することはありませんが、それをやり直せば、SQLiteに固執するだけで多くの時間を節約できます。

IOSで始めてからAndroidに移行することを計画している場合は、FMDBなどのSQLiteラッパーまたは他のソフトウェアを使用してデータベースに事前に入力します。 Core Dataを事前に入力したSQLiteデータベースを技術的に抽出することはできますが、スキーマ(テーブル名や列名など)は奇妙な名前になります。

ところで、事前に入力されたデータベースを変更する必要がない場合は、アプリのインストール後にデータベースをドキュメントディレクトリにコピーしないでください。バンドルから直接アクセスするだけです。

// get url reference to databaseName.sqlite in the bundle
let databaseURL: NSURL = NSBundle.mainBundle().URLForResource("databaseName", withExtension: "sqlite")!

// convert the url to a path so that FMDB can use it
let database = FMDatabase(path: databaseURL.path)

これにより、コピーが2つないようになります。

更新

FMDBではなく SQLite.Swift を使用しています。これは、Swiftプロジェクトとの統合性が高いためです。

2
Suragch

NSUserDefaultsを使用して、デフォルトを保存する別の方法が見つかります。 (驚き!)そして簡単です。

いくつかによって提案され、それをapplicationDidFinishLaunchingに入れます

デフォルト値が10の場合、Airport0〜9

セッティング

NSUserDefaults *nud = [NSUserDefaults standardUserDefaults];
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport0"];
    ...
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport9"];
[nud synchronize];

または

[[NSUserDefaults standardUserDefaults] setString:@"MACADDRESSORWHY" forKey:@"Airport9"]];
     ...
[[NSUserDefaults standardUserDefaults] synchronize];

そして、デフォルトを取得します。

NSString *air0 = [[NSUserDefaults standardUserDefaults] stringForKey:@"Airport0"];
0
Gabe Rainbow