Exercice : compter le nombre de caractères dans un String

exercice : il s’agit de créer une fonction appelée validatePassword() et qui retourne un Bool si un paramètre String contient entre 8 et 15 caractères.
Le programme doit retourner un message indiquant à l’utilisateur si le mot de passe est valide ou non.
»

Extrait de: Apple Education. « Introduction au développement d’apps avec Swift Guide d’enseignement. » Apple Inc. - Education, 2017. iBooks. https://itun.es/fr/vLrBib.l

J’ai le code suivant mais j’ai une erreur ‘expected declaration’ au moment où je voudrais lancer ma fonction,

sur la ligne validatePassword(motDePasse)

Mon code :

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

var motDePasse:String = "sdfgsfqdsf"

validatePassword(motDePasse)

}

func validatePassword(motDePasse: String) -> Bool {
    let nombreDeCaracteres = motDePasse.characters.count
    if nombreDeCaracteres >= 8 && nombreDeCaracteres <= 15 {
        print("Mot de passe 'valide'")
        return true
    }
print("mot de Passe 'invalide'")

return false

}

Salut Fanfan,

Je suis débutant également, mais en lisant le code il me semble que ton problème est que tu essaies d’appeler ta fonction validatePassword dans ta class alors que tu l’as définis en dehors de celle-ci.

Storyboard permet de taper du code un peu n’importe comment. Ce n’est pas le cas de la « vraie programmation » où le code doit être défini dans le corps de fonctions précises, appelées par le système pour des raisons particulières.

Xcode ne comprend pas ton code, parce qu’il n’est pas dans le corps d’une fonction.

viewDidLoad() est une fonction d’initialisation appelée automatiquement par un viewController juste après son chargement en mémoire. C’est là que je met généralement le code de mes minis-tutos.

Voici une version corrigée de ton exercice :

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let passe = "sdsf"
        if validatePasseword(motDePasse: passe) {
            print ("Mot de passe valide")
        } else {
            print ("Mot de passe invalide. Veillez vous rendre en salle de désintégration")
        }
        
    // Fin viewDidLoad()
    }

// Fin du viewController        
}


func validatePasseword(motDePasse:String) -> Bool {
    let size = motDePasse.characters.count
    if size>=8 && size<=15 {
        return true
    }
    return false
}

Si tu avais tapé ton code dans le corps de viewDidLoad et non après la parenthèse finissant celui-ci, cela aurait (presque) fonctionné.

Presque parce que le compilateur t’aurais craché à la figure que :

1/ motDePasse n’étant pas modifiée dans le corps du programme c’est une CONSTANTE (let) et non une VARIABLE (var).

2/ validatePasseword() étant définie comme une fonction retournant une valeur BOOL, le paramètre de retour doit forcément être géré par le programme.

1 J'aime

Merci Astro et Draken pour vos retours et explications…

Encore une question ; pourquoi écrire :

let passe = "sdsf"
if validatePasseword(motDePasse: passe)

et pas directement en mettant passe dans la fonction à la place de motDePasse

let passe = "sdsf"
if validatePasseword(passe)

A cause de la syntaxe de la fonction validatePassword() que tu as donné dans ton premier post.

func validatePasseword(motDePasse: String) -> Bool {
 ...
}

Avec cette syntaxe Xcode EXIGE TOUJOURS le nom du paramètre.

let passe = "sdsf"
if validatePasseword(motDePasse: passe)

Pour s’en passer, il faut ajouter _ devant le nom du paramètre.

func validatePasseword(_ motDePasse: String) -> Bool {
     ...
 }

Là ça marche sans le nom :

let passe = "sdsf"
if validatePasseword(passe)

A toi de voir quelle syntaxe utiliser. Moi je préfère la notation sans nom pour les fonctions avec un paramètre unique.

Il est évident que le seul paramètre de validatePasseword() est un passeword. Avec deux ou trois paramètres la signification est moins évidente, d’où la nécessité des noms.

1 J'aime

1- Je ne suis pas sur de bien suivre : motDepasse et passe, ce sont bien des variables ? En mettent le underscore, j’ai passe en dehors de la fonction et motDePasse à l’intérieur. Pourquoi pas uniquement passe, qui est celui qu’on utilise dès le départ pour saisir la proposition de l’utilisateur ?

2- Pourquoi interpréter la condition et rendre les print en dehors de la fonction et non pas à l’intérieur ?
On aurait :
a- l’utilisateur entre un mot de passe
b- on lance la fonction qui vérifie si celui-ci entre bien dans la fourchette demandée et restitue une réponse

