Question

J'ai crée une application de liste et la sauvegarde avec les données de base.

Je voudrais avoir une liste par défaut de dire 10 articles de l'aéroport, de sorte que l'utilisateur ne doit pas repartir de zéro.

Est-il possible de le faire?

Toute aide est appréciée. Merci à l'avance.

Était-ce utile?

La solution

Voici la meilleure façon (et ne nécessite pas de connaissances SQL):
Créer une application iPhone rapide de base de données (ou même application Mac) en utilisant le même modèle d'objet que votre application de la liste. Écrire quelques lignes de code pour enregistrer les objets par défaut géré à la boutique. Ensuite, exécutez cette application dans le simulateur. Maintenant, allez à ~ / Library / Application Support / iPhone Simulator / utilisateur / Applications. Trouvez votre application parmi les GUIDs, puis il suffit de copier le magasin sqlite sur dans le dossier du projet de votre application de liste.

Ensuite, la charge qui stockent comme ils le font dans l'exemple de CoreDataBooks.

Autres conseils

Oui, il y a, en fait, l'exemple CoreDataBooks que cela, vous pouvez télécharger le code ici: un exemple de code

Ce que vous faites est de créer le magasin interne (base de données) en utilisant la procédure normale pour initialiser votre magasin comme vous le feriez avec tout autre magasin, vous exécutez simplement votre code et laisser exécuter le code comme décrit dans l'exemple de CoreDataBooks ( extrait de code ci-dessous). Une fois que le magasin a été initialisé vous voulez créer un NSManagedObjectContext et l'initialiser avec le magasin persistant créé, insérez toutes les entités dont vous avez besoin, et enregistrez le contexte.

Une fois que le contexte a été enregistré avec succès, vous pouvez arrêter votre application, puis aller à Moteur de Recherche et aller au dossier: type ~/Library/Developer dans le .sqlite de recherche et regarder sous / Developer, le tri par date vous donnera le plus récent .sqlite base de données qui doit correspondre au temps que le code a été exécuté, vous pouvez alors prendre ce magasin et l'ajouter en tant que ressource de votre projet. Ce fichier peut alors être lu par un coordonnateur du magasin persistant.

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

L'espoir qui aide.

-Oscar

Avec cette méthode, vous n'avez pas besoin de faire une application séparée ou avoir des connaissances en SQL. Vous ne devez être en mesure de faire un fichier JSON pour vos données initiales.

J'utilise un fichier JSON que je parse des objets, puis les insérer dans Core Data. Je le fais lorsque l'application initialise. Je fais aussi une entité dans mes données de base qui indique si ces données de départ est déjà inséré, après insérer les données initiales que je mis cette entité de sorte que la prochaine fois que le script est exécuté il voit que les données initiales a déjà été initialisé.

Pour lire le fichier JSON en objets:

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

Ensuite, vous pouvez faire des objets d'entité pour elle comme ceci:

[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

}];

Si vous voulez une description plus détaillée sur la façon de procéder, consultez ce tutoriel: http://www.raywenderlich.com/12170/core- données-tutorial-how-to-preloadimport-données-existants mis à jour

Pour 10 articles, vous pouvez simplement le faire dans applicationDidFinishLaunching: dans votre délégué de l'application.

Définir une méthode, par exemple insertPredefinedObjects, qui crée et renseigne les instances de l'entité chargée de la gestion de vos articles de l'aéroport et enregistrer votre contexte. Vous pouvez soit lire les attributs d'un fichier ou tout simplement les câbler dans votre code. Ensuite, appelez cette méthode à l'intérieur applicationDidFinishLaunching:.

Gardez à l'esprit, en suivant l'exemple de code CoreDataBooks, qu'il casse probablement les lignes directrices de stockage de données iOS:

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

J'ai eu une application rejetée pour copier le (lecture seule) base de données pré-rempli dans le répertoire des documents - comme il se puis sauvegardées sur iCloud -. Et Apple veulent seulement que cela se produise dans les fichiers générés par l'utilisateur

Les directives ci-dessus offre quelques solutions, mais ils font bouillir la plupart du temps jusqu'à:

  • stocker la base de données dans le répertoire des caches et gérer correctement les situations où le système d'exploitation purges les caches -. Vous devrez reconstruire le DB, ce qui exclut probablement pour la plupart d'entre nous

  • définir un 'ne pas attribut cache' dans le fichier DB, qui est un peu Arcane, comme il doit être fait différemment pour les différentes versions OS.

