Frage

Ich habe eine Liste App erstellen und mit Kerndatensicherung.

Ich mag eine Standardliste von etwa 10 Flughafen Stücken haben, so dass der Benutzer nicht von Grunde auf neu starten muss.

Gibt es eine Möglichkeit, dies zu tun?

Jede Hilfe ist willkommen. Vielen Dank im Voraus.

War es hilfreich?

Lösung

Hier ist der beste Weg (und erfordert keine SQL-Kenntnisse):
Erstellen Sie ein schnelles Core Data iPhone App (oder sogar Mac App) das gleiche Objektmodell als Liste App. Schreiben Sie ein paar Zeilen Code die Standard verwalteten Objekte, die Sie in den Laden speichern möchten. Dann laufen diese App im Simulator. Gehen Sie nun zu ~ / Library / Application Support / iPhone Simulator / User / Applications. Finden Sie Ihre Anwendung unter dem GUIDs, dann kopieren Sie einfach den SQLite-Speicher heraus in der Liste der App-Projektordner.

Dann Last, die Speicher, wie sie in dem CoreDataBooks Beispiel tun.

Andere Tipps

Ja, es ist in der Tat das CoreDataBooks Beispiel bedeutet dies, können Sie den Code hier herunterladen: Beispielcode

Was Sie tun, ist der interne Speicher erstellen (Datenbank) das normale Verfahren mit Ihrem Speicher zu initialisieren, so wie Sie es mit jedem anderen Geschäft, dann einfach Sie Ihren Code ausführen und lassen Sie es den Code auszuführen, wie in dem CoreDataBooks Beispiel beschrieben ( Codeausschnitt unten). Sobald der Speicher initialisiert wurde wollen Sie eine NSManagedObjectContext erstellen und initialisieren es mit dem erstellten persistenten Speicher, Fügen Sie alle Elemente, die Sie brauchen, und speichern Sie den Kontext.

Wenn der Kontext erfolgreich gespeichert wurde, können Sie Ihre Anwendung beenden, dann gehen Sie zum Finder und gehen in den Ordnern: ~/Library/Developer Typen bei der Suche .sqlite und Blick unter / Developer nach dem Datum sortiert werden Sie die neuesten .sqlite Datenbank, die die Zeit wurde, dass der Code ausgeführt übereinstimmen sollten, dann können Sie diesen Speicher nehmen und fügen Sie es als Ressource des Projekts. Diese Datei kann dann durch einen persistenten Speicher Koordinator gelesen werden.

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

Ich hoffe, das hilft.

-Oscar

Mit dieser Methode, die Sie nicht brauchen, um eine separate App zu machen oder jede SQL-Kenntnisse haben. Sie müssen nur in der Lage sein, eine JSON-Datei für Ihre Ausgangsdaten zu machen.

Ich verwende eine JSON-Datei, dass ich in Objekte analysieren, dann legen Sie sie in Core Data. Ich tue dies, wenn die Anwendung initialisiert. Ich mache auch eine Einheit in meinen Kerndaten, wenn diese erste Daten zeigen bereits eingeführt ist, nachdem ich Einsatz die ersten Daten, die ich diese Einheit so eingestellt, dass das nächste Mal das Skript läuft es sieht, dass die ersten Daten bereits initialisiert wurde.

JSON-Datei Objekte zu lesen:

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

Dann können Sie Entitätsobjekten für es so machen:

[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

}];

Wenn Sie eine detaillierte Beschreibung wollen, wie dies zu tun, lesen Sie in diesem Tutorial: http://www.raywenderlich.com/12170/core- Daten-Tutorial-how-to-preloadimport bestehenden daten aktualisiert

Für 10 Stück, können Sie einfach diese in AppDelegate innerhalb applicationDidFinishLaunching: tun.

Definieren Sie eine Methode, sagen wir insertPredefinedObjects, die erstellt und füllt die Instanzen des Unternehmens verantwortlich für Ihre Flughafen Artikel verwalten und speichern Sie Ihre Kontext. Sie können entweder die Attribute aus einer Datei lesen oder einfach verdrahten sie in Ihrem Code. Dann rufen Sie diese Methode innerhalb applicationDidFinishLaunching:.

Beachten Sie, wenn nach dem CoreDataBooks Beispiel-Code, dass es wahrscheinlich bricht die iOS Data Storage-Richtlinien:

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

Ich habe eine App für das Kopieren der (read-only) vorge besiedelten Datenbank in das Dokumentenverzeichnis abgelehnt hatte - wie es dann bis zu iCloud gesichert wird -. Und Apple will nur, dass zu nutzergenerierten Dateien passieren

Die oben genannten Richtlinien bieten einige Lösungen, aber sie meist laufen auf:

  • Speicher die DB im Verzeichnis Caches und graziös Situationen behandeln, in denen das Betriebssystem die Caches spült -. Sie die DB wieder aufbauen müssen, die wahrscheinlich für die meisten von uns ausgeschlossen ist

  • set a 'nicht Cache-Attribut' auf der DB-Datei, die ein wenig obskur ist, wie es anders für verschiedene OS-Versionen getan werden muss.

Ich glaube nicht, es zu schwierig ist, aber darüber im Klaren sein, dass Sie ein bisschen mehr zu tun haben, dass die Beispiel-Code Arbeit neben iCloud zu machen ...

