Une introduction à Swift Partie 2

Dans le premier article de cette série d'introduction sur Swift, nous avons parlé de la philosophie de Swift, avons d'abord examiné sa syntaxe et souligné quelques différences essentielles par rapport à Objective-C. Dans cet article, nous continuons notre exploration de la syntaxe de Swift. Vous apprendrez également à connaître les options et à voir comment fonctionne la gestion de la mémoire dans Swift..

1. Conditions et boucles

Si

Si les déclarations sont identiques dans Swift et Objective-C à l’exception de deux différences subtiles:

  • les parenthèses autour de la variable de condition sont facultatives
  • des accolades sont nécessaires

Ce sont à peu près les seules différences avec les déclarations if dans Objective-C.

Gammes

Comme nous l'avons vu dans le premier article, Swift inclut deux opérateurs de gamme … < et pour spécifier une plage de valeurs. Ces deux opérateurs sont les opérateur de champ semi-fermé et le opérateur fermé.

Une gamme semi-fermée, telle que 1… <5, représente les valeurs 1, 2, 3 et 4, à l'exclusion de 5. Une plage fermée, telle que 1… 5, représente les valeurs 1, 2, 3, 4 et comprend 5.

Les plages peuvent être utilisées dans pour boucles, tableau indice, et même dans commutateur déclarations. Regardez les exemples suivants.

// Exemple de boucle for i in 1… <10   // iterates from 1 to 9
// exemple d'indice de tableau let someArray = ["apple", "pair", "peach", "pastèque", "fraise"] pour les fruits de someArray [2… <4]  println(fruit)  // outputs: peach and watermelon
// exemple de commutateur switch someInt cas 0: // faire quelque chose avec 0 cas 1… <5: // do something with 1,2,3,4 case 5… 10: // do something with 5,6,7,8,9,10 default: // everything else 

Commutateur

Les instructions Switch sont plus puissantes dans Swift qu'elles ne le sont dans Objective-C. En Objective-C, le résultat de l'expression d'une instruction switch doit être de type entier et les valeurs de chaque instruction case doivent être une constante ou une expression constante. Ce n'est pas vrai dans Swift. Dans Swift, les instructions de cas peuvent être de tout type, y compris les plages.

Dans Swift, le commutateur n'a pas Pause déclarations et il ne tombe pas automatiquement d'un cas à l'autre. Lors de l'écriture d'une instruction switch, il faut veiller à ce que toutes les conditions soient gérées par ses instructions case, faute de quoi une erreur du compilateur sera générée. Un moyen sûr de couvrir toutes les conditions consiste à inclure un défaut déclaration de cas.

Voici un exemple de commutateur déclaration avec Chaîne cas:

let légume = "poivron rouge" changez de légume cas "céleri": let légumeComment = "Ajoutez des raisins secs et faites des fourmis sur une bûche." cas "concombre", "cresson": let légumeComment = "Cela ferait un bon sandwich au thé." default: let légumeComment = "Tout est bon en soupe."  

Dans Swift, les instructions case ne passent pas par défaut. Cette décision a été prise délibérément pour éviter des erreurs courantes. Si un cas spécifique doit échouer, vous pouvez utiliser le tomber dans mot-clé pour l'indiquer au compilateur.

changer someInt case 0: // faire quelque chose avec 0 cas 1: // faire quelque chose avec 1 cas 2: // faire quelque chose avec 2 valeur par défaut default: // faire quelque chose pour tout le reste // cas 2 tombera par défaut Cas

Ça ne s'arrête pas là. Swift ajoute deux autres fonctionnalités pour passer, liaisons de valeurs et le clause. La liaison de valeur est utilisée avec le affaire laisse mots-clés pour lier une constante avec la casse correspondante. La clause where ajoute une condition supplémentaire à l'instruction case en utilisant le  mot-clé.

Ces deux concepts sont mieux expliqués à l'aide d'exemples. Le bloc de code suivant montre comment liaison de valeur travaux.

let somePoint = (xaxis: 2, yaxis: 0) change un certainPoint cas (let x, 0): println ("sur l'axe des x avec une valeur x de \ (x)") cas (0, let y): println ("sur l'axe des y avec la valeur de \ (y)") cas let (x, y): println ("ailleurs à (\ (x), \ (y))")