Je ne pense pas que ce soit trop difficile, mais sachez que vous avez un peu plus à faire pour faire cet exemple travail de code aux côtés iCloud ...

J'ai donc mis au point une méthode générique qui se charge d'un dictionnaire (peut-être de JSON) et renseigne la base de données. Il doit être utilisé uniquement avec des données fiables (à partir d'un canal sûr), il ne peut pas gérer des références circulaires et les migrations de schéma peut être problématique ... Mais pour les cas simples d'utilisation comme le mien, il devrait être bien

Ici, il va

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

et les charges de 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]];

Exemples JSON

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

et

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

Qu'en est-il vérifier si des objets existent et sinon, créer un avec des données?

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

Cette réponse est seulement pour les personnes qui sont

  • y compris une base de données préchargées dans votre application
  • faire une application pour plusieurs plates-formes (IOS, les applications, etc.)

Je l'avais fait une base de données SQLite prérempli pour une application Android. Puis, quand je faisais une version iOS de l'application que je pensais que ce serait préférable d'utiliser des données de base. J'ai donc passé un temps assez long apprentissage de base de données, puis réécrire le code pour préremplir la base de données. Apprendre à faire chaque étape dans les deux plates-formes requises beaucoup de recherche et d'essais et d'erreurs. Il y avait beaucoup moins de chevauchement que je l'aurais espéré.

En fin de compte je viens décidé d'utiliser la même base de données SQLite de mon projet Android. Ensuite, je l'emballage FMDB pour accéder directement à la base de données dans iOS. Les avantages:

  • Suffit de faire une fois que la base de données préremplies.
  • Ne nécessite pas un changement de paradigme. La syntaxe entre Android et FMDB, bien que différents, est encore assez similaire.
  • Avoir beaucoup plus de contrôle sur la façon dont les requêtes sont effectuées.
  • Permet une recherche en texte intégral.

Bien que je ne regrette pas l'apprentissage de base de données, si je devais le faire sur je aurais pu sauver beaucoup de temps en collant juste SQLite.

Si vous commencez dans iOS et de la planification puis de passer à Android, je continue à utiliser un emballage SQLite comme FMDB ou un autre logiciel pour préremplir la base de données. Bien que techniquement, vous pouvez extraire la base de données SQLite que vous préremplir avec Core Data, le schéma (noms de table et de colonne, etc.) sera étrangement nommé.

Par ailleurs, si vous n'avez pas besoin de modifier votre base de données préremplies, alors ne copiez pas dans le répertoire des documents après l'application est installée. Il suffit d'accéder directement à partir du faisceau.

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

fait en sorte que vous n'avez pas deux copies.

Mise à jour

Je l'utilise maintenant SQLite.swift plutôt que FMDB, car il intègre mieux avec projets Swift.

Une autre méthode pour stocker des valeurs par défaut est trouvé par l'intermédiaire d'NSUserDefaults. (surprise!) Et il est facile.

suggérée par certains, mettez-le dans applicationDidFinishLaunching

Dans le cas particulier des 10 paramètres par défaut, Aéroport0 thru 9

Réglage

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

ou

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

Et puis, obtenir les valeurs par défaut.

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

Cela a fonctionné pour moi. Ceci est une modification de cette répondre par Andrea Toso et inspiré par cette Blog . Le seul problème avec la réponse est qu'il ya une chance de perte de données lors du déplacement des fichiers SQLite avec FileManager. J'ai sauvé environ 500 lignes de données à l'aide replacePersistentStore au lieu de FileManager.default.copyItem

Étape 1 Peupler vos données de base dans une autre application et obtenir le chemin de fichiers en utilisant ce code:

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

Étape 2 Faites glisser vos 3 fichiers avec l'extension .sqlite dans votre projet Xcode. (Assurez-vous de sélectionner l'option Ajouter à cibles).

Étape 3 Créer la fonction de vérifier d'abord l'exécution de l'application dans AppDelegate.swift

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
}

Step4 Copiez cette fonction dans AppDelegate.swift pour obtenir url où la base de données SQLite doit être déplacé:

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

Étape 5 Remplacer déclaration de persistentContainer avec celui-ci:

// 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
}()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top