Projet: Post'TIM – version Swift

Passage de données, par l’utilisation d’un protocole

 

Contenu

Post'TIM

Pré-requis:

 
 


 
Vidéo du résultat final:

 


Description du projet

Dans ce tutoriel, nous verrons comment construire une application qui permet la gestion d’une liste de tâches à réaliser – présentées dans un ‘UITableView’ – , sous forme de mémos éditables.
Les ‘tâches’ seront lues et enregistrées dans un fichier de propriétés, ce qui assurera leur pérennité entre les chargements de l’application.
L’application proposera une liste de tâches à partir de laquelle il sera possible:

 


Objectif principal

Savoir utiliser un ‘protocole’ sous Swift pour les passages de données entre les classes des scènes.
Explication:
Nous allons programmer un protocole, dans la classe de la scène ‘ajouter/modifier’, qui va permettre à l’abonné, de recevoir les messages ‘ajouterTache’ et ‘modifierTache’  avec en paramètre, des données en provenance de la classe proposant le protocole.
 

Objectifs secondaires


1 – Le projet de départ

 
Action 1 – Ouvrons le projet de départ et testons l’app: Post’TIM version swift 6.01 – depart

Remarquons que les modifications, ainsi que l’ajout d’une nouvelle tâche, ne sont pas enregistrés.
 

Astuce: Pour tester une scène du storyboard, non accessible par navigation, renseigner sa propriété ‘is initial View Controller‘.

 
Action 1.01 – Analysons le schéma de départ:
Post-TIM_-_projet_de_depart-schema1.swift
 


1.1 – Animation de propriétés

La classe UIView propose la méthode de classe animateWithDuration().  Cette méthode permet d’animer plusieurs des propriétés des classes dérivées de UIView.  Par exemple, unUILabel.alpha, unUIImageView.center.y, …
La méthode  animateWithDuration() utilise la technique des blocs pour soumettre, à un fil d’exécution (thread),  les instructions d’animation.
Voici sa signature:

UIView.animateWithDuration(
_ duration: NSTimeInterval,
// delay: NSTimeInterval,
// options: UIViewAnimationOptions,
animations: () -> Void,
completion: ((Bool) -> Void)?
)

Voici un exemple d’utilisation:

logo.alpha = 0
UIView.animateWithDuration(
   2.0,
   animations: {
                  self.logo.alpha = 1 // il faut utiliser 'self.' dans un bloc
               }, // animations:
   completion: { terminee in  // la signature de completion indique un paramètre de type Bool
                  println("L'animation de logo.alpha est terminée")
               } // completion:
) // UIView.animateWithDuration

 

Nous allons animer plusieurs éléments de la scène Intro.

Action 1.1.1 – Ajoutons le code suivant, à la méthode viewDidLoad de la classe Intro:

        titre1.alpha = 0;
        titre2.alpha = 0;
        logo.alpha   = 0;
        logo.center.y = view.bounds.height      // Placer le centre du logo au bas de l'écran.
        // logo.center.y = view.frame.height    // Placer le centre du logo au bas de la view.
        // Rappel: Il faut toujours préciser le contexte des instances, dans un bloc. Par exemple, 'self.titre1'.
        UIView.animateWithDuration(1,
            delay: 0,
            options: UIViewAnimationOptions.CurveEaseIn,
            animations: {
                            self.titre1.alpha   = 1
                        },
            completion: { terminee in
                            UIView.animateWithDuration( 2.0,
                                                        animations: {
                                                                        self.titre2.alpha = 1
                                                                        self.logo.alpha   = 1
                                                                        self.logo.center.y = self.titre2.center.y + self.titre2.frame.height
                                                                    }, // animations:
                                                        completion: { terminee in
                                                                         println("Animation de logo.alpha terminée")
                                                                     } // completion:
                            ) // UIView.animateWithDuration
                        } // completion:
        ) // UIView.animateWithDuration

