Swift vs Objective

Le 2 juin 2014, Apple a dévoilé un tout nouveau langage de programmation orienté objet : Swift, un remplaçant pour Objective-C, qui était jusqu’alors le langage de programmation standard pour OS X et le développement d’applications iOS.

Ce fut un audacieux changement de langage de développement principal pour une plateforme aussi populaire ; malgré tout, notre équipe a accueilli cette nouvelle avec un grand enthousiasme et a décidé de passer à Swift rapidement. Et nous ne sommes pas les seuls : Swift a reçu des éloges pour sa simplicité et sa flexibilité, et son taux d’adoption a explosé.

Après avoir développé quelques applications iOS avec Swift, nous avons décidé de partager nos réflexions sur certaines des choses qui, selon nous, rendent la programmation plus facile et plus agréable. Voici donc notre liste des dix plus grandes et plus importantes différences entre Swift et Objective-C !

(N’hésitez pas à utiliser un playground pour vous entraîner avec les extraits de code de cet article. C’est toujours une bonne idée d’explorer de nouveaux langages et frameworks !)

Swift vs. Objective-C : 10 différences

1. Les optionnels

Les optionnels sont un concept qui n’existe pas en C ou en Objective-C. Ils permettent aux fonctions qui ne peuvent pas toujours retourner une valeur significative (par exemple, en cas d’entrée invalide) de retourner soit une valeur encapsulée dans un optionnel, soit nil. En C et Objective-C, on peut déjà retourner nil d’une fonction qui retournerait normalement un objet, mais nous n’avons pas cette option pour les fonctions censées retourner un type de base comme int, float ou double. Observez :

let a = "512"
let b = Int(a)
print(b) // Optional(512)

La fonction Int dans ce cas retourne un optionnel contenant la valeur entière 512, comme prévu. Mais que se passe-t-il si nous essayons de convertir quelque chose comme “Hello” à la place ? Dans ce cas, la fonction retournera nil, comme expliqué ci-dessus :

let a = "Hello"
let b = Int(a)
print(b) // nil

Comme vous le savez peut-être déjà, en Objective-C, si vous appelez une méthode sur un pointeur nil, rien ne se passe. Pas d’erreurs de compilation, pas d’erreurs d’exécution, rien. C’est une source bien connue de bugs et de comportements inattendus, et de frustration générale : le manque de feedback signifie que les développeurs sont obligés de chasser la source de ces erreurs par eux-mêmes.

Avec Swift, vous n’avez pas à vous soucier de cela :

var x = Int("555")
print(x.successor()) // error

Le compilateur lui-même lèvera une erreur, car x est actuellement un optionnel et pourrait potentiellement être nil. Avant d’utiliser une valeur optionnelle, vous devez la “déballer” (unwrap) comme ceci :

var x = Int("555")
if x != nil {
    print(x!.successor()) // 556
}

Alternativement, nous pouvons utiliser le “liaison optionnelle” (optional binding) :

var x = Int("555")
if var y = x {
    y += 445
    print(y) // 1000
}

2. Flux de contrôle

Quiconque a programmé en C ou dans un langage similaire au C connaît l’utilisation des accolades ({}) pour délimiter les blocs de code. En Swift, cependant, elles ne sont pas seulement une bonne idée : elles sont obligatoires !

if a < 5 {
    print("Something")
}

Cela provoquera une erreur de compilation en Swift !

