web-dev-qa-db-fra.com

Comment ajouter des données de base à un projet Xcode 9 existant Swift 4 iOS 11)?

Une mise à jour est demandée, puisque cette question a bien sûr été répondue pour les versions précédentes, le dernier résultat de recherche daté du 12/16 génère une compatibilité non pertinente avec les projets iOS 9 et 10 précédents.

La documentation indique bien sûr de sélectionner la case à cocher Utiliser les données de base lors du démarrage d'un nouveau projet, que je n'ai pas sélectionné, mais pense maintenant que iCloud + Core Data doit être ajouté pour amener mon application à sa prochaine phase -> dans laquelle quelque chose comme NSFileCoordinator et NSFilePresenter est nécessaire, car dans mon application, les utilisateurs de l'interface utilisateur sont présentés avec un certain nombre de sujets, chacun ayant trois OPTIONS, concernant les utilisateurs qui doivent choisir une option. Pour chaque sujet, l'interface utilisateur affiche ensuite le NOMBRE TOTAL d'utilisateurs qui ont choisi chaque option et le POURCENTAGE du total pour chaque option.

À l'heure actuelle, le nombre de choix pour chaque option et le pourcentage du total sont bien sûr simplement calculés dans mon application native -> mais doivent en fait être CALCULÉS dans quelque chose de central comme le cloud ou très probablement sur un site Web ... mais ensuite le site Web soulève les problèmes de lecture/écriture simultanés que NSFileCoordinator et NSFilePresenter ont déjà résolus.

Donc, si le système iCloud + Core Data peut interjecter des calculs arithmétiques de base sur les totaux de valeurs numériques du conteneur Ubiquitous existants - dans le cloud lors de la réception des commandes d'écriture de valeurs numériques d'utilisateurs individuels - avant d'envoyer les nouvelles valeurs numériques totales et en pourcentage du conteneur Ubiquitous Container - alors je J'apprécierais beaucoup les conseils sur la façon de corriger les erreurs générées ci-dessous en essayant de créer et d'initialiser la pile de données de base. Sinon, devinez que je vais devoir gratter Xcode et aller à une application hybride comme PhoneGap si c'est la meilleure pour le travail.

Par conséquent, en se référant au Core Data Programming Guide:

https://developer.Apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/InitializingtheCoreDataStack.html#//Apple_ref/doc/uid/TP40001075-CH4-SW1

et coller dans le code suivant au début de mon projet existant, génère

Utilisation de l'identifiant non résolu "persistentContainer"… "managedObjectContext"

... les erreurs. Et la ligne

init(completionClosure: @escaping () -> ()) { 

... génère

Les initialiseurs ne peuvent être déclarés que dans un type

import UIKit

import CoreData
class DataController: NSObject {
  var managedObjectContext: NSManagedObjectContext
  init(completionClosure: @escaping () -> ()) {
    persistentContainer = NSPersistentContainer(name: "DataModel")
    persistentContainer.loadPersistentStores() { (description, error) in
      if let error = error {
        fatalError("Failed to load Core Data stack: \(error)")
      }
      completionClosure()
    }
  }
}

init(completionClosure: @escaping () -> ()) {
  //This resource is the same name as your xcdatamodeld contained in your project
  guard let modelURL = Bundle.main.url(forResource: "DataModel", withExtension:"momd") else {
    fatalError("Error loading model from bundle")
  }
  // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
  guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
    fatalError("Error initializing mom from: \(modelURL)")
  }

  let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)

  managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.mainQueueConcurrencyType)
  managedObjectContext.persistentStoreCoordinator = psc

  let queue = DispatchQueue.global(qos: DispatchQoS.QoSClass.background)
  queue.async {
    guard let docURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
      fatalError("Unable to resolve document directory")
    }
    let storeURL = docURL.appendingPathComponent("DataModel.sqlite")
    do {
      try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
      //The callback block is expected to complete the User Interface and therefore should be presented back on the main queue so that the user interface does not need to be concerned with which queue this call is coming from.
      DispatchQueue.main.sync(execute: completionClosure)
    } catch {
      fatalError("Error migrating store: \(error)")
    }
  }
}

// followed by my existing working code:

class ViewController: UIViewController {
13
ehounder

allez dans Fichier> nouveau fichier ... sélectionnez Données de base sous iOS et sélectionnez Modèle de données vous aurez toujours besoin d'un code que xcode génère automatiquement chaque fois que vous sélectionnez des données de base lors de la création du projet. pour l'obtenir, créez simplement un nouveau projet avec l'option de données de base vérifié et copiez tout le code écrit sous ** // Marque: - Core Data Stack ** commentaire dans AppDelegate.Swift = et ajoutez

import CoreData

au dessus de

FACULTATIF

Et n'oubliez pas de changer le nom de l'application après avoir copié le bloc d'achèvement pour lazy var persistentContainer. Modifiez le nom de votre application sur cette partie * NSPersistentContainer (nom: "DEVRAIT-ÊTRE-LE-NOM-DE-VOTRE-APP") Et la fonction managedObjectModel du code que vous venez de copier **

35
Jay N.

Si vous êtes paresseux comme moi, voici tout le code que vous devez copier à partir du nouveau projet Core Data ... (pourquoi inciter tout le monde à créer un nouveau projet?). Modifiez YOUR_APP_NAME_HERE

import CoreData


// MARK: - Core Data stack

func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        // Saves changes in the application's managed object context before the application terminates.
        self.saveContext()
    }

lazy var persistentContainer: NSPersistentContainer = {
    /*
     The persistent container for the application. This implementation
     creates and returns a container, having loaded the store for the
     application to it. This property is optional since there are legitimate
     error conditions that could cause the creation of the store to fail.
    */
    let container = NSPersistentContainer(name: "YOUR_APP_NAME_HERE")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() 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 parent directory does not exist, cannot be created, or disallows writing.
             * The persistent store is not accessible, due to permissions or data protection when the device is locked.
             * The device is out of space.
             * The store could not be migrated to the current model version.
             Check the error message to determine what the actual problem was.
             */
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

// MARK: - Core Data Saving support

func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() 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.
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}
11
iOSDevSF

Je sais que c'est répondu, mais je crois que le problème réel est avec la documentation d'Apple. Si vous comparez le code Objective-C au code Swift, vous verrez que var managedObjectContext: NSManagedObjectContext n'est pas réellement défini. Vous devez remplacer cette ligne par var persistentContainer: NSPersistentContainer. Ceci est l'interface Objective-c

@interface MyDataController : NSObject
@property (strong, nonatomic, readonly) NSPersistentContainer *persistentContainer; 
- (id)initWithCompletionBlock:(CallbackBlock)callback;
@end

Alors DataController.Swift devrait être:

class DataController: NSObject {
 // Delete this line   var managedObjectContext: NSManagedObjectContext
    var persistentContainer: NSPersistentContainer
    init(completionClosure: @escaping () -> ()) {
        persistentContainer = NSPersistentContainer(name: "DataModel")
        persistentContainer.loadPersistentStores() { (description, error) in
          if let error = error {
              fatalError("Failed to load Core Data stack: \(error)")
          }
          completionClosure()
       }
    }
}

Quant au reste de votre code, il n'est pas nécessaire Apple Docs .

Avant iOS 10 et macOS 10.12, la création de la pile Core Data était plus impliquée

Cette section de code vous montre l'ancienne méthode.

3
hidden-username