iOS
...
Data Objects
Analyse des Types de Données avec ParseSwift sur iOS
16 min
analyser les types de données sur swift introduction lors de l'enregistrement de données sur une base de données back4app, chaque entité est stockée sous forme de paires clé valeur le type de données pour le champ valeur va des fondamentaux (tels que string , int , double , float , et bool ) à des structures plus complexes la principale exigence pour stocker des données sur une base de données back4app est que l'entité doit se conformer au parseswift protocole à son tour, ce protocole fournit un ensemble de méthodes pour stocker, mettre à jour et supprimer toute instance d'une entité dans ce guide, vous apprendrez comment créer et configurer une entité pour l'enregistrer sur votre base de données back4app dans l'exemple de projet, l'entité que nous stockons contient des informations sur une recette ce tutoriel utilise une application de base créée dans xcode 12 et ios 14 à tout moment, vous pouvez accéder au projet complet via nos dépôts github dépôt d'exemple ios objectif pour comprendre comment les objets sont analysés et stockés dans une base de données back4app prérequis pour compléter ce guide rapide, vous avez besoin de xcode une application créée sur back4app suivez le tutoriel de nouvelle application parse pour apprendre à créer une application parse sur back4app remarque suivez le tutoriel d'installation du sdk parse (swift) pour créer un projet xcode connecté à back4app comprendre notre application de recettes la fonctionnalité de l'application est basée sur un formulaire où l'on peut entrer des informations sur une recette en fonction des informations, le type de données peut varier dans notre exemple, la recette a les caractéristiques suivantes champ type de données description nom chaîne nom de la recette portions int nombre de portions disponible bool détermine si la recette est disponible ou non catégorie catégorie une énumération personnalisée qui classe une recette en trois catégories petit déjeuner, déjeuner et dîner ingrédients \[ingrédients] l'ensemble des ingrédients contenus dans une structure customingredient options latérales \[chaîne] noms des options supplémentaires avec lesquelles la recette est fournie informations nutritionnelles \[chaîne\ chaîne] un dictionnaire contenant des informations sur le contenu nutritionnel de la recette date de sortie date une date indiquant quand la recette était disponible de plus, il existe d'autres types de données qui sont utilisés pour implémenter des fonctionnalités de base de données comme la relation entre les objets ces types de données ne sont pas couverts dans ce tutoriel référence rapide des commandes que nous allons utiliser étant donné un objet, disons recette, si vous souhaitez l'enregistrer dans une base de données back4app, vous devez d'abord faire en sorte que cet objet soit conforme au protocole parseswift (disponible via le sdk parseswift) 1 import foundation 2 import parseswift 3 4 struct recipe parseobject { 5 /// enumeration for the recipe category 6 enum category int, caseiterable, codable { 7 case breakfast = 0, lunch = 1, dinner = 2 8 9 var title string { 10 switch self { 11 case breakfast return "breakfast" 12 case lunch return "lunch" 13 case dinner return "dinner" 14 } 15 } 16 } 17 18 19 20 /// a string type property 21 var name string? 22 23 /// an integer type property 24 var servings int? 25 26 /// a double (or float ) type property 27 var price double? 28 29 /// a boolean type property 30 var isavailable bool? 31 32 /// an enumeration type property 33 var category category? 34 35 /// an array of structs 36 var ingredients \[ingredient] 37 38 /// an array of strings 39 var sideoptions \[string] 40 41 /// a dictionary property 42 var nutritionalinfo \[string string] 43 44 /// a date type property 45 var releasedate date? 46 } avant de stocker des instances de cet objet dans une base de données back4app, toutes ses propriétés doivent être conformes aux protocoles codable et hashable nous utilisons les méthodes suivantes pour gérer ces objets sur la base de données back4app create //the procedure for reading and updating a recipe object is similar since they rely on the save() method how a recipe is instantiated determines if we are creating or updating the object on the back4app database when creating a new instance we use 1 var newrecipe recipe 2 3 // setup newrecipe's properties 4 newrecipe name = "my recipe's name" 5 newrecipe servings = 4 6 newrecipe price = 3 99 7 newrecipe isavailable = false 8 newrecipe category = breakfast 9 newrecipe sideoptions = \["juice"] 10 newrecipe releasedate = date() 11 12 13 // saves newrecipe on your back4app database synchronously and returns the new saved item it throws and error if something went wrong 14 let savedrecipe = try? savedrecipe save() 15 16 // saves savedrecipe on your back4app database asynchronously, and passes a result\<todolistitem, parseerror> object to the completion block to handle the save proccess 17 savedrecipe save { result in 18 // handle the result to check the save was successfull or not 19 } update //and to update an existing instance, we have to provide the objectid value which identifies the the object on the back4app database a satandard update can be implemented in the following way 1 let recipetoupdate = recipe(objectid "object id") 2 3 // update the properties you need 4 recipetoupdate name = "my updated recipe's name" 5 recipetoupdate servings = 5 6 recipetoupdate price = 5 99 7 recipetoupdate isavailable = true 8 recipetoupdate category = lunch 9 recipetoupdate sideoptions = \["juice", "coffee"] 10 recipetoupdate releasedate = date() addingtimeinterval(3600 24) 11 12 13 // save changes synchronousty 14 try? recipetoupdate save() 15 16 // or save changes asynchronously 17 recipetoupdate save { result in 18 // handle the result 19 } read //for reading objects stored on your back4app database, recipe now provides the query() static method which returns a query\<recipe> this query object can be constructed using one or more queryconstraint objects in the following way 1 let query = recipe query() // a query to fetch all recipe items on your back4app database 2 let query = recipe query("name" == "omelette") // a query to fetch all recipe items with name "omelette" on your back4app database 3 let query = recipe query(\["name" == "omelette", "price" = 9 99]) // a query to fetch all recipe items with name = "omelette" and price = 9 99 4 5 // fetches the items synchronously or throws an error if found 6 let fetchedrecipes = try? query find() 7 8 // fetches the items asynchronously and calls a completion block passing a result object containing the result of the operation 9 query find { result in 10 // handle the result 11 } delete //any deletion process is performed by calling the method delete() on the object to be deleted 1 var recipetodelete recipe 2 3 // delete recipetodelete synchronously 4 try? recipetodelete delete() 5 6 // delete recipetodelete asynchronously 7 recipetodelete delete { result in 8 // handle the result 9 } 1 créer le modèle d'application recipe nous commençons par créer un nouveau projet xcode dans ce tutoriel, le projet devrait ressembler à ceci à tout moment, vous pouvez accéder au projet complet via nos dépôts github dépôt d'exemple ios allez dans xcode et trouvez le fichier scenedelegate swift afin d'ajouter une barre de navigation en haut de l'application, nous configurons un uinavigationcontroller comme contrôleur de vue racine de la manière suivante 1 class scenedelegate uiresponder, uiwindowscenedelegate { 2 3 var window uiwindow? 4 5 func scene( scene uiscene, willconnectto session uiscenesession, options connectionoptions uiscene connectionoptions) { 6 guard let scene = (scene as? uiwindowscene) else { return } 7 8 window = init(windowscene scene) 9 window? rootviewcontroller = uinavigationcontroller(rootviewcontroller recipescontroller()) 10 window? makekeyandvisible() 11 12 // additional logic 13 } 14 15 16 } la classe du contrôleur de vue racine (recipescontroller) pour le contrôleur de navigation est une sous classe de uiviewcontroller dans laquelle nous allons disposer un formulaire pour créer et mettre à jour des objets recipe dans la base de données back4app 2 configurer l'objet recipe les objets que vous souhaitez enregistrer dans votre base de données back4app doivent se conformer au protocole parseobject dans notre application recipes, cet objet est recipe par conséquent, vous devez d'abord créer cet objet créez un nouveau fichier recipe swift et ajoutez ce qui suit 1 import foundation 2 import parseswift 3 4 struct recipe parseobject { 5 /// enumeration for the recipe category 6 enum category int, caseiterable, codable { 7 case breakfast = 0, lunch = 1, dinner = 2 8 9 var title string { 10 switch self { 11 case breakfast return "breakfast" 12 case lunch return "lunch" 13 case dinner return "dinner" 14 } 15 } 16 } 17 18 // required properties from parseobject protocol 19 var objectid string? 20 var createdat date? 21 var updatedat date? 22 var acl parseacl? 23 24 /// a string type property 25 var name string? 26 27 /// an integer type property 28 var servings int? 29 30 /// a double (or float ) type property 31 var price double? 32 33 /// a boolean type property 34 var isavailable bool? 35 36 /// an enumeration type property 37 var category category? 38 39 /// an array of structs 40 var ingredients \[ingredient] 41 42 /// an array of strings 43 var sideoptions \[string] 44 45 /// a dictionary property 46 var nutritionalinfo \[string string] 47 48 /// a date type property 49 var releasedate date? 50 51 /// maps the nutritionalinfo property into an array of tuples 52 func nutritionalinfoarray() > \[(name string, value string)] { 53 return nutritionalinfo map { ($0 key, $0 value) } 54 } 55 } où nous avons déjà ajouté toutes les propriétés nécessaires à recipe selon le tableau des caractéristiques des recettes le type de données ingredient est une structure contenant la quantité et la description de l'ingrédient comme mentionné précédemment, ce type de données doit se conformer aux protocoles codable et hashable pour faire partie des propriétés de la recette 1 import foundation 2 3 struct ingredient hashable, codable { 4 var quantity float 5 var description string 6 } de plus, la propriété category dans recipe a une énumération (category) comme type de données qui se conforme également aux protocoles correspondants 1 struct recipe parseobject { 2 /// enumeration for the recipe category 3 enum category int, caseiterable, codable { 4 case breakfast = 0, lunch = 1, dinner = 2 5 6 7 } 8 9 } 3 configuration de recipescontroller dans recipescontroller, nous devrions mettre en œuvre toute la configuration nécessaire pour la navigationbar et le formulaire utilisé pour capturer toutes les propriétés de la recette ce tutoriel ne couvre pas comment mettre en œuvre la mise en page du formulaire nous nous concentrons ensuite sur la logique liée à la gestion des types de données en utilisant le sdk parseswift ci dessous, nous soulignons les points clés dans recipescontroller qui nous permettent de comprendre comment nous mettons en œuvre la connexion entre l'interface utilisateur et les données provenant de votre base de données back4app 1 class recipescontroller uiviewcontroller { 2 enum previousnext int { case previous = 0, next = 1 } 3 4 5 6 var recipes \[recipe] = \[] // 1 an array of recipes fetched from your back4app database 7 8 // section header labels 9 private let recipelabel uilabel = titlelabel(title "recipe overview") 10 private let ingredientslabel uilabel = titlelabel(title "ingredients") 11 private let nutritionalinfolabel uilabel = titlelabel(title "nutritional information") 12 13 // 2 a custom view containing input fields to enter the recipe's information (except nutritional info and ingredients) 14 let recipeoverviewview recipeinfoview 15 16 // 3 a stack view containig the fields to enter the recipe's ingredients 17 let ingredientsstackview uistackview 18 19 // 4 a stack view containig the fields to enter the nutritional information 20 let nutritionalinfostackview uistackview 21 22 // 5 buttons to handle the crud logic for the recipe object currently displayed 23 private var savebutton uibutton = uibutton(title "save") 24 private var updatebutton uibutton = uibutton(title "update") 25 private var reloadbutton uibutton = uibutton(title "reload") 26 27 var currentrecipeindex int? // 6 an integer containing the index of the current recipe presenten from the recipes property 28 29 override func viewdidload() { 30 super viewdidload() 31 setupnavigationbar() 32 setupviews() 33 } 34 35 override func viewdidappear( animated bool) { 36 super viewdidappear(animated) 37 handlereloadrecipes() 38 } 39 40 private func setupnavigationbar() { 41 navigationcontroller? navigationbar bartintcolor = primary 42 navigationcontroller? navigationbar titletextattributes = \[ foregroundcolor uicolor white] 43 navigationcontroller? navigationbar istranslucent = false 44 navigationcontroller? navigationbar barstyle = black 45 navigationitem title = "parse data types" uppercased() 46 } 47 48 private func setupviews() { 49 // see the project example for more details 50 51 savebutton addtarget(self, action #selector(handlesaverecipe), for touchupinside) 52 updatebutton addtarget(self, action #selector(handleupdaterecipe), for touchupinside) 53 reloadbutton addtarget(self, action #selector(handlereloadrecipes), for touchupinside) 54 } 55 56 57 } 3 gestion de l'entrée utilisateur et analyse d'un objet recette dans un fichier séparé (appelé recipescontroller+parseswiftlogic swift), en utilisant une extension, nous implémentons maintenant les méthodes handlesaverecipe(), handleupdaterecipe() et handleupdaterecipe() pour gérer les données d'entrée 1 import uikit 2 import parseswift 3 4 extension recipescontroller { 5 /// retrieves all the recipes stored on your back4app database 6 @objc func handlereloadrecipes() { 7 view\ endediting(true) 8 let query = recipe query() 9 query find { \[weak self] result in // retrieves all the recipes stored on your back4app database and refreshes the ui acordingly 10 guard let self = self else { return } 11 switch result { 12 case success(let recipes) 13 self recipes = recipes 14 self currentrecipeindex = recipes isempty ? nil 0 15 self setuprecipenavigation() 16 17 dispatchqueue main async { self presentcurrentrecipe() } 18 case failure(let error) 19 dispatchqueue main async { self showalert(title "error", message error message) } 20 } 21 } 22 } 23 24 /// called when the user wants to update the information of the currently displayed recipe 25 @objc func handleupdaterecipe() { 26 view\ endediting(true) 27 guard let recipe = preparerecipemetadata(), recipe objectid != nil else { // prepares the recipe object for updating 28 return showalert(title "error", message "recipe not found ") 29 } 30 31 recipe save { \[weak self] result in 32 switch result { 33 case success(let newrecipe) 34 self? recipes append(newrecipe) 35 self? showalert(title "success", message "recipe saved on your back4app database! (objectid \\(newrecipe id)") 36 case failure(let error) 37 self? showalert(title "error", message "failedto save recipe \\(error message)") 38 } 39 } 40 } 41 42 /// saves the currently displayed recipe on your back4app database 43 @objc func handlesaverecipe() { 44 view\ endediting(true) 45 guard var recipe = preparerecipemetadata() else { // prepares the recipe object for storing 46 return showalert(title "error", message "failed to retrieve all the recipe fields ") 47 } 48 49 recipe objectid = nil // when saving a recipe object, we ensure it will be a new instance of it 50 recipe save { \[weak self] result in 51 switch result { 52 case success(let newrecipe) 53 if let index = self? currentrecipeindex { self? recipes\[index] = newrecipe } 54 self? showalert(title "success", message "recipe saved on your back4app database! (objectid \\(newrecipe id))") 55 case failure(let error) 56 self? showalert(title "error", message "failed to save recipe \\(error message)") 57 } 58 } 59 } 60 61 /// when called it refreshes the ui according to the content of recipes and currentrecipeindex properties 62 private func presentcurrentrecipe() { 63 64 } 65 66 /// adds the 'next recipe' and 'previous recipe' button on the navigation bar these are used to iterate over all the recipes retreived from your back4app database 67 private func setuprecipenavigation() { 68 69 } 70 71 /// reads the information the user entered via the form and returns it as a recipe object 72 private func preparerecipemetadata() > recipe? { 73 let ingredientscount = ingredientsstackview\ arrangedsubviews count 74 let nutritionalinfocount = nutritionalinfostackview\ arrangedsubviews count 75 76 let ingredients \[ingredient] = (0 \<ingredientscount) compactmap { row in 77 guard let textfields = ingredientsstackview\ arrangedsubviews\[row] as? doubletextfield, 78 let quantitystring = textfields primarytext, 79 let quantity = float(quantitystring), 80 let description = textfields secondarytext 81 else { 82 return nil 83 } 84 return ingredient(quantity quantity, description description) 85 } 86 87 var nutritionalinfo \[string string] = \[ ] 88 89 (0 \<nutritionalinfocount) foreach { row in 90 guard let textfields = nutritionalinfostackview\ arrangedsubviews\[row] as? doubletextfield, 91 let content = textfields primarytext, !content isempty, 92 let value = textfields secondarytext, !value isempty 93 else { 94 return 95 } 96 nutritionalinfo\[content] = value 97 } 98 99 let recipeinfo = recipeoverviewview\ parseinputtorecipe() // reads all the remaining fields from the form (name, category, price, serving, etc) and returns them as a tuple 100 101 // we collect all the information the user entered and create an instance of recipe 102 // the recipeinfo objectid will be nil if the currently displayed information does not correspond to a recipe already saved on your back4app database 103 let newrecipe recipe = recipe( 104 objectid recipeinfo objectid, 105 name recipeinfo name, 106 servings recipeinfo servings, 107 price recipeinfo price, 108 isavailable recipeinfo isavailable, 109 category recipeinfo category, 110 ingredients ingredients, 111 sideoptions recipeinfo sideoptions, 112 nutritionalinfo nutritionalinfo, 113 releasedate recipeinfo releasedate 114 ) 115 116 return newrecipe 117 } 118 119 /// called when the user presses the 'previous recipe' or 'next recipe' button 120 @objc private func handleswitchrecipe(button uibarbuttonitem) { 121 122 } 123 } 4 exécutez l'application ! avant d'appuyer sur le bouton exécuter dans xcode, n'oubliez pas de configurer votre application back4app dans la classe appdelegate ! la première fois que vous exécutez le projet, vous devriez voir quelque chose comme ça dans le simulateur (avec tous les champs vides) maintenant, vous pouvez commencer à entrer une recette pour ensuite l'enregistrer dans votre base de données back4app une fois que vous avez enregistré une recette, allez sur votre tableau de bord back4app https //parse dashboard back4app com/apps et allez dans votre application, dans la section base de données, vous trouverez la classe recette où toutes les recettes créées par l'application ios en particulier, il convient de noter comment des types de données non fondamentaux comme ingrédient, recette catégorie ou les dictionnaires sont stockés si vous naviguez à travers les données enregistrées sous la classe recette, vous constaterez que le dictionnaire nutritionalinformation est stocké en tant qu'objet json le tableau \[ingrédients] est stocké en tant que tableau d'objets json l'énumération recette catégorie, puisqu'elle a un type de données entier comme rawvalue, est transformée en un type de valeur numérique la propriété releasedate, une valeur de type date en swift , est également stockée en tant que valeur de type date pour conclure, lors de la récupération des données de votre base de données back4app, vous n'avez pas besoin de décoder tous ces champs manuellement, le sdk parseswift les décode automatiquement cela signifie que, lors de la création d'une requête (query\<recette> dans ce cas) pour récupérer des données, la méthode query find() analysera tous les types de données et objets json pour renvoyer un tableau de recettes, il n'y a pas de procédure d'analyse supplémentaire à mettre en œuvre