Note: Il faut mettre en commentaire: self.performSegueWithIdentifier(« versTaches », sender: self) situé dans la méthode virewDidLoad()

 
Aide mémoire:  
Dans un bloc de code,  il faut toujours préciser le contexte des méthodes et des propriétés.
Par exemple,
self.titre1
self.uneMéthode()

 


1.1.2 – Utilisation de GCD pour soumettre un bloc de code

 
Grand Central Dispatch (GCD) permet la gestion des fils d’exécution (threads).
 
Nous avons vu, dans d’autres projets,  comment programmer l’exécution d’une fonction suite à un délai.
Par exemple,
passer de la scène d’introduction à la scène principale d’un projet.
Ceci était réalisé grâce à la classe NSTimer.
 
Il est possible d’obtenir le même résultat en utilisant les fonctions de Grand Central Dispatch (GCD).
 
Autre référence: RW
 
Action 1.1.2 – Ajoutons le code suivant, permettant de lancer un segue après un délai,  à la méthode viewDidLoad de la classe Intro:

        // Utilisation de GrandCentralDispatch (GCD) pour placer en attente un 'performSegueWithIdentifier'
        // Référence: http://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1
        let delaiEnSecondes:UInt64 = 2
        let delaiEnNanoSecondes = Int64(delaiEnSecondes * NSEC_PER_SEC)  // nanoSec = 10e-9 sec
        let deltaTemps = dispatch_time(DISPATCH_TIME_NOW, delaiEnNanoSecondes)
        dispatch_after(deltaTemps, dispatch_get_main_queue(),
            {
                self.performSegueWithIdentifier("versTaches", sender: self)
            }
        ) // dispatch_after

Action 1.1.3 – Testons l’application
 


1.2 – Activer la suppression des UITableViewCell sur ‘swap’.

 
Le protocole UITableViewDataSource propose la méthode ‘commitEditingStyle‘.
Cette dernière permet, en autres choses,  d’activer la suppression d’une cellule sur glissement horizontal.
Il suffit d’ajouter la méthode ‘commitEditingStyle‘ pour qu’un glissement, sur une UITableViewCell, propose des opérations sur la cellule.
 
Action 1.2 – Ajoutons la méthode suivante à la classe ‘VCNotes

    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
         if (editingStyle == UITableViewCellEditingStyle.Delete) {
            // Effacer, de tableauDesTaches,
            // l'élément correspondant à la cellule courante
            tableauDesTaches.removeObjectAtIndex(indexPath.row)
            // Enregistrer le tableau dans le fichier.plist
            updatePlist()
            // Actualiser le UITableView
            tableView.reloadData()
        } // FIN -> editingStyle == delete
    } // ### FIN -> commitEditingStyle

Action 1.2b – Testons le glissement (swap) sur une des cellules du UITableView:
 
PostTIM-delete
 
 


1.3 – Utiliser un ‘NSDateFormatter’ pour afficher une date en heure locale…

 
Si nous exécutons l’application, nous allons remarquer que l’heure affichée des tâches ne correspond pas aux données du fichier ‘listeDesTaches.plist’.  Celà s’explique par le fait qu’une date est localisée au fuseau horaire ‘UCT’ lors de sa conversion vers un NSString.
 
POSTTIM-date-UCT
Note: Utiliser le code suivant pour afficher la date:

cell.date.text = (tableauDesTaches[indexPath.row][« date »]! as NSDate).description

 
L’utilisation de la classe ‘NSDataFormatter‘ va permettre d’utiliser le fuseau horaire de l’appareil lors de la conversion.  De plus, il sera possible de programmer les éléments de date à afficher.  Par exemple, le nom du jour (lundi) + le numéro du mois + HH:MM, …
Voir le site suivant pour les commandes de formatage d’une date.
 
