Nous allons créer un jeu d'anagrammes dans lequel il est demandé à l'utilisateur de faire des mots à partir d'un mot plus grand. Nous allons dresser une liste des mots de départ possibles pour le jeu et cette liste sera stockée dans un fichier séparé. Mais comment pouvons-nous obtenir le texte à partir d'un fichier dans l'application ? Eh bien, il s’avère que le type de données String
de Swift est très facile à utiliser - merci Apple !
Si vous n'avez pas encore téléchargé les ressources de ce projet à partir de GitHub (https://github.com/twostraws/HackingWithSwift), il est temps de le faire à présent. Dans le dossier project5-files, vous trouverez le fichier start.txt. Faites-le glisser dans votre projet Xcode, en vous assurant que l'option "Copy items if needed" (Copier les éléments si nécessaire) est cochée.
Le fichier start.txt contient plus de 12 000 mots de huit lettres, un par ligne, que nous pouvons utiliser pour notre jeu. Nous devons transformer cela en un tableau (array) de mots avec lesquels nous pouvons jouer. En coulisse, les sauts de ligne sont marqués par un caractère spécial de saut de ligne qui est généralement exprimé par \n
. Nous devons donc charger cette liste de mots dans une chaîne de caractères, puis la scinder chaque fois que nous voyons \n
pour stocker chaque mot dans le tableau .
Tout d’abord, allez au début de votre classe et créez deux nouveaux tableaux. Nous allons utiliser le premier pour contenir tous les mots du fichier et le second pour contenir tous les mots que le joueur a utilisés dans le jeu.
Donc ouvrez ViewController.swift et ajoutez ces deux propriétés :
var allWords = [String]()
var usedWords = [String]()
Ensuite, chargez le contenu du fichier dans notre tableau. Cela se fait en trois parties : trouver l'emplacement de notre fichier start.txt, charger le contenu de ce fichier, puis le scinder en un tableau.
Trouver l'emplacement d'un fichier est quelque chose que vous ferez fréquemment, car même si vous savez que le fichier s'appelle "start.txt", vous ne savez pas où il se trouve dans le système de fichiers. Nous utilisons donc une méthode intégrée de Bundle
pour le trouver : path(forResource:)
. Celle-ci prend comme paramètres le nom du fichier et son extension, et retourne une chaîne de caractères optionnelle String?
- c’est-à-dire que vous récupérez le chemin ou vous obtenez "nil" si le fichier n’existe pas.
Vous devez également vous familiariser avec le chargement du contenu d'un fichier dans une chaîne de caractères. Encore une fois, il existe un moyen simple de le faire : lorsque vous créez une instance de type String
, vous pouvez lui demander de se créer à partir du contenu d'un fichier stocké à un emplacement particulier.
Enfin, nous devons diviser notre chaîne de caractères unique chaque fois que nous trouvons un saut de ligne (\n
) en un tableau de chaînes de caractères. C’est également simple et consiste à un autre appel de méthode sur String
: components(separatedBy:)
. Indiquez-lui la chaîne que vous souhaitez utiliser comme séparateur (pour nous, il s'agit de \n
) et vous récupérerez un tableau.
Avant d’entrer dans le code, vous devez savoir deux choses : path(forResource:)
et la création d’une chaîne de caractères String
à partir du contenu d’un fichier renvoient dans les deux cas une chaîne de caractères optionnelle String?
, ce qui signifie que nous devons vérifier et déballer l'optionnel en utilisant la syntaxe if let
.
OK, c'est l'heure de coder. Mettez ceci dans viewDidLoad()
, juste après la ligne contenant super
:
if let startWordsPath = Bundle.main.path(forResource: "start", ofType: "txt") {
if let startWords = try? String(contentsOfFile: startWordsPath) {
allWords = startWords.components(separatedBy: "\n")
}
} else {
allWords = ["silkworm"]
}
Si vous regardez bien, il y a un nouveau mot-clé : try?
. Vous avez déjà vu try!
auparavant, et nous pourrions en fait l'utiliser ici aussi car nous chargeons un fichier à partir du paquet de notre application, et si on n'y arrivait pas, ça serait catastrophique. Cependant, de cette façon, j'ai l'occasion de vous apprendre quelque chose de nouveau : try?
signifie "appele ce code, et s'il génère une erreur, retourne "nil" à la place." Cela signifie que le code que vous appelez fonctionnera toujours, mais que vous devez déballer le résultat avec soin.
Comme vous pouvez le constater, ce code vérifie et déballe prudemment le contenu de notre fichier de démarrage, puis le convertit en tableau. Une fois terminé, allWords
contiendra plus de 12 000 chaînes de caractères prêtes à être utilisées dans notre jeu.
Pour prouver que tout fonctionne avant de continuer, créons une nouvelle méthode appelée startGame()
. Celle-ci sera appelée chaque fois que nous voulons générer un nouveau mot pour le joueur, et elle utilisera la méthode randomElement()
des tableaux (arrays) de Swift pour choisir un élément au hasard parmi toutes les chaînes de caractères.
Voici le code :
func startGame() {
title = allWords.randomElement()
usedWords.removeAll(keepingCapacity: true)
tableView.reloadData()
}
La ligne 1 définit le titre de notre contrôleur de vue comme étant un mot pris au hasard dans le tableau, qui sera le mot à partir duquel le joueur doit trouver des anagrammes.
La ligne 2 supprime toutes les valeurs du tableau usedWords
, que nous utiliserons pour stocker les réponses du joueur plus tard. Nous n'y avons rien ajouté pour le moment, donc removeAll()
ne fait rien pour l'instant.
La ligne 3 est la partie intéressante : elle appelle la méthode reloadData()
de tableView
. Ce tableau nous est donné en tant que propriété parce que notre classe ViewController
provient de UITableViewController
. Notre tableau ne contient pas encore de lignes, donc cela ne fera rien pour quelques instants encore. Cependant, la méthode est prête à être utilisée et nous permet de vérifier que toutes les données ont été chargées correctement. Ajoutez donc ceci juste avant la fin de viewDidLoad()
:
startGame()
Appuyez maintenant sur Cmd + R pour exécuter l'application, et vous devriez voir un mot de huit lettres en haut, prêt pour commencer à jouer.
Ce n'est pas terminé, nous devons ajouter quelques méthodes pour gérer les données du tableau dans l'interface utilisateur : numberOfRowsInSection
et cellForRowAt
. Celles-ci sont identiques aux implémentations du projet 1, à la différence près que nous nous basons maintenant sur le tableau usedWords
et que l’identifiant de la cellule est "Word". Ajoutez ces deux méthodes :
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return usedWords.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Word", for: indexPath)
cell.textLabel?.text = usedWords[indexPath.row]
return cell
}
Elles n’ont pas encore d’effet car le tableau usedWords
ne change jamais, mais au moins la base est maintenant en place.
SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.
Link copied to your pasteboard.