if a < 5
print(“Something")

Contrairement à Objective-C, Swift traite les accolades comme obligatoires pour les instructions if, for, while et repeat. Cela ne semble peut-être pas une amélioration par rapport à Objective-C en soi, mais considérez que même les propres développeurs d’Apple ont eu des problèmes sans les accolades pour les maintenir en ligne :

if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;

C’est exact : le tristement célèbre bug “goto fail” d’iOS aurait pu être évité si Objective-C avait été aussi strict que Swift sur l’application des accolades !

3. Inférence de type

Swift introduit la sécurité des types (type safety) dans le développement iOS. Une fois qu’une variable est déclarée avec un type particulier, son type est statique et ne peut pas être modifié. Le compilateur est également suffisamment intelligent pour déterminer (ou inférer) le type de vos variables en fonction des valeurs que vous leur assignez :

var str = "Some string"
// OU
var str2:String
str2 = "Other string"

Cela signifie également que le compilateur lèvera une erreur si vous essayez d’assigner une valeur numérique, comme 10, à notre variable str2 :

str2 = 10 // error: Cannot assign value of type 'Int' to type 'String'

Comparez avec Objective-C, où vous devez toujours spécifier explicitement le type d’une variable :

NSString str = @"There is no type inference in Objective-C :("

4. Tuples

Swift prend en charge les tuples, des valeurs qui stockent des groupes d’autres valeurs. Contrairement aux tableaux, les valeurs d’un tuple n’ont pas besoin d’être toutes du même type. Par exemple, vous pouvez avoir un tuple de String et d’Int :

var t:(String, Int) = ("John", 33)
print(t.0, t.1)
var j:(name:String, Int) = ("Morgan", 52)
print(j.name, j.1)

L’utilisation la plus évidente des tuples est de retourner plusieurs valeurs d’une fonction :

var arr = [23, 5, 7, 33, 9]

func findPosition(el:Int, arr:[Int]) -> (found:Bool, position:Int)? {
    if arr.isEmpty {
        return nil
    }

    for (i, value) in arr.enumerate() {
        if value == el {
            return (true, i)
        }
    }
    return (false, -1)
}

if let (isFound, elPosition) = findPosition(5, arr: arr) {
    print(isFound, elPosition)
    // true 1
}

En Objective-C, on peut utiliser des blocs de manière similaire, mais ce n’est pas aussi direct ou élégant.

5. Manipulation de chaînes de caractères

Swift offre d’énormes améliorations par rapport à Objective-C en matière de manipulation de chaînes de caractères. Pour commencer, vous n’avez plus à vous soucier des chaînes mutables vs immuables : déclarez simplement votre chaîne avec var si vous souhaitez la modifier plus tard, ou avec let si vous avez besoin qu’elle reste constante.

La concaténation de chaînes est aussi simple que 1+1=2 :

// Swift:
var str = "My string"
str += " and another string”

Comparez avec Objective-C, où la concaténation de deux chaînes immuables nécessite la création d’un nouvel objet NSString. Voici un exemple utilisant la méthode “stringWithFormat” :

// Obj-C:
NSString *myString = @"My string";
myString = [NSString stringWithFormat:@"%@ and another string", myString];

Comme vous pouvez le voir ici, le formatage des chaînes en Objective-C implique l’insertion de marqueurs spéciaux pour chaque type de données différent que nous voulons interpoler dans notre chaîne :

NSString *str = [NSString stringWithFormat:@"String: %@ | Signed 32-bit integer: %d | 64-bit floating-point number: %f", @"My String", myInt, myFloat];

En Swift, nous pouvons plutôt interpoler des valeurs en insérant directement les noms des variables dans notre chaîne :

var str = "String: (myString) | Signed 32-bit integer: (myInt) | 64-bit floating-point number: (myFloat)"

6. Guard et Defer

Avez-vous déjà entendu parler de la “pyramide de la mort” ? Sinon, voici un extrait de code Objective-C qui devrait vous rafraîchir la mémoire :

enum TriangleAreaCalcError: ErrorType {
    case AngleNotSpecified
    case InvalidAngle
    case SideANotSpecified
    case SideBNotSpecified
}

func calcTriangleArea(a: Double ? , b : Double ? , alpha : Double ? ) throws - > Double {
    if let a = a {
        if let b = b {
            if let alpha = alpha {
                if alpha < 180 && alpha >= 0 {
                    if alpha == 180 {
                        return 0
                    }
                    return 0.5 * a * b * sin(alpha * M_PI / 180.0)
                } else {
                    throw TriangleAreaCalcError.InvalidAngle
                }
            } else {
                throw TriangleAreaCalcError.AngleNotSpecified
            }
        } else {
            throw TriangleAreaCalcError.SideBNotSpecified
        }
    } else {
        throw TriangleAreaCalcError.SideANotSpecified
    }
}

Voilà une pyramide qui ferait cligner des yeux même Indiana Jones ! Heureusement, en Swift, nous avons guard, une nouvelle instruction conditionnelle qui peut rendre ce code beaucoup plus lisible. Guard arrête le flux du programme si une condition n’est pas remplie :

func calcTriangleArea(a: Double ? , b : Double ? , alpha : Double ? ) throws - > Double {

    guard
    let a = a
    else {
        throw TriangleAreaCalcError.SideANotSpecified
    }

    guard
    let b = b
    else {
        throw TriangleAreaCalcError.SideBNotSpecified
    }

    guard
    let alpha = alpha
    else {
        throw TriangleAreaCalcError.AngleNotSpecified
    }

    if alpha == 180 {
        return Double(0)
    }

    guard alpha < 180 && alpha >= 0
    else {
        throw TriangleAreaCalcError.InvalidAngle
    }

    return 0.5 * a * b * sin(alpha * M_PI / 180.0)
}

Swift nous donne également le mot-clé defer, qui offre un moyen sûr et facile de gérer le code que nous voulons exécuter uniquement lorsque le programme quitte la portée actuelle :

func someImageFunc() - > UIImage ? {

    let dataSize: Int = ...
    let destData = UnsafeMutablePointer < UInt8 > .alloc(dataSize)

    // ...

    guard error
    else {
        destData.dealloc(dataSize) // #1
        return nil
    }

    guard error2
    else {
        destData.dealloc(dataSize) // #2
        return nil
    }

    guard error3
    else {
        destData.dealloc(dataSize) // #3
        return nil
    }

    destData.dealloc(dataSize) // #4

    // ...
}

Comme vous pouvez le constater, nous devons écrire quatre appels séparés à destData.dealloc(dataSize) pour nous assurer que notre pointeur est désalloué, même si guard fait sortir la fonction en cas d’erreur. Avec defer, nous avons un moyen sans tracas de nettoyer à la fois notre pointeur et notre code :

func someImageFunc() - > UIImage ? {

    let dataSize: Int = ...
    let destData = UnsafeMutablePointer < UInt8 > .alloc(dataSize)

    // ...

    defer {
        destData.dealloc(dataSize)
    }

    guard error
    else {
        return nil
    }

    guard error2
    else {
        return nil
    }

    guard error3
    else {
        return nil
    }

    // ...
}

7. Modèles de programmation fonctionnelle

Swift intègre un certain nombre de fonctionnalités de programmation fonctionnelle, telles que map et filter, qui peuvent être utilisées sur toute collection implémentant le protocole CollectionType :

let a = [4, 8, 16]
print(a.map{$0 / 2})
// [2, 4, 8]

let a:[(name:String, area:String)] = [("John", "iOS"), ("Sam", "Android"), ("Paul", "Web")]

let b = a.map({"Developer ($0.name) (($0.area))"})
// ["Developer John (iOS)", "Developer Sam (Android)", "Developer Paul (Web)”]

let a = [23, 5, 7, 12, 10]
let b = a.filter{$0 > 10}
print(b) // [23, 12]

let sum = (20...30)
.filter { $0 % 2 != 0 }
.map { $0 * 2 }
.reduce(0) { $0 + $1 }

print(sum) // 250

Objective-C n’a pas de support intégré pour la programmation fonctionnelle. Pour utiliser ces mêmes types de fonctions, vous devriez utiliser une bibliothèque tierce.

8. Énumérations

En Swift, les énumérations sont plus puissantes qu’elles ne l’ont jamais été en Objective-C : elles peuvent désormais contenir des méthodes et être passées par valeur. Voici un petit extrait de code qui illustre bien le fonctionnement des énumérations en Swift :

enum Location {
    case Address(city: String, street: String)
    case Coordinates(lat: Float, lon: Float)

    func printOut() {
        switch self {
            case let.Address(city, street):
            print("Address: " + street + ", " + city)
            case let.Coordinates(lat, lon):
            print("Coordiantes: ((lat), (lon))")
        }
    }
}

let loc1 = Location.Address(city: "Boston", street: "33 Court St")
let loc2 = Location.Coordinates(lat: 42.3586, lon: -71.0590)

loc1.printOut() // Address: 33 Court St, Boston
loc2.printOut() // Coordiantes: (42.3586, -71.059)

Les énumérations peuvent également être récursives, nous pouvons donc construire une liste chaînée en utilisant l’instruction indirect, qui indique au compilateur d’ajouter la couche d’indirection nécessaire :

enum List {
    case Empty
    indirect
    case Cell(value: Int, next: List)
}

let list0 = List.Cell(value: 1, next: List.Empty)
let list1 = List.Cell(value: 4, next: list0)
let list2 = List.Cell(value: 2, next: list1)
let list3 = List.Cell(value: 6, next: list2)
let headL = List.Cell(value: 3, next: list3)

func evaluateList(list: List) - > Int {
    switch list {
        case let.Cell(value, next):
        return value + evaluateList(next)
        case .Empty:
        return 0
    }
}

print(evaluateList(headL)) // 16

9. Fonctions

La syntaxe des fonctions de Swift est suffisamment flexible pour définir tout, d’une simple fonction de style C à une méthode complexe de style Objective-C avec des noms de paramètres locaux et externes.

Chaque fonction en Swift a un type, qui se compose des types de paramètres et du type de retour de la fonction. Cela signifie que vous pouvez assigner des fonctions à des variables ou les passer comme paramètres à d’autres fonctions :

func stringCharactersCount(s: String) - > Int {
    return s.characters.count
}

func stringToInt(s: String) - > Int {
    if let x = Int(s) {
        return x
    }
    return 0
}

func executeSuccessor(f: String - > Int, s: String) - > Int {
    return f(s).successor()
}

let f1 = stringCharactersCount
let f2 = stringToInt

executeSuccessor(f1, s: "5555") // 5
executeSuccessor(f2, s: "5555") // 5556

Swift vous permet également de définir des valeurs par défaut pour les paramètres de fonction :

func myFunction(someInt: Int = 5) {
    // Si aucun argument n'est passé, la valeur de someInt est 5
}
myFunction(6) // someInt est 6
myFunction() // someInt est 5

10. Instruction Do

L’instruction do en Swift vous permet d’introduire une nouvelle portée :

let a = "Yes"

do {
    let a = "No"
    print(a) // No
}

print(a) // Yes

Les instructions Do peuvent également contenir une ou plusieurs clauses catch :

do {
    try expression
    statements
} catch pattern 1 {
    statements
} catch pattern 2 where condition {
    statements
}

Pour plus d’informations, veuillez vous référer à la documentation officielle de Swift pour l’instruction do.

Conclusion

Nous sommes fermement convaincus que Swift est l’avenir du développement iOS, et avec sa nature open source et sa popularité croissante, nous pouvons nous attendre à le voir utilisé sur d’autres plateformes à l’avenir.

L’une de ses fonctionnalités les plus prometteuses est ce qu’Apple appelle la Programmation Orientée Protocole (Protocol-Oriented Programming), un paradigme qui pourrait avoir un impact énorme sur le développement logiciel à l’avenir. En Swift, les protocoles (ou “Interfaces” dans des langages comme C#) peuvent être implémentés non seulement par des classes, mais aussi par des énumérations et des structs ; de plus, ils offrent une alternative élégante et sans confusion à l’héritage multiple, car un seul objet peut implémenter plusieurs protocoles.

Avec sa syntaxe légère et flexible et ses nombreuses fonctionnalités pour se prémunir contre les erreurs de codage courantes, Swift est tout simplement un plaisir à programmer. Essayez-le vous-même – vous serez presque certain d’être d’accord. Un bon endroit pour commencer est la documentation officielle (et assez complète) d’Apple pour le langage.

À propos de Redwerk

Fondée en 2005, Redwerk a eu amplement le temps de s’exercer au développement de jeux iOS, d’applications, de solutions d’e-gouvernement et de médias locaux, etc.

Parmi les projets les plus stimulants qui nous ont permis d’acquérir et de tester notre expérience en développement iOS, on peut citer :

School Observation App. Une solution parfaite pour les superviseurs scolaires. Le développement de cette application a été commandé par The Education Partners car ils avaient besoin d’enregistrer leurs notes sur les enseignants, les élèves et l’école elle-même rapidement et facilement, aussi bien en ligne qu’hors ligne. Grâce à notre expérience précédente, Redwerk a été en mesure de livrer un prototype simple et convivial en un temps record et de passer rapidement à l’implémentation de l’application. Dès le départ, la performance a été un objectif clé, car l’application était censée gérer une quantité massive de médias. Il ne nous a fallu que trois mois pour développer et lancer une application d’observation scolaire qui, nous l’espérons, aidera The Education Partners à maintenir les normes éducatives au plus haut niveau.

Local Media Mobile Apps. Redwerk a assuré la maintenance à long terme de la majorité des applications d’actualités locales iOS de Worldnow. Notre routine quotidienne consistait à résoudre un certain nombre de problèmes, tels que les problèmes de chargement des flux d’actualités, le contenu dupliqué et les échecs de mise à jour des rapports météorologiques. Nous avons également travaillé à l’ajout de nouveaux blocs et fonctionnalités d’application et à la modification de ceux existants en fonction des besoins actuels des utilisateurs.

YouTown. Notre équipe a été mandatée pour concevoir et développer de zéro une application mobile qui connecterait les citoyens américains à leurs autorités locales et fournirait des informations à jour sur la ville à tout moment. Redwerk est fier de dire qu’il ne nous a fallu que trois mois pour livrer les premières bêtas entièrement fonctionnelles d’une interface web pour les représentants du gouvernement et d’une application mobile pour les utilisateurs finaux. Finalement, l’application a gagné en popularité dans plus de 20 villes aux États-Unis et à l’étranger, et a été finalement acquise par une société tierce.

Outre le développement d’applications externalisé, nous contribuons beaucoup à des projets internes. En observant la suprématie des élections présidentielles américaines de 2016, nous avons décidé de saisir cette opportunité pour améliorer nos compétences en développement de jeux multijoueurs avec Unity. Ni une ni deux, en seulement 6 mois, une équipe de deux développeurs a livré Electoral.io, un jeu dynamique multiplateforme disponible en versions Android, iOS et navigateur.

Comme tout autre client, soyez assuré qu’une équipe de développeurs hautement qualifiés et des gestionnaires efficaces feront de leur mieux pour livrer votre projet à temps et au plus haut niveau possible.
N’hésitez pas à externaliser le développement iOS à Redwerk, car nous avons suffisamment d’expérience pour satisfaire toutes vos exigences.

Découvrez comment nous avons développé une application de type Uber pour tuteurs en utilisant Swift comme technologie principale

Veuillez saisir votre adresse courriel professionnelle n'est pas un courriel professionnel
Section image

Nos développeurs sont également experts en

Développement C et C++

 

Développement logiciel C#

 

Développement Microsoft Windows

 

Développement ASP.NET

 

Développement de jeux HTML5