Action 1.3 –  Ajoutons le code suivant à la méthode ‘cellForRowAtIndexPath‘ de la classe ‘VCNotes

        let uneDate = tableauDesTaches[indexPath.row]["date"]! as NSDate  // 1 - Obtenir la date de la tâche courante
        let unFormateurDeDate = NSDateFormatter()                         // 2 - Créer un formateur de date
        unFormateurDeDate.dateFormat = "yyyy.MM.dd HH:mm"                 // 3 - Préciser le format de date désiré
        let dateMiseEnForme = unFormateurDeDate.stringFromDate(uneDate)   // 4 - Obtenir, en chaine de caractères, la date formatée
        cell.date.text = dateMiseEnForme;                                 // 5 - Afficher dans la cellule courante

 
Action 1.3b – Testons l’application et observons maintenant le format des dates.
POSTTIM-date-locale
 


1.4 – Déterminer quelle est la cellule qui a déclenchée le ‘segue’

Note: voir 1.5 en premier.
Il y a deux ‘UIButton‘s dans le modèle de la cellule personnalisée du projet.
Un déplacement ‘segue’ pourra donc être déclenché par le bouton ‘ajouter‘ ou le bouton ‘consulter‘.
Dans les deux cas,  il y aura exécution de la méthode ‘prepareForSegue‘ et le bouton sélectionné sera passé en paramètre.
Nous ne recevrons pas la cellule où est survenu l’événement.  Il ne sera donc pas possible d’interroger le UITableView sur la position de la cellule reçue.
Il est par contre possible d’obtenir la position d’une cellule en fonction du point d’encrage (origin) d’un des objets présent dans le UITableView.
Note: Par default, le point d’encrage d’un objet se trouve au centre de l’objet.
 
Action 1.4 – Ajoutons le code suivant à la méthode ‘prepareForSegue‘ de la classe ‘VCNotes‘.

        let button = sender as UIButton
        let buttonFrame = button.convertRect(button.bounds, toView:self.tableView)
        let indexPath   = self.tableView.indexPathForRowAtPoint(buttonFrame.origin)

 


1.5  – Déterminer la destination du ‘segue’

 
La scène Notes possède trois liens de type ‘segue’.
Il n’y a qu’une seule méthode ‘prepareForSegue‘ par classe de scène.
Par contre, en vérifiant le paramètre ‘segue.identifier‘, il sera possible de déterminer la destination.
Voici un exemple:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject
     if segue.identifier == "modifier" {
         // Pointer sur l'instance la scène de destination
         // Passer les données à la scène de destination
         println("Segue vers 'modifier' avec le détail de l'indice 'n' du tableau")
     } // versAjouter
     if segue.identifier == "detail" {
         // Pointer sur l'instance la scène de destination
         // Passer les données à la scène de destination
         println("Segue vers 'detail' avec le détail de l'indice 'n' du tableau")
     } // VersDetail
        ...
} // prepareForSegue

Note: Tester cet exemple en laboratoire avec le contenu de 1.4.
 
Action 1.5 – Ajoutons le code suivant à la méthode ‘prepareForSegue‘ de la classe ‘VCNotes‘:

        // Tester si 'segue' est = 'ajouter'
        if segue.identifier == "ajouter" {
            let vers = segue.destinationViewController as VCAjouterTache
            // *********************************************************************************
            // À observer
            // TODO: - Action 3.4b - Segue Ajouter: Renseigner le délégué
            // ---------------------------------------------------------------------------------
            /// vers.delegate = self;
            // ---------------------------------------------------------------------------------
            vers.modeAjouter = true;
            NSLog("Transition vers %@", segue.identifier);
        } // segue.identifier == "ajouter"
        // Tester si 'segue' est = 'modifier'
        if segue.identifier == "modifier"{
            let vers = segue.destinationViewController as VCAjouterTache
            // *********************************************************************************
            // À observer
            // TODO: Action 3.5b - Segue modifier: Renseigner le délégué
            // ---------------------------------------------------------------------------------
            ///  vers.delegate = self;
            // ---------------------------------------------------------------------------------
            vers.modeAjouter = false
            vers.detailTache = Tache(detail: tableauDesTaches[indexPath!.row] as NSDictionary)
            // sauvegarder la sélection courante pour le retour de modifierTache
            indiceTacheCourante = indexPath!.row;
            NSLog("Transition vers %@ avec indice: %d", segue.identifier, indexPath!.row);
        }  // segue.identifier == "modifier"
        // Tester si 'segue' est = 'detail'
        if segue.identifier == "detail"{
            let vers = segue.destinationViewController as VCDetail
            vers.detailTache = Tache(detail: tableauDesTaches[indexPath!.row] as NSDictionary)
            NSLog("Transition vers %@ avec indice: %d", segue.identifier, indexPath!.row);
        } // segue.identifier == "detail"

 