La première déclaration de cas, cas (let x, 0), correspondra aux valeurs où yaxis est égal à 0 et toute valeur pour xaxis, et nous nous lions xaxis à la constante X à utiliser dans la déclaration de cas.

Voici un exemple de la clause where en action.

let légume = "poivron rouge" change de casse case "céleri": println ("Ajoute quelques raisins secs et fait des fourmis sur une bûche.") cas let let x où x.hasSuffix ("poivre"): println ("je suis allergique to \ (x) ") défaut: println (" Tout est bon en soupe. ") // sorties: je suis allergique au poivron rouge

2. Fonctions et fermetures

Les fonctions

La définition des fonctions et des fermetures est facile dans Swift. Les développeurs Objective-C les connaissent mieux sous forme de fonctions et de blocs.

Dans Swift, les paramètres de fonction peuvent avoir des valeurs par défaut, rappelant les langages de script tels que PHP et Ruby..

La syntaxe des fonctions est la suivante:

func functionName (NomParamètre: Type = ValeurPar défaut) -> returnType […] return returnType; 

Écrire un dis bonjour fonction qui prend un paramètre prénom de type Chaîne et retourne un Bool en cas de succès, nous écrivons ce qui suit:

func sayHello (name: String) -> Bool println ("bonjour \ (nom)"); retourne vrai;  sayHello ("World") // sortie // hello World

Pour passer une valeur par défaut pour le prénom paramètre, l'implémentation de la fonction ressemblerait à ceci:

func sayHello (name: String = "World") -> Bool println ("hello \ (nom)"); retourne vrai;  sayHello () // sortie // bonjour le monde ditHello ("mike") // sortie // bonjour mike

Une fonctionnalité complètement absente dans Objective-C est tuples. Dans Swift, les fonctions peuvent renvoyer plusieurs valeurs sous la forme d'un tuple. Les tuples sont traités comme une seule variable, ce qui signifie que vous pouvez le faire passer comme une variable..

Les tuples sont très faciles à utiliser. En fait, nous avons déjà travaillé avec des n-uplets dans l'article précédent lorsque nous avons énuméré un dictionnaire. Dans le prochain extrait de code, la paire clé / valeur est un tuple..

