En Swift, les types de valeur (struct, enum, tuple) possèdent ce que l'on appelle la sémantique de valeur : lors du passage ou de l'affectation à une variable, tout le contenu est copié - un nouvel exemplaire indépendant est créé. Cela permet d'éviter une série de complexités liées à l'état partagé, caractéristiques des types de référence (class).
Cependant, pour optimiser la mémoire, les collections (par exemple, Array, Dictionary, Set) utilisent la stratégie de copy-on-write : la copie se produit uniquement lorsqu'un des exemplaires est modifié.
Exemple :
var a = [1, 2, 3] var b = a b.append(4) print(a) // [1, 2, 3] print(b) // [1, 2, 3, 4]
Ici, le tableau a ne changera pas - bien qu'il y ait eu un stockage commun au départ, lorsque b est modifié, Swift fera une copie séparée des données.
Il est important de se rappeler : si une structure contient un type de référence (par exemple, une classe), la sémantique de valeur s'applique uniquement à la structure elle-même, et non aux objets référencés imbriqués.
Le contenu d'un tableau changera-t-il si nous le passons à une fonction et que nous l'éditons à l'intérieur de cette fonction ? Expliquez la différence entre le comportement d'une struct et d'une class.
Réponse avec exemple :
func mutate(_ arr: inout [Int]) { arr.append(100) } var source = [1, 2] mutate(&source) print(source) // [1, 2, 100]
Si on ne passe pas en inout, la copie se produira automatiquement au premier changement dans la fonction, et le tableau d'origine ne changera pas. Pour les classes, aucune copie ne se produit - l'objet d'origine changera toujours.
Histoire
Les développeurs mettaient des objets de référence dans un tableau de structures (struct), s'attendant à ce qu'une modification via une structure n'affecte pas d'autres exemplaires. En réalité, en modifiant des objets référencés à un endroit, ils changeaient de manière inattendue partout (état partagé).
Histoire
Dans un projet d'équipe, on a tenté de protéger contre la condition de course en copiant des collections à chaque accès. Cela a entraîné des dépenses mémoire imprévues et une baisse de performance lors du traitement de grands tableaux.
Histoire
Un jeune développeur essayait de suivre les changements dans un tableau, ce qui l'a amené à le passer par inout à plusieurs fonctions de traitement en même temps. L'ordre des modifications devenait obscur, ce qui a conduit à des modifications non sécurisées, des bogues et des erreurs de synchronisation.