Action 1.5bFaire les TODO: des fichiers VCDetail et VCAjouterTache.  
Action 1.5b – Testons l’application

 


2  – Mise en place du protocole tacheDelegate

Note:  Pour une explication détaillée de la mise en place d’un protocole, voir le laboratoire Aquarium.
Dans le projet de départ, la classe VCAjouterTache propose déjà le protocole ‘tacheDelegate‘ avec les méthodes ‘ajouterTache‘ et ‘modifierTache‘.
Nous utiliserons ce protocole pour retourner les données modifiées vers la classe de la scène Notes.

Rappel des étapes de mise en place d’un protocole:

 

2.1a et 2.1b – Déclaration du protocole ‘tacheDelegate’

Action 2.1 – Observons le code suivant du fichier  ‘VCAjouterTache’.

/// 2.1a - Déclaration du protocole
protocol tacheDelegate {
    /**
        Retourne, au délégué du protocole tacheDelegate, la tâche à ajouter.
        :param: instance de la classe Tache
    */
    func ajouterTache(detailInfo:Tache)
    /**
        Retourne, au délégué du protocole tacheDelegate, la tâche modifiée.
        :param: instance de la classe Tache
    */
    func modifierTache(detailInfo:Tache)
} // protocol tacheDelegate
    /// 2.1b - Propriété pour le delégué du protocole tacheDelegate.
    var delegate:tacheDelegate?

 

2.2 – Programmer l’appel des méthodes du protocole (gestion)

L’appel d’une méthode d’un protocole, implémentée dans la classe du délégué,  se fait en utilisant la syntaxe suivante: delegate?uneMéthodeDuProtocole().
uneMéthodeDuProtocole() sera exécutée que si ‘delegate‘ n’est pas nil.
 
Action 2.2 – Observons le code suivant du fichier  ‘VCAjouterTache’.

        // Si en modeAjouter
        if modeAjouter {
            delegate?.ajouterTache(info)
        }  // modeAjouter
        else // alors c'est 'modeModifier'
        {
            self.delegate?.modifierTache(info)
        }  // modeModifier

Le protocole de la classe ‘VCAjouterTache’ est maintenant en place.  Par contre, s’il n’y a pas de délégué, les méthodes du protocole ne seront pas exécutées.
 


3.3 – Souscrire (abonnement) au protocole tacheDelegate

Note: La numérotation passe à 3.x car les étapes suivantes sont réalisées dans la classe ‘VCNotes’.
Action 3.3– Observons le code suivant de la classe ‘VCNotes

class VCNotes: UIViewController, UITableViewDataSource, tacheDelegate {
  ...

Note: Il faut enlever le commentaire /* tacheDelegate */ dans le code source. Cela provoquera l’erreur ‘VCNotes’ non conforme au protocole ‘tacheDelegate’.
À partir de cette étape, il faut maintenant programmer les méthodes  ‘ajouterTache’ et ‘modifierTache’ du protocole ‘tacheDelegate’ dans la classe ‘Notes’.
 

3.4a – Programmation de la méthode ‘ajouterTache’


Action 3.4a 
– Ajoutons le code suivant au fichier ‘VCNotes.m’