for (clé, valeur) dans someDictionary println ("Key \ (key) a la valeur \ (value)"

Comment utilise-t-on les n-uplets et quels avantages en tirez-vous? Jetons un coup d'oeil à un autre exemple. Modifions ce qui précède dis bonjour fonction pour retourner un booléen en cas de succès, ainsi que le message résultant. Nous faisons cela en retournant un tuple, (Bool, String). La mise à jour dis bonjour la fonction ressemble à ceci:

func sayHello (name: String = "World") -> (Bool, String) let greeting = "hello \ (name)" return (true, salutation);  let (success, greeting) = sayHello () println ("sayHello a renvoyé succès: \ (succès) avec message d'accueil: \ (message d'accueil)"); // sortie // sayHello a renvoyé le succès: 1 avec salutation: hello World 

Tuples est sur la liste de souhaits de nombreux programmeurs Objective-C depuis longtemps.

Une autre fonctionnalité intéressante des tuples est que nous pouvons nommer les variables retournées. Si nous revoyons l'exemple précédent et donnons des noms aux variables du tuple, nous obtenons ce qui suit:

func sayHello (name: String = "World") -> (success: Bool, greeting: String) let greeting = "hello \ (name)" return (true, salutation);  let status = sayHello () println ("sayHello a renvoyé succès: \ (status.success) avec message d'accueil: \ (status.greeting)"); // sortie // sayHello a renvoyé le succès: 1 avec salutation: hello World 

Cela signifie qu'au lieu de définir une constante distincte pour chaque élément de retour d'un tuple, nous pouvons accéder aux éléments de tuple renvoyés à l'aide de la notation par points, comme indiqué dans l'exemple ci-dessus., status.success et status.greeting.

Fermetures

Les fermetures dans Swift sont les mêmes que les blocs dans Objective-C. Ils peuvent être définis inline, passés en paramètre ou renvoyés par des fonctions. Nous les utilisons exactement comme nous utiliserions des blocs dans Objective-C.

Définir les fermetures est également facile. En fait, une fonction est un cas particulier de fermeture. Il n’est donc pas étonnant que la définition d’une fermeture ressemble beaucoup à la définition d’une fonction.

Les fermetures sont un type de première classe, ce qui signifie qu'elles peuvent être passées et retournées par des fonctions comme tout autre type, tel que IntChaîneBool, etc. Les fermetures sont essentiellement des blocs de code qui peuvent être appelés ultérieurement et ont accès à la portée dans laquelle ils ont été définis..

Créer une fermeture sans nom est aussi simple que de mettre un bloc de code entre accolades. Les paramètres et le type de retour de la fermeture sont séparés du corps de la fermeture avec le dans mot-clé.

Disons que nous voulons définir une fermeture qui retourne vrai si un nombre est pair, alors la fermeture pourrait ressembler à:

let isEven = (number: Int) -> Bool dans let mod = number% 2 return (mod == 0)

le est même la fermeture prend un Int en tant que paramètre unique et renvoie un Bool. Le type de cette fermeture est (numéro: Int) -> Bool, ou (Int -> Bool) pour faire court. Nous pouvons appeler est même n'importe où dans notre code, tout comme nous invoquerions un bloc de code en Objective-C.

Pour passer une fermeture de ce type en tant que paramètre d'une fonction, nous utilisons le type de la fermeture dans la définition de la fonction:

let isEven = (number: Int) -> Bool dans let mod = number% 2; return (mod == 0);  func verifyIfEven (number: Int, vérificateur: (Int-> Bool)) -> Bool renvoyer le vérificateur (numéro);  verifyIfEven (12, isEven); // retourne true verifyIfEven (19, isEven); // retourne faux

Dans l'exemple ci-dessus, le vérifieur paramètre de la verifyIfEven la fonction est une fermeture que nous passons à la fonction.

3. Classes et structures

Des classes

Il est temps de parler de la pierre angulaire de la programmation orientée objet, les classes. Les classes, comme mentionné précédemment, sont définies dans un seul fichier d'implémentation avec un .rapide extension. Les déclarations de propriétés et les méthodes sont toutes définies dans ce fichier.

Nous créons une classe avec le classe mot-clé suivi du nom de la classe. L'implémentation de la classe est entourée d'une paire d'accolades. Comme en Objective-C, la convention de nommage des classes est d'utiliser la casse supérieure du chameau pour les noms de classe..

class Hotel // propriétés // fonctions

Pour créer une instance du Un hôtel classe nous écrivons:

soit h = hôtel ()

En Swift, pas besoin d'appeler init sur des objets comme init s'appelle automatiquement pour nous.

L'héritage de classe suit le même modèle qu'en Objective-C, une virgule sépare le nom de la classe et celui de sa super-classe. Dans l'exemple suivant, Un hôtel hérite de la BigHôtel classe.

classe BigHotel: Hôtel 

Comme en Objective-C, nous utilisons la notation pointée pour accéder aux propriétés d'un objet. Cependant, Swift utilise également la notation par points pour appeler des méthodes de classe et d'instance, comme vous pouvez le voir ci-dessous..

// Objective-C UIView * view = [[UIView alloc]] init]; [self.view addSubview: view]; // Swift let view = UIView () self.view.addSubview (view)

Propriétés

Une autre différence avec Objective-C est que Swift ne fait pas la distinction entre les variables d'instance (ivars) et les propriétés. Une variable d'instance est une propriété.

Déclarer une propriété revient à définir une variable ou une constante en utilisant le var et laisser mots clés. La seule différence est le contexte dans lequel elles sont définies, c'est-à-dire le contexte d'une classe.

hôtel de classe let rooms = 10 var fullRooms = 0

Dans l'exemple ci-dessus, pièces est une valeur immuable, une constante, définie sur dix et fullRooms est une variable avec une valeur initiale de 0, que nous pouvons changer plus tard. La règle est que les propriétés doivent être initialisées lorsqu'elles sont déclarées. La seule exception à cette règle concerne les optionnels, dont nous parlerons dans un instant.

Propriétés calculées

Le langage Swift définit également les propriétés calculées. Les propriétés calculées ne sont rien d'autre que des accesseurs sophistiqués qui ne stockent pas de valeur. Comme leur nom l'indique, ils sont calculés ou évalués à la volée.

Vous trouverez ci-dessous un exemple de propriété calculée. J'ai changé le pièces propriété à un var pour le reste de ces exemples. Vous découvrirez pourquoi plus tard.

classe Hôtel var rooms = 10 var fullRooms = 0 var description: String get return "Taille de l'hôtel: \ (chambres) capacité des chambres: \ (chambres pleines) / \ (chambres)"

Parce que le la description propriété est en lecture seule et a seulement un revenir déclaration, nous pouvons omettre le obtenir mot-clé et accolades, et ne gardez que le revenir déclaration. C'est un raccourci et c'est ce que je vais utiliser dans la suite de ce tutoriel..

classe Hôtel var rooms = 10 var fullRooms = 0 var description: String return "Taille de l'hôtel: \ (chambres) capacité des chambres: \ (fullRooms / \ (chambres)"

Nous pouvons également définir des propriétés calculées en lecture-écriture. Dans notre classe Un hôtel, nous voulons un chambres vides propriété qui obtient le nombre de chambres vides dans l'hôtel, mais nous souhaitons également mettre à jour fullRooms quand on met le chambres vides propriété calculée. Nous pouvons le faire en utilisant le ensemble mot clé comme indiqué ci-dessous.

class Hotel var rooms = 10 var fullRooms = 0 var description: String return "Taille de l'hôtel: \ (chambres) capacité des chambres: \ (fullRooms) / \ (chambres)" var emptyRooms: Int get return rooms - fullRooms set // la constante newValue est disponible ici // contenant la valeur transmise if (newValue < rooms)  fullRooms = rooms - newValue  else  fullRooms = rooms     let h = Hotel() h.emptyRooms = 3 h.description // Size of Hotel: 10 rooms capacity:7/10

dans le chambres vides poseur, le nouvelle valeur constante nous est remise et représente la valeur transmise au passeur. Il est également important de noter que les propriétés calculées sont toujours déclarées en tant que variables, en utilisant var mot-clé, car leur valeur calculée peut changer.

Les méthodes

Nous avons déjà couvert les fonctions plus haut dans cet article. Les méthodes ne sont rien de plus que des fonctions liées à un type, comme une classe. Dans l'exemple suivant, nous implémentons une méthode d'instance, bookNumberOfRooms, dans le Un hôtel classe que nous avons créée plus tôt.

class Hotel var rooms = 10 var fullRooms = 0 var description: String return "Taille de l'hôtel: \ (chambres) capacité des chambres: \ (fullRooms) / \ (chambres)" var emptyRooms: Int get return rooms - fullRooms set // la constante newValue est disponible ici // contenant la valeur transmise if (newValue < rooms)  fullRooms = rooms - newValue  else  fullRooms = rooms    func bookNumberOfRooms(room:Int = 1) -> Bool if (self.emptyRooms> room) self.fullRooms ++; return true else return false let h = Hotel () h.emptyRooms = 7 h.description // taille de l'hôtel: 10 chambres capacité: 3/10 h.bookNumberOfRooms (room: 2) // renvoie true h .description // Taille de l’hôtel: 10 chambres, capacité: 5/10 h.bookNumberOfRoom () // renvoie vrai h.description // Taille de l’hôtel: 10 chambres, capacité: 6/10 

Initialiseurs

L’initialiseur par défaut pour les classes est init. dans le init fonction, nous définissons les valeurs initiales de l'instance créée.

Par exemple, si nous avions besoin d’un Un hôtel sous-classe avec 100 chambres, alors nous aurions besoin d’un initialiseur pour régler la pièces propriété à 100. Rappelez-vous que j'ai déjà changé pièces d'être une constante d'être une variable dans le Un hôtel classe. La raison en est que nous ne pouvons pas changer les constantes héritées dans une sous-classe, seules les variables héritées peuvent être changées.

class BigHotel: Hôtel init () super.init () rooms = 100 let bh = BigHotel () println (bh.description); // taille de l'hôtel: capacité de 100 chambres: 0/100

Les initialiseurs peuvent également prendre des paramètres. L'exemple suivant vous montre comment cela fonctionne.

class CustomHotel: Hôtel init (taille: Int) super.init () chambres = taille soit c = CustomHotel (taille: 20) c.description // Taille de l’hôtel: 20 chambres, capacité: 0/20

Méthodes de substitution et propriétés calculées

C'est l'une des choses les plus cool à Swift. Dans Swift, une sous-classe peut remplacer les méthodes et les propriétés calculées. Pour ce faire, nous utilisons le passer outre mot-clé. Remplaçons le la description propriété calculée dans le CustomHotel classe:

class CustomHotel: Hotel init (size: Int) super.init () rooms = size remplace la description de la variable: String return super.description + "Howdy!"  let c = CustomHotel (taille: 20) c.description // taille de l'hôtel: 20 chambres capacité: 0/20 Howdy! 

Le résultat est que la description renvoie le résultat de la superclasse la description méthode avec la chaîne "Salut!" annexé.

Ce qui est bien avec les méthodes de substitution et les propriétés calculées est le passer outre mot-clé. Quand le compilateur voit le passer outre mot-clé, il vérifie si la superclasse de la classe implémente la méthode qui est remplacée. Le compilateur vérifie également si les propriétés et méthodes d'une classe sont en conflit avec les propriétés ou méthodes situées plus haut dans l'arbre d'héritage..

Je ne sais pas combien de fois une faute de frappe dans une méthode surchargée dans Objective-C m'a jeté au sort, car le code ne fonctionnait pas. Dans Swift, le compilateur vous dira exactement ce qui ne va pas dans ces situations.

Des structures

Structures, définies avec le struct mot-clé, sont plus puissants dans Swift que dans C et Objective-C. En C, les structures ne définissent que les valeurs et les pointeurs. Les structures Swift ressemblent aux structures C, mais elles supportent également les propriétés et les méthodes calculées.

Tout ce que vous pouvez faire avec une classe, vous pouvez le faire avec une structure, avec deux différences importantes:

  • les structures ne supportent pas l'héritage comme le font les classes
  • les structures sont transmises par valeur tandis que les classes sont transmises par référence

Voici quelques exemples de structures à Swift:

struct Rect var origine: Taille du point: Taille de la zone: Double return size.width * size.height func isBiggerThanRect (r: Rect) -> Bool return (self.area> r.area) struct Point var x = 0 var y = 0 taille de la structure var width = 0 var height = 0

4. Options

Solution à un problème

Les options sont un nouveau concept si vous venez d’Objective-C. Ils résolvent un problème auquel nous sommes tous confrontés en tant que programmeurs. Lorsque nous accédons à une variable dont nous ne sommes pas sûr de la valeur, nous renvoyons généralement un indicateur, appelé sentinelle, pour indiquer que la valeur renvoyée est une valeur nulle. Laissez-moi illustrer cela avec un exemple d'Objective-C:

NSString * someString = @ "ABCDEF"; NSInteger pos = [chaîne de chaînes de chaînes de caractères: @ "B"]. // pos = 1

Dans l'exemple ci-dessus, nous essayons de trouver la position de @ "B" dans un peu de corde. Si @ "B" est trouvé, son emplacement ou sa position est stocké dans pos. Mais qu'advient-il si @ "B" ne se trouve pas dans un peu de corde?

La documentation indique que rangeOfString: renvoie un NSRange avec emplacement mis à la NSNotFound constant. Dans le cas de rangeOfString:, la sentinelle est NSNotFound. Les sentinelles sont utilisées pour indiquer que la valeur renvoyée n'est pas valide.

Dans Cocoa, ce concept a de nombreuses utilisations, mais la valeur sentinelle diffère d’un contexte à l’autre., 0, -1, NUL, NSIntegerMax, INT_MAX, Néant, etc. Le problème pour la programmeuse est qu’elle doit se rappeler quelle sentinelle est utilisée dans quel contexte. Si le programmeur ne fait pas attention, il peut confondre une valeur valide pour une sentinelle et inversement. Swift résout ce problème avec les optionnels. Pour citer Brian Lanier, "Les optionnels sont la seule sentinelle pour les gouverner tous."

Les optionnels ont deux états, un néant state, ce qui signifie que l’option (optionnel) ne contient aucune valeur et un second état, ce qui signifie qu’elle contient une valeur valide. Pensez aux options comme un paquet avec un indicateur pour vous dire si le contenu du paquet est valide ou non..

Usage

Tous les types dans Swift peuvent devenir facultatifs. Nous définissons une option en ajoutant un ? après la déclaration de type comme suit:

laisser someInt: Int? // someInt == nil

Nous assignons une valeur à un paquet optionnel comme nous le faisons avec des constantes et des variables.

someInt = 10 // someInt! == 10

Rappelez-vous que les optionnels sont comme des paquets. Quand nous avons déclaré laissez someInt: Int?, nous avons défini une boîte vide avec une valeur de néant. En assignant la valeur dix optionnel, la case contient un entier égal à dix et son indicateur ou son état devient pas nul.

Pour accéder au contenu d’une option, nous utilisons le ! opérateur. Nous devons nous assurer que l’option (optionnel) a une valeur valide avant de la décompresser. Sinon, une erreur d'exécution sera générée. Voici comment nous accédons à la valeur stockée dans une option:

if (someInt! = nil) println ("someInt: \ (someInt!)") else println ("someInt n'a pas de valeur") // someInt: 10

Le modèle ci-dessus est si commun dans Swift que nous pouvons simplifier le bloc de code ci-dessus en utilisant reliure optionnelle avec le si laisse mots clés. Jetez un coup d'œil au bloc de code mis à jour ci-dessous.

si let value = someInt println ("someInt: \ (valeur)") else println ("someInt n'a pas de valeur")

Les optionnels sont le seul type pouvant prendre une néant valeur. Les constantes et les variables ne peuvent pas être initialisées ou définies sur néant. Cela fait partie de la politique de sécurité de Swift, toutes les variables et constantes non facultatives doit avoir une valeur.

5. Gestion de la mémoire

Si vous vous en souvenez, quand ARC a été introduit, nous utilisions le fort et faible mots-clés pour définir la propriété de l'objet. Swift a aussi un fort et faible modèle de propriété, mais il introduit également un nouveau, sans propriétaire. Jetons un coup d'oeil à chaque modèle de propriété d'objet dans Swift.

fort

Les références fortes sont les valeurs par défaut dans Swift. La plupart du temps, nous possédons l'objet que nous référençons et nous sommes responsables de la conservation de l'objet référencé..

Puisque les références fortes sont la valeur par défaut, il n'est pas nécessaire de conserver explicitement une référence forte à un objet. Toute référence est une référence forte..

faible

Une référence faible dans Swift indique que la référence pointe vers un objet que nous ne sommes pas responsables de maintenir en vie. Il est principalement utilisé entre deux objets qui n'ont pas besoin de l'autre pour rester en vie..

Il existe une mais, toutefois. Dans Swift, les références faibles doivent toujours être des variables de type facultatif, car elles sont définies sur néant lorsque l'objet référencé est désalloué. le faible mot-clé est utilisé pour déclarer une variable aussi faible:

faible vue var: UIView?

sans propriétaire

Les références non possédées sont nouvelles pour les programmeurs Objective-C. Une référence non possédée signifie que nous ne sommes pas responsables de maintenir en vie l'objet référencé, tout comme les références faibles.

La différence avec une référence faible est qu’une référence non possédée n’est pas définie sur néant lorsque l'objet auquel il fait référence est désalloué. Une autre différence importante avec les références faibles est que les références non possédées sont définies comme un type non facultatif..

Les références non possédées peuvent être des constantes. Un objet non possédé n'existe pas sans son propriétaire et par conséquent la référence non possédée n'est jamais néant. Les références non possédées ont besoin de sans propriétaire mot clé avant la définition de la variable ou constante.

vue var non propriétaire: UIView

Conclusion

Swift est une langue étonnante qui a beaucoup de profondeur et de potentiel. Il est amusant d'écrire des programmes avec et cela supprime une grande partie du code standard écrit en Objective-C pour garantir la sécurité de notre code..

Je recommande vivement le langage de programmation Swift, disponible gratuitement dans la boutique iBooks d'Apple..