Also habe ich eine generische Methode, dass Belastungen aus einem Wörterbuch entwickelt haben (möglicherweise von JSON) und füllt die Datenbank. Es sollte nur mit vertrauenswürdigen Daten verwendet wird (von einem sicheren Kanal), ist es nicht zirkuläre Referenzen und Schema-Migrationen können problematisch umgehen kann ... Aber für einfache Anwendungsfälle wie bei mir soll es in Ordnung sein

Hier geht es

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

Und Lasten von 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 Beispiele

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

und

{
    "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"}]
}

Wie wäre es zu überprüfen, ob alle Objekte vorhanden sind und wenn nicht, mit einigen Daten erstellen?

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

Diese Antwort ist nur für Menschen, die

  • einschließlich einer Pre-besiedelte Datenbank in Ihrer App
  • macht eine App für mehrere Plattformen (iOS, Android, etc.).

Ich hatte eine vorbelegt SQLite-Datenbank für einen Android-App gemacht. Dann, als ich eine iOS-Version der App machen dachte ich, es wäre am besten, Core Data zu nutzen. Also habe ich eine ziemlich lange Zeit für das Erlernen Core Data ausgegeben und dann den Code Umschreiben der Datenbank vorab auszufüllen. Lernen, wie man jeden einzelnen Schritt in beide Plattformen tun erforderlich viel Forschung und Versuch und Irrtum. Es gab viel weniger überlappen, als ich gehofft hätte.

Am Ende habe ich beschlossen, nur die gleiche SQLite-Datenbank von meinem Android-Projekt zu verwenden. Dann habe ich den FMDB Wrapper, um direkt auf die Datenbank in iOS zugreifen. Die Vorteile:

  • Nur müssen die Vorkonfektionierte Datenbank einmal machen.
  • benötigt keinen Paradigmenwechsel. Die Syntax zwischen Android und FMDB, während andere, ist immer noch ziemlich ähnlich.
  • Haben Sie viel mehr Kontrolle darüber, wie Abfragen ausgeführt werden.
  • Erlaubt Volltextsuche.

Obwohl ich bereue nicht, Core Data zu lernen, wenn ich es tun über ich nur durch das Festhalten an SQLite viel Zeit retten können.

Wenn Sie in iOS starten und planen dann auf Android zu bewegen, würde ich immer noch einen SQLite-Wrapper wie FMDB oder eine andere Software verwenden, um die Datenbank vorab auszufüllen. Obwohl Sie technisch die SQLite-Datenbank extrahieren können, dass Sie mit Core Data vorab ausgefüllt, das Schema (Tabellen- und Spaltennamen, etc.) wird seltsam genannt werden.

By the way, wenn Sie Ihre Vorkonfektionierte Datenbank nicht ändern müssen, dann tun Sie es auf das Dokumentenverzeichnis nicht kopieren, nachdem die App installiert ist. Zugriff es einfach direkt aus dem Bündel.

// 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)

Das macht es so, dass Sie nicht über zwei Kopien.

Aktualisieren

Ich verwende jetzt SQLite.swift statt FMDB, weil es besser integriert mit Swift-Projekten.

Ein weiteres Verfahren für die Ausfälle Speicherung erfolgt über NSUserDefaults gefunden. (Überraschung!) Und seine leicht.

von einigen vorgeschlagen, setzen, dass in den applicationDidFinishLaunching

Im gegebenen Fall von 10 Standardwerten, Flughafen0 bis 9

Einstellung

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

oder

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

Und dann die Standardwerte zu bekommen.

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

Das ist für mich gearbeitet. Dies ist eine Modifikation dieser Antwort von Andrea Toso und inspiriert von diesem Blog . Das einzige Problem mit der Antwort ist, dass es eine Möglichkeit von Datenverlust ist, wenn SQLite-Dateien mit Filemanagern bewegen. Ich sparte rund 500 Reihen von Daten unter Verwendung replacePersistentStore statt FileManager.default.copyItem

Schritt 1:
Füllen Sie Ihre Stammdaten in einer anderen App und erhalten Dateien Weg mit diesem Code:

let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
print(documentsDirectory)

Schritt 2:
Ziehen Sie die 3 Dateien mit .sqlite Erweiterung in Ihr Xcode-Projekt. (Achten Sie darauf, In den Zielen Option).

Schritt 3:
Erstellen Funktion App ersten Lauf in AppDelegate.swift überprüfen

func isFirstLaunch() -> Bool {
    let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
    let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
    if (isFirstLaunch) {
        UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
        UserDefaults.standard.synchronize()
    }
    return isFirstLaunch
}

Schritt 4:
Kopieren Sie diese Funktion in AppDelegate.swift zu bekommen url wo SQLite-Datenbank sollte verschoben werden:

func getDocumentsDirectory()-> URL {
    let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    return documentsDirectory
}

Schritt 5:
Ersetzen Erklärung persistentContainer mit dieser:

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "ProjectName")

    let storeUrl = self.getDocumentsDirectory().appendingPathComponent("FileName.sqlite")

    if UserDefaults.isFirstLaunch() {
        let seededDataUrl = Bundle.main.url(forResource: "FileName", withExtension: "sqlite")
        try! container.persistentStoreCoordinator.replacePersistentStore(at: storeUrl, destinationOptions: nil, withPersistentStoreFrom: seededDataUrl!, sourceOptions: nil, ofType: NSSQLiteStoreType)
    }

    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top