    func ajouterTache(info:Tache){
        NSLog("ajouterTache, info = %@", info.tache);
        // Ajouter au tableauTaches les données reçues.
        tableauDesTaches.addObject(info.tacheToDictionary())
        NSLog("tableauDesTaches ajouterTache = %@", info.tacheToDictionary());
        // Actualiser le UITableView
        self.tableView.reloadData()
        // Enregistrer le tableau dans le fichier.plist
        updatePlist()
    } // ### FIN -> ajouterTache

3.4b – Renseigner la propriété ‘delegate’ pour la destination ‘ajouter’.


Action 3.4b 
– Observons  le code suivant du fichier ‘VCNotes.m’

vers.delegate = self;

 

3.5a – Programmation de la méthode ‘modifierTache’


Action 3.5a 
– Ajoutons le code suivant au fichier ‘VCNotes.m’

   func modifierTache(info:Tache) {
        NSLog("retour de la méthode 'modifier', info = %@", info.tache);
        // Remplacer l'élément courant du tableauTaches par les données reçues.
        tableauDesTaches[indiceTacheCourante] = info.tacheToDictionary()
        NSLog("tableauDesTaches élément %d modifié = %@", indiceTacheCourante, tableauDesTaches);
        // Actualiser le UITableView
        tableView.reloadData()
        // Enregistrer tableauTaches dans le fichier 'listeDesTaches.plist'
        updatePlist()
    } // ### FIN -> modifierTache

 

Étape 3.5b – Renseigner la propriété ‘delegate’ pour la destination ‘modifier’.


Action 3.5b
– Observons le code suivant du fichier ‘VCNotes.m’

vers.delegate = self

 
Action 3.6 – Testons l’application.
 


4 – Sauvegarder les données dans l’appareil

 
Note: Le code est déjà présent dans le projet de départ.  Ce qui suit est un exercice de compréhension de la technique nécessaire pour être en mesure d’enregistrer des données sur l’appareil.
 

Aide mémoire:
Les fichiers d’une application, présents dans le dossier d’installation,  sont accessible en lecture seulement.  Pour qu’une application puisse les modifier, il faut les copier vers un des dossiers de l’utilisateur: Documents, Images, …
 

Étape initiale – Au besoin, copier les fichiers, qui seront modifiés par l’application, du paquet de l’installation (bundle) vers un dossier de l’utilisateur.
4.1 – Si non présent dans le dossier ‘Documents’, copier le fichier listeDesTaches.plist, livré avec l’application, vers de dossier ‘Documents’

    // MARK: - Gestion de la listeDesTaches.plist
    /**
        Envoyer une copie du ficher 'listeDesTaches.plist' vers le dossier 'Document'.
        Raison: La version livrée avec l'app est non modifiable.
    */
     func copierPlistVersDocuments() {
        let filemanager = NSFileManager.defaultManager()
        let documentsPath: AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0]
        let destinationPath = documentsPath.stringByAppendingString("/listeDesTaches.plist")
        if !filemanager.fileExistsAtPath(destinationPath) {
            let fileForCopy = NSBundle.mainBundle().pathForResource("listeDesTaches",ofType:"plist")
            filemanager.copyItemAtPath(fileForCopy!,toPath:destinationPath, error: nil)
            println("La liste des tâches a été copiée dans le dossier 'mes documents'")
        }
        else{
            println("La liste des tâches est déjà dans le dossier 'mes documents'")
        }
     } // copierPlistVersDocuments

 
4.2 – Lire les tâches sauvegardées à partir du dossier ‘Documents’

    /**
    Lire le fichier 'listeDesTaches.plist' vers le tableau 'tableauDesTaches'
    */
    func lirePlist() {
        let filemanager = NSFileManager.defaultManager()
        let documentsPath : AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0]
        let destinationPath = documentsPath.stringByAppendingString("/listeDesTaches.plist")
        tableauDesTaches = NSMutableArray(contentsOfFile: destinationPath)
        NSLog("%@", tableauDesTaches);
    } // lirePlist()

Note:  Il faudrait ajouter une validation sur la lecture du fichier des données.
 