Oui et … non ! Reprenons au début. Je crois que tu as un problème avec la notion de variable locale. Ce n’est pas évident au début. Il faut une démarche d’esprit un peu particulière se développant avec l’expérience.

Quand la fonction validatePassword() est appelée avec une variable, on lui ne transmet pas cette variable, mais une copie de son contenu. C’est l’information qui est transmise et non la variable elle-même. La variable motDePasse n’existe qu’à l’intérieur de validatePassword(). Son existence est purement locale.

Son contenu est identique à celui de la variable passe, mais ce sont deux entités différentes.

validePassword() est une boîte noire, un mini-mécanisme logiciel indépendant ne connaissant pas la structure du programme qui l’utilise, ni la manière dont il stocke ces informations. Elle sais « juste » recevoir une information, faire un traitement dessus et retourner le résultat.

On pourrais modifier la validation du passeword, de manière à ce qu’il se fasse avec une variable globale, sans lui passer de paramètres. Mais ce serait une très mauvaise idée, car on perdrait le coté générique de la vérification. Toute l’information moderne repose sur la création de petites boîtes noires indépendantes, dont on ne connait que les paramètres d’entrés et de sortie.

1 J'aime

Parce qu’on doit toujours séparer les routines « systèmes » des interactions utilisateurs. Ce sont des choses très différentes. Imagine une version plus évoluée de ton petit programme, tournant avec une interface graphique (un label pour afficher le résultat du test, et un composant graphique pour afficher le clavier virtuel et saisir la frappe de l’utilisateur).

Tu peux le faire en reprenant la même fonction validatePasseword(), sans rien modifier. Il suffit « juste » d’utiliser Storyboard pour ajouter les composants graphique et de taper du code pour le nouvel affichage.

Si tu avais écrit une fonction « hybride » mélangeant les calculs et l’affichage, il aurais fallu TOUT refaire, au risque d’introduire des bugs dans les nouveaux calculs.

En avançant dans les cours, tu découvrira le paradigme MVC. C’est une manière de coder qui fait que l’affichage des informations est TOTALEMENT indépendant de la manière de les calculer. Tout le système d’interface graphique d’iOS est basé sur ce concept.

2- Pourquoi interpréter la condition et rendre les print en dehors de la fonction et non pas à l’intérieur ?

Et aussi parce que c’est demandé dans l’énoncé de l’exercice !

exercice : il s’agit de créer une fonction appelée validatePassword() et qui retourne un Bool si un paramètre String contient entre 8 et 15 caractères.
Le programme doit retourner un message indiquant à l’utilisateur si le mot de passe est valide ou non.

D’ailleurs, tu peux aussi créer une autre fonction retournant le texte à afficher en fonction de la valeur du test.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let passe = "sdsf"
        let test = validatePasseword(motDePasse: passe)
        let texte = texteReponse(flag: test)
        print ("Réponse : ", texte)
    }
    
}

func texteReponse(flag:Bool) -> String {
    if flag {
        return "Mot de passe valide"
    } else {
        return "mot de passe invalide"
    }
}

func validatePasseword(motDePasse:String) -> Bool {
    let size = motDePasse.characters.count
    if size>=8 && size<=15 {
        return true
    }
    return false
}

La recherche du texte est « encapsulée » dans une fonction, ce qui la rend indépendante du programme principal. Cela n’est pas très utile ici, mais imagine que l’application doive aussi fonctionner en anglais et en allemand. C’est plus d’internationaliser le code si le texte est défini dans une routine spécifique. On peut imaginer un autre paramètre de texteReponse() : langueAffichage spécifiant si le texte doit être en français, anglais ou allemand.

En isolant chaque fonctionnalité de l’application dans une logique modulaire, on facilite les futurs modifications du code. Et des améliorations il y en TOUJOURS à faire (nouvelles fonctions, nouvel algorithme, changement d’interface, etc…).

EDIT : Les novices cherchent toujours à écrire un code optimisé le plus court possible, au lieu de penser création de « briques logicielle » réutilisables et autonomes. Cela vient avec l’expérience. En blabla tech on appelle cela « l’encapsulation ».

Tu verras plus tard que cela facilite grandement le débugage de programmer avec des « briques de légo », plutôt qu’un code spaghettis faisant tout et n’importe quoi.

1 J'aime

Quel plaisir d’avoir des réponses si détaillées. Merci à toi

1 J'aime

Je suis un grand bavard, par nature …

1 J'aime