[Résolu] Mémoire - ImageIO_PNG_DATA - weak/strong

busterTheobusterTheo Membre
octobre 2015 modifié dans Apple Developer Programs #1

Bonjour,


suite à  ce post, et les conseils de Draken, je teste la consommation mémoire dans le Debug Navigator, et je remarque un truc grave.


 


Le fait de faire un push vers un second VC puis un popToRoot vers le premier VC, puis de recommencer cela plusieurs fois, ne fait qu'augmenter la consommation mémoire (seulement dans le sens push).


Environ 12Mo à  chaque fois.


 


J'ai donc tester sur plusieurs de mes projets (simple et complexes), et à  chaque fois, ça augmente. 


 


Comment  revenir à  la consommation précédent le push.


On dirait que la consommation due au push s'accumule à  chaque fois, et ne redescend pas lors du popToRoot.


 


J'ai lu ça, enfin parcouru, parce que c'est tout en anglais et hyper long.


C'est sur ça : 



 


strong reference cycles



 


J'ai cru comprendre en fouillant sur le web, que le problème pouvait venir de là .


Mais je ne sais pas comment faire.


 


En attendant, je rajoute ça sur  le premier VC :



etape1ViewController = UIStoryboard.etape1ViewController()
etape1ViewController.removeFromParentViewController()
etape1ViewController = nil

et ça sur le second VC :



etape0ViewController = UIStoryboard.etape0ViewController()
etape0ViewController.removeFromParentViewController()
etape0ViewController = nil

et ça ne change rien.


 


Pourtant, en faisant un println je vois bien que les VC sont chacun leur tour "nil".


 


Je pensais que en faisant ça, les variables associées aux VC seraient vidées ?


 


Quelqu'un a-t-il une idée ?


 


Merci.


«1