4.3 – Écrire les tâches dans le dossier ‘Document’

    /**
        Écrire le tableau 'tableauDesTaches' dans le fichier 'listeDesTaches.plist'
    */
    func updatePlist() {
        let filemanager = NSFileManager.defaultManager()
        let documentsPath : AnyObject = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0]
        let destinationPath = documentsPath.stringByAppendingString("/listeDesTaches.plist")
        tableauDesTaches.writeToFile(destinationPath, atomically:true)
    }  // updatePlist()

Note:  Il faudrait ajouter une validation sur l’écriture des données dans le fichier plist.


5 – Documentation en ligne

 
Xcode propose des outils pour documenter, en ligne, les codes sources, les classes, les méthodes, les propriétés.
La documentation en ligne, des classes livrées avec Xcode, est accessible soit par la séquence alt+clic:
doc-en-ligne.01
 
soit par l’inspecteur d’aide:
doc-en-ligne.02
 
Il est aussi possible d’obtenir de la documentation sur une méthode ou un propriété d’une classe:
doc-en-ligne.03

 


5.1 Documentation de nos classes

 
Il est possible de programmer le même genre de documentation en ligne pour les classes de nos projets.
 
Par exemple, sur complétion du code:

doc-en-ligne.04
 

doc-en-ligne.06
 

doc-en-ligne.07
 
Documentation en ligne d’une classe personnalisée

doc-en-ligne.05
 

doc-en-ligne.08
 
 


5.2 – Rédiger de la documentation en ligne

 
Pour rédiger de la documentation en ligne, il suffit d’utiliser la syntaxe suivante:

/// Une description de ce qui suit …
var unePropriété:Int
/// Une description de ce qui suit …
var uneAutrePropriété:String

Note: Il faut utiliser trois ‘/’.
Note:  Entre le commentaire et le code, il est possible d’insérer des lignes vides mais pas de commentaires standards:  // Ceci est un commentaire standard.
 

/**
De la documentation
sur plusieurs
lignes…
*/
func uneMéthodeDocumentée() {}

Note: Il faut utiliser ‘/**’ pour ouvrir le commentaire.
 

/**
Transformer les propriétés de la classe Tache en format NSDictionary
    :param:  Aucun
    :returns: Tache en format NSDictionary
Auteur:   Alain Boudreault
Date:       2014.10.20
M-A-J:      2014.10.21 – Ajout de la documentation en ligne.
*/
func tacheToDictionary()

Note:  Le mot clé est entre ::
Note:  Il doit y avoir au moins une ligne vide entre les sections.
Résultat:
docum-enligne-sections-2

Précision:
Au moment d’écrire ce document (Xcode 6.1), la fonction de documentation en ligne, sous swift, n’était pas entièrement implémentée par Apple.
Plusieurs mots clés, pour les sous-sections, qui étaient disponibles en Objective-C ne le sont pas encore.
Cette situation devrait être corrigée dans les prochaines versions de Xcode.

En référence, voici une liste des mots clés, de sous-sections, disponibles en Objective-C
[table]
Section, Exemple
:brief:, :brief: Ceci est la description sommaire
:attention:, :attention: À l’usage exclusif des étudiants de TIM
:author:, :author: Alain Boudreault
:bug:,:bug:  La méthode @b mangerDuPain retourne un lapin!
:copyright:,:copyright: 2014 – Alain Boudreault
:date: ,:date: 2014.10.27
:invariant:,:invariant: ..
:note:, :note: ..
:post:, :post: ..
:pre:,:pre: ..
:remarks:,:remarks: Voici des remarques …
:sa:,:sa: sa text
:see:,:see: see text
:since:,:since: depuis toujours
:todo: ,:todo: Corriger la méthode @b mangerDuPain
:version:,:version: 1.0
:warning:,:warning: Ici la voix des mistérons…
:result:,:result: result text
:return:,:return: return text
:returns:,:returns: returns text
:code::endcode:, Pour afficher un bloc de code
[/table]
 
Exemple,
xcode.docum.enligne
 
 


5.3 – Les marqueurs MARK:, TODO: et FIXME:

 
Les marqueurs MARK:, TODO: et FIXME: servent à insérer des points d’ancrage dans le code source.  Ces points d’ancrage permettent un accès rapide à un section de notre code.  Après définitions, il sont accessible via le menu de saut (Jump Bar).
jump-bar
 
documentation-marqueurs


6.4 Exemple d’une classe documentée

 
Voici le code de la classe ‘Tache’.  Il est extrait du projet en cours.
 

//
//  Tache.swift
//  Post'TIM version swift
//
//  Créé par Alain Boudreault le 20105.11.15
//  Copyright (c) 2014 Alain Boudreault. All rights reserved.
//
//  MARK: - Note importante!
//  ============================================================================================
//  À l'usage exclusif des étudiants et étudiantes de
//  ============================================================================================
import Foundation
// NOTE: un retour de chariot est requis entre les différentes sections de la documentation.
/**
    Classe pour regrouper les informations d'une tâche.
    Propose un init permettant de construire une tâche à partir d'un NSDictionary
    :returns: une instance de la classe Tache.
    :param: aucun
    Auteur:   Alain Boudreault
    Date:     2014.10.20
*/
class Tache {
    /// La date de la tâche.
    var date:NSDate
    /// Le nom de la tâche.
    var tache:String
    /// L'importance de la tâche, une valeur entre 1...9
    var importance:String
    /// Un texte décrivant la tâche.
    var description:String  ///< Un texte décrivant la tâche.  // Syntaxe non fonctionnelle sous Swift.
    /**
        Construire une tache vide.
        :param: aucun
    */
    init () {
        self.date           = NSDate()
        self.description    = ""
        self.importance     = ""
        self.tache          = ""
    } // init
    /**
        Construire une tache à partir de données d'un dictionnaire.
        :param: detail:NSDictionary contenant les clés "date", "description", "importance" et "tache"
    */
    init (detail:NSDictionary) {
        self.date           = detail["date"]        as NSDate
        self.description    = detail["description"] as String
        // FIXME: Valider le contenu de detail["importance"]
        self.importance     = detail["importance"]  as String
        self.tache          = detail["tache"]       as String
    } // init
    /**
        Transformer les propriétés de la classe Tache en format NSDictionary
        :returns: Tache en format NSDictionary
        Auteur:   Alain Boudreault
        Date:       2014.10.20
        M-A-J:      2014.10.21 - Ajout de la documentation en ligne.
    */
    func tacheToDictionary() -> NSDictionary {
        return NSDictionary(dictionary: ["tache":self.tache,
            "date":self.date,
            "importance":self.importance,
            "description":self.description])
    } // tacheToDictionary()
    //TODO: Ajouter une méthode quiSuisJe()
} // class Tache

 


6 – Ajouter les icônes de l’application

 
Pour ajouter des icons à l’application, il suffit de faire glisser des images, de la bonne taille, dans le panneau ‘AppIcon’ du groupe ‘Images.xcassets’:
post-tim.icon.01b
Note:  Il y a une série d’images, pouvant servir d’icon, dans un des dossiers du projet de départ.
 

Référence pour la taille des fichiers:

post-tim.icon.02b

Résultat sur l’appareil:

changer-icon.01
Dans spotlight:
changer-icon.02
 


6.1 Changer le titre le l’application

Le titre de l’application est tronqué, sur le téléphone, car il est trop long.
 
changer-titre-app.01
 
Voici comment le changer:
changer-titre-app.02
 
changer-titre-app.03
 
Résultat sur l’appareil:
changer-titre-app.04
 
Voici qui complète le laboratoire Post’TIM!
 
Post’TIM version swift 6.01 – solution
Post’TIM version swift 6.1 – solution


Document préparé par Alain Boudreault (c) 2013-2014 – version 2014.11.17