Réponses

  • Joanna CarterJoanna Carter Membre, Modérateur
    Et dans la méthode etape0ViewController, qu'est-ce que y se trouve ?
  • Heu c'est pas une méthode, c'est une classe.



    class Etape0ViewController: UIViewController, UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    ...

    }

    C'est le controller associé à  la view correspondante.


     


    Idem pour etape1


     


    Et dedans, y'a plein de méthodes, et de variables. Normal, quoi.


     


    Je ne comprend pas comment on vide les variables d'un controller que l'on quitte pour un autre.


     


    J'ai aussi testé ça :




    override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)

    self.removeFromParentViewController()
    }

    override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)

    self.removeFromParentViewController()
    }

    ça change rien


  • J'ai aussi essayé ça :



    override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Release any cached data, images, etc that aren't in use.
    }

    ça change rien, toujours 13Mo de plus à  chaque push


  • En testant dans Instruments, dans "Leaks",  et je n'ai pas de "leaks".


     


    Par contre, je remarque dans les stats que la ligne "ImageIO_PNG_DATA", augmente justement de 13Mo à  chaque "push", dans la colonne "Persistent bytes", alors que mon dossier d'images fait 3Mo, et que la photo chargée dans la view fait 280Ko.


     


    Y'a cette page qui nomme la chose.


    Il résout le pb avec une librairie, mais je ne comprend rien à  l'install.


    Et est-ce vraiment nécessaire de mettre une librairie. Y'a surement un truc à  faire dans mon code...

  • Joanna CarterJoanna Carter Membre, Modérateur
    juillet 2015 modifié #6


    Heu c'est pas une méthode, c'est une classe.

    class Etape0ViewController: UIViewController, UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {...}
    C'est le controller associé à  la view correspondante.


    Idem pour etape1


    Et dedans, y'a plein de méthodes, et de variables. Normal, quoi.


    Je ne comprend pas comment on vide les variables d'un controller que l'on quitte pour un autre.

    Tu as écrit :

    etape1ViewController = UIStoryboard.etape1ViewController()

    UIStoryboard ne possède pas la méthode de classe etape1ViewController()


    Comment as-tu ajouté ce méthode de classe et qu'est-ce que tu as écrit là  dedans ?

  • import UIKit

    extension UIStoryboard {

    class func mainStoryboard() -> UIStoryboard {
    return UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
    }

    class func patientsViewController() -> PatientsViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("ListePatientsSB") as? PatientsViewController
    }

    class func contentEtapesViewController() -> ContentEtapesViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("ContentEtapesSB") as? ContentEtapesViewController
    }

    class func etape0ViewController() -> Etape0ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape0SbLevel1") as? Etape0ViewController
    }

    class func etape1ViewController() -> Etape1ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape1SB") as? Etape1ViewController
    }

    class func etape1L1ViewController() -> Etape1L1ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape1SbLevel1") as? Etape1L1ViewController
    }

    class func etape1L2ViewController() -> Etape1L2ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape1SbLevel2") as? Etape1L2ViewController
    }

    class func etape1L3ViewController() -> Etape1L3ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape1SbLevel3") as? Etape1L3ViewController
    }

    class func etape1L4ViewController() -> Etape1L4ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape1SbLevel4") as? Etape1L4ViewController
    }

    class func etape1L5ViewController() -> Etape1L5ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape1SbLevel5") as? Etape1L5ViewController
    }

    class func etape2ViewController() -> Etape2ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape2SB") as? Etape2ViewController
    }

    class func etape2L1ViewController() -> Etape2L1ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape2SbLevel1") as? Etape2L1ViewController
    }

    class func etape2L2ViewController() -> Etape2L2ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape2SbLevel2") as? Etape2L2ViewController
    }

    class func etape2L3ViewController() -> Etape2L3ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape2SbLevel3") as? Etape2L3ViewController
    }

    class func etape2L4ViewController() -> Etape2L4ViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("Etape2SbLevel4") as? Etape2L4ViewController
    }

    class func orientationViewController() -> OrientationViewController? {
    return mainStoryboard().instantiateViewControllerWithIdentifier("OrientationStoryBoard") as? OrientationViewController
    }

    }
  • Sans quoi, je suis tombé là -dessus.


     


    Donc, j'apprend que l'on peut maintenant faire ça, et pas de pb de mémoire.



    self.imageViewIntro.image = UIImage(named: "intro.jpg")

    Mais du coup, j'essaie quand même de remplacer mes



    self.imageViewIntro.image = UIImage(named: "intro.jpg")

    par 



    self.imageViewIntro.image = UIImage(contentsOfFile: NSBundle.mainBundle().pathForResource("intro",ofType:"jpg")!)

    et ça



    viewRampeLeft.backgroundColor = UIColor(patternImage: UIImage(named: "rampeEtape1L2.png")!)

    par ça



    viewRampeLeft.backgroundColor = UIColor(patternImage: UIImage(contentsOfFile: NSBundle.mainBundle().pathForResource("rampeEtape1L2",ofType:"png")!)!)

    Donc je fais ça dans tous mes fichiers, et je retisserais.


     


    Il faut bien essayé, et comme je n'ai pas la pure culture et l'historique de Xcode, je n'ai pas le choix.


     


    Merci pour tes efforts


  • Bon, ben ça ne change rien.


     


    Ni dans Instrument/Leaks, et ni dans le Debug Navigator.


     


    Donc, toujours pas de solutions, ou de piste ?


  • AliGatorAliGator Membre, Modérateur
    Pas grand chose à  voir avec la question d'origine, mais pour t'éviter d'avoir à  écrire toutes ces "class func" dans une extension de UIStoryboard à  la main, tu peux utiliser mon outil (écrit en Swift pour écrire du Swift!) SwiftGen qui est justement fait pour ça !
  • Merci AliGator. ça a l'air bien ton truc, mais trop compliqué pour moi. Et puis je la trouve pas mal cette petite classe, qui n'est pas de moi d'ailleurs. ça vient d'un toto, je sais plus lequel. Mais j'aime bien le principe.


    Pour les class fun, un p'tit copier coller et hop. C'est pas grand chose.


     


    En attendant t'as une idée pour la mémoire et les images et apparemment une histoire de cache ?


  • D'après ce post, il semblerait que ce problème n'apparaisse que sur un simulator, et non pas sur un device.


     


    Des infos là -dessus ?


     


    Si c'est vrai, ça me rassure.


     


    Je rappelle le problème de base.


     


    dans Instruments/Leaks (ImageIO_PNG_DATA) et aussi dans le debug navigator, la mémoire augmente sans cesse.


     


    La mémoire réservée par le système pour les images ne se vide jamais.


  • AliGatorAliGator Membre, Modérateur

    [...] Mais j'aime bien le principe.

    Bah mon outil reprend *exactement* le principe que ton tuto t'as fait faire à  la main, donc ce principe que tu aimes bien dans ton tuto, c'est justement exactement ce que je génère de mon côté

    mais trop compliqué pour moi.

    Heu le README ne serait pas clair ?

    Il suffit d'exécuter ceci dans ton terminal et c'est fini, il te génère tout seul le code avec toutes les "class func" pour ton UIStoryboard dans "Storyboard.swift"... c'est pas sorcier quand même, on peut difficilement faire plus simple que de faire ça en une seule ligne !

    swiftgen-storyboard /chemin/vers/to/dossier/projet >Storyboards.swift

    ---


    Sinon, pour ton problème de mémoire, "UIImage(named: xxx)" garde en cache les images (dans un NSCache interne, ce qui est donc tout à  fait adapté, et se vide tout seul dès réception d'un Memory Warning pour libérer la mémoire à  la moindre demande / au moindre besoin). C'est très bien implémenté et permet à  la fois d'avoir un chargement très rapide des images que tu as déjà  utilisées avant dans ton code, et de libérer la mémoire tout seul quand le système en demande. Mais évidemment, du coup à  chaque fois que tu demandes une nouvelle UIImage avec un nom d'image que tu n'as pas encore demandé avant, ça fait un pic mémoire qui ne sera pas vidé immédiatement (car c'est le but, garder l'image en cache), mais sera automatiquement vidé si le système a besoin de ressources. Tu peux voir justement si ces pics mémoires et usage de la RAM redescendent tout seul si tu simules un MemoryWarning dans ton simulateur.
  • Merci Alligator pour tes explications, qui commencent à  m'éclairer.


     




    1- Concernant ton outils, tu m'as convaincu.




    J'essaierai, un de ces quatre, la ligne de commande, ça a l'air super intéressant.


    Ton readMe est super clair, sauf que c'est moi qui a un peu de mal avec l'anglais.


     


     


     


     




    2- Concernant UIImage :




    Tu conseilles donc d'utiliser 



    UIImage(named:

    plutôt que 



    UIImage(contentsOfFile: NSBundle.mainBundle().pathForResource(

    Parce que j'ai lu tellement de choses là -dessus, que je ne sais plus à  quel saint me vouer.


    Tu sembles confirmer que 



    UIImage(named:

    soit l'idéal. Mais je me pose des questions concernant les images qui sont réutilisées et celles qui sont ponctuelles.


     


    Voici donc le type d'images que j'utilise :


    Toutes les images sont en 264dpi - Le projet ne tournera que sur des iPad2.


     


    Des images de fond en jpg placées sur toutes les Views dans le storyBoard - 163Ko - 1024x768


    D'autres images de fond en jpg placées en code sur peu de Views - 148Ko, etc.


    Des p'tits pictos en png placés en code sur toutes les Views - 11Ko


    Et surtout des photos qui chargées par l'utilisateur d'après l'album, l'appareil photo, ou téléchargées. Pour le dév. j'utilise des photos en jpg de 560x420 - 250Ko.


     


     



     


    Mais évidemment, du coup à  chaque fois que tu demandes une nouvelle UIImage avec un nom d'image que tu n'as pas encore demandé avant, ça fait un pic mémoire qui ne sera pas vidé immédiatement



     


    Quand je passe du controller VC1 à  VC2, la mémoire consommée augmente - Donc, là , ok - Mais quand je passe ensuite de VC2 à  VC1 puis à  nouveau de VC1 à  VC2, la mémoire augmente encore (et cela avec les deux techniques UIImage). J'ai donc l'impression que l'image est stockée plusieurs fois en cache. C'est très bizarre, d'autant plus que j'ai lu plein de posts qui soulignent ce fait. On le remarque dans Instruments/Leaks sur "ImageIO_PNG_DATA)".


     


     



     


     


    mais sera automatiquement vidé si le système a besoin de ressources

    Je peux faire monter la mémoire consommée au-delà  de 500Mo, en faisant VC1 -> VC2 puis VC2 -> VC1 puis VC1 -< VC2 etc.


    La mémoire ne se vide jamais. Cela veut-il dire que le système n'a pas besoin de mémoire ? Plus de 500Mo, c'est quand même chaud, non ? Et surtout que c'est simplement en faisant "VC1 -> VC2 puis VC2 -> VC1 puis VC1 -< VC2" - Alors qu'ensuite, lorsque je navigue dans le projet (dans un PageView entre autres) et que j'utilise toutes mes fonctionnalités, cela n'augmente pas la mémoire consommée.


     



     


     





    3- Concernant memory warnings :




    J'ai fait "Simulate Memory Warning", aussi bien dans le simulator que dans Instruments. Pour ce faire, j'ai fait ça :



    override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

    println("memory warning")
    }

    puis "Simulate ...."" dans le soft.


     


    J'ai aussi essayé sur un nouveau projet vide.


     


    J'ai exactement les mêmes infos - Et cela, uniquement au démarrage - à  savoir :



     


    2015-07-21 12:52:34.419 GuideEsthetique[32837:4651762] Received memory warning.


    memory warning



     


    Puis lorsque je navigue (VC1 -> VC2 puis VC2 -> VC1 puis VC1 -< VC2 etc), je n'ai aucun message supplémentaire.


     


    Je ne vois pas trop comment utiliser ces simulations de memory warnings. En tout cas, cela ne m'aide pas pour éviter que la mémoire consommée augmente indéfiniment.


     


    Merci d'avance pour ta réponse.


     


    Pour info, je récupère un vieil iPad2 dans une semaine - J'ai hâte.


  • AliGatorAliGator Membre, Modérateur
    On parle de UIImage mais t'es sur que la source de ta fuite vient d'une UIImage ? ça t'a été confirmé avec Instruments ?
  • Ben je vois que "ImageIO_PNG_DATA" (dans Instruments/Leaks) augmente sans cesse quand je navigue vc1 / vc2 / vc1 / vc2 etc.


    Et à  chaque fois de 13Mo.


     


    Puis quand j'explore le détail, je vois qu'il y a des images de 12Mo :



     


    # Address Category Timestamp Live Size Responsible Library Responsible Caller


    0 0x116891000 ImageIO_PNG_Data 00:11.615.212 • 12,00 MB ImageIO ImageIO_Malloc

    1 0x115c91000 ImageIO_PNG_Data 00:11.176.621 • 12,00 MB ImageIO ImageIO_Malloc

    2 0x115091000 ImageIO_PNG_Data 00:09.449.142 • 12,00 MB ImageIO ImageIO_Malloc

    3 0x114cb2000 ImageIO_PNG_Data 00:09.446.965 • 212,00 KB ImageIO ImageIO_Malloc

    4 0x1130f7000 ImageIO_PNG_Data 00:11.611.414 • 8,00 KB ImageIO ImageIO_Malloc

    5 0x1130f5000 ImageIO_PNG_Data 00:11.611.016 • 8,00 KB ImageIO ImageIO_Malloc

    6 0x1130f1000 ImageIO_PNG_Data 00:11.610.567 • 8,00 KB ImageIO ImageIO_Malloc

    7 0x1130ef000 ImageIO_PNG_Data 00:11.609.846 • 8,00 KB ImageIO ImageIO_Malloc

    8 0x112b99000 ImageIO_PNG_Data 00:11.558.964 • 4,00 KB ImageIO ImageIO_Malloc

    9 0x112b97000 ImageIO_PNG_Data 00:11.557.618 • 4,00 KB ImageIO ImageIO_Malloc

    10 0x112b98000 ImageIO_PNG_Data 00:11.556.212 • 4,00 KB ImageIO ImageIO_Malloc

    11 0x112813000 ImageIO_PNG_Data 00:06.590.959 • 4,00 KB ImageIO ImageIO_Malloc

     


     


     


    Je ne sais pas, d'ailleurs comment repérer les images en fonction de" l'Adresse".


     


    J'ai mis une vidéo ici, où l'on voit bien la mémoire de "ImageIO_PNG_DATA" augmentée indéfiniment.


  • T'en penses quoi du coup de mon "ImageIO_PNG_DATA" ?


  • AliGatorAliGator Membre, Modérateur
    Sans le projet ni le temps pour vraiment étudier l'impact et les traces Instruments, je vais avoir du mal à  te dire, je laisse la main à  ceux qui ont un peu plus de temps pour regarder ça de plus près.
  • Ah désolé, encore merci.


  • Sans connaà®tre rien à  Swift et à  ton projet, mais en Objective-C, je checkerais ça :

    deinit (équivalent dealloc) est-il appelé ?

    Des NSTimers ?


    Des delegates strong ? De ce que j'ai lu rapidement, les var sont à  strong par défaut.


    Des observers ? (addObserver:zzz:)


  • busterTheobusterTheo Membre
    juillet 2015 modifié #22

    Merci Larme pour tes précisions.


     



     


     


    les var sont à  strong par défaut

    J'avais vu ça aussi. Et il faut donc faire :



    weak var viewVoletTop: UIView!

    plutôt que :



    var viewVoletTop: UIView! 

    Mais quand je lance l'appli, j'ai une erreur (ça plante -> nil...) dès que j'utilise :



    viewVoletTop

    D'autre part si je fais :



    weak var poigneesHeight: CGFloat!

    J'ai cette erreur :


     



     'weak' cannot be applied to non-class type 'CGFloat'



     


    Génial le weak !!!


     


     


     


    deinit (équivalent dealloc) est-il appelé

    Je ne sais pas me servir de ces trucs là , mais je vais faire des recherches...


     


     



    Des NSTimers



    Je n'ai aucun (pour l'instant) timer. Et si ça devient le cas, je ne sais pas ce à  quoi tu fais référence.


     


     



    Des observers ? (addObserver:zzz:)



    Alors là , carrément, je suis complètement inculte sur ce sujet.


    Je connais les écouteurs en ActionScript, je pense que c'est un peu la même chose.


    Je vais faire des recherches.


     


    Pour le coup des images, t'as pas d'idée ?


     


    Merci encore pour ces pistes à  suivre.


  • DrakenDraken Membre
    juillet 2015 modifié #23


     


    D'autre part si je fais :



    weak var poigneesHeight: CGFloat!

    J'ai cette erreur :


     


    'weak' cannot be applied to non-class type 'CGFloat'


     


    Génial le weak !!!


     


     




    Forcément, weak n'est applicable que sur une variable contenant un objet. Un CGFloat n'est pas un objet, c'est juste un nombre. 


     


    Le mécanisme de gestion mémoire de Swift est efficace, mais il ne sait pas gérer les références croisées.


     


    Si un objet A contient une référence sur l'objet B, et que B contient une référence sur l'objet A, il y a un problème. A ne peut être détruit que si B est détruit. Et B ne peut être détruit que si A n'existe plus, une situation paradoxale !


     


    Cela arrive chaque fois qu'un objet possède un lien sur son "supérieur". Par exemple une vue avec une référence sur son contrôleur. 


     


    Pour éviter ça, on utilise les références fortes et les références faibles. Si un objet B possède une référence faible sur un objet A, le gestionnaire de mémoire sait qu'il peut le détruire, même si A existe encore.


     


    // Problème


    A possède une référence sur B


    B possède une référence sur A


     


    // Solution


    A possède une référence forte sur B


    B possède une référence faible sur A


     


    Par défaut, toutes les références sont fortes.



    // Référence forte
    let uneVue = UIView()

    Pour créer une référence faible, il faut ajouter l'attribut weak.



    weak var unObjet = MonObjet()
  • Merci Draken.


     



     


     


    Pour créer une référence faible, il faut ajouter l'attribut weak.

    Oui, ça je sais.


     


    Ok pour le CGFloat. Merci.


     


    Mais, dixit la première erreur dont je parle, comment fait-on pour mettre un weak sur un objet (weak var viewVoletTop: UIView!), alors que dès qu'on l'utilise (viewVoletTop) on tombe en erreur ?


     


    Merci


  • A mon avis tu n'as pas initialisé viewVoletTop.


  • Joanna CarterJoanna Carter Membre, Modérateur
    Ou tu as seulement le weak sans un strong
  • Ouaaah, je n'ai donc rien compris.


     


    En swift, je croyais que (avec weak ou pas)



    var viewVoletTop: UIView!

    était l'initialisation, puis, par exemple



    override func viewDidLoad() {
    viewVoletTop = UIView(frame: CGRectMake(262, 115, 500, 400))
    ...
    }

    était l'instanciation.

  • busterTheobusterTheo Membre
    juillet 2015 modifié #28

     


    Ou tu as seulement le weak sans un strong



    Désolé, mais je ne comprend pas ce que tu veux dire ...


  • Joanna CarterJoanna Carter Membre, Modérateur
    juillet 2015 modifié #29


    Désolé, mais je ne comprend pas ce que tu veux dire ...



    Pour avoir une référence weak qui restera valide, il faut "tenir" l'objet dans une autre référence strong, autrement il n'y aura rien à  empêcher l'objet de mourir.


  • Ouaaah, je n'ai donc rien compris.


     


    En swift, je croyais que (avec weak ou pas)



    var viewVoletTop: UIView!

    était l'initialisation, puis, par exemple



    override func viewDidLoad() {
    viewVoletTop = UIView(frame: CGRectMake(262, 115, 500, 400))
    ...
    }

    était l'instanciation.





    var viewVoletTop: UIView!

    ça c'est la déclaration de la variable et non l'initialisation.


     


    On peut aussi utiliser la formulation suivante pour déclarer et initialiser en même temps :



    var viewVoletTop = UIView()

    ou encore



    var viewVoletTop:UIView! = UIView()

    Et initialiser la frame de la vue dans le viewDidLoad.



    override func viewDidLoad() {
    viewVoletTop.frame = CGRectMake(262, 115, 500, 400)
    ...
    }
  • AliGatorAliGator Membre, Modérateur
    La déclaration, c'est ce qui consiste à  dire quel est le nom de ta variable et quel est son type.
    L'initialisation, c'est quand tu lui donnes une valeur initiale.

    ---

    Donc par exemple :

    var viewVoletTop : UIView!
    C'est une déclaration, tu déclares que tu as une variable nommée "viewVoletTop" et que son type est "UIView!". Tu déclares qu'elle existe et quel est son type, mais tu pour l'instant elle n'a aucune valeur dedans, tu dis juste qu'elle existe. Qui dit déclaration de variable/constante dit mot clé "var"/"let" (respectivement).

    ---

    Alors qu'ensuite quand tu écris :

    viewVoletTop = UIView()
    Tu affectes une valeur initiale à  cette propriété/variable, c'est bien une initialisation (qui dit initialisation dit affectation d'une valeur à  la variable, donc dit forcément un "=" quelque part)

    Après, tu peux faire les deux en même temps, ainsi :
    var viewVoletTop : UIView! = UIView()
    Est à  la fois une déclaration et une initialisation en une seule ligne de code. Tu déclares à  la fois qu'il existe une variable ("var") qui porte le nom "viewVoletTop" et que son type (":") est "UIView!", tout ça c'est la partie "déclaration", et dans la même ligne tu lui donnes une valeur initiale (tu l'initialises) avec le "= UIView()" ("UIView()" va créer une instance de la classe UIView, donc va créer un objet de type UIView, et ensuite tu affectes cette nouvelle instance / ce nouvel objet dans ta variable viewVoletTop)

    ---

    Il se trouve que Swift étant assez intelligent pour inférer {déduire) le type des variables quand le contexte le lui permet, donc de même quand tu écris :
    var viewVoletTop = UIView()
    TU fais également à  la fois une déclaration et une initialisation en une seule ligne. Cette ligne est en fait exactement l'équivalent de la ligne que j'ai écrite juste avant, sauf que quand tu *déclares* ta variable avec "var viewVoletTop" tu ne précises pas *explicitement* son type, mais Swift sait le déduire car il voit que tu en profites pour aussi *initialiser* cette variable avec un objet de type "UIView" (car l'objet créé par le constructeur "UIView()" est forcément un objet de type UIView) et donc il va en déduire que cette variable "viewVoletTop" bah son type c'est certainement "UIView", et donc que la ligne que tu as écrit revient à  la même chose que si tu avais écrit implicitement :
    var viewVoletTop : UIView = UIView()
    NB : Note d'ailleurs au passage que ce n'est donc pas *exactement* la même chose qu'avant, car dans ce cas il considère que ta variable est de type non-optional ("UIView") alors qu'en la typant explicitement avec ": UIView!" tu lui dis que c'est une "implicitly-unwrapped-optional" donc une "UIView!" et pas juste une "UIView"...



    Bref, déclaration c'est quand tu as "var" ou "let". initialisation c'est quand tu affectes une valeur initiale à  ta variable ou constante avec un "=". Chose qui peut se faire soit sur la même ligne que la déclaration, soit dans le "init" (le constructeur) de ta classe.
Connectez-vous ou Inscrivez-vous pour répondre.