Sous-classe UIApplication avec Swift

92

En Objective C c'était simple: il suffisait de mettre à jour le fichier main.m et de changer les paramètres UIApplicationMain ()

return UIApplicationMain(argc, argv, NSStringFromClass([CustomUIApplication class]), NSStringFromClass([AppDelegate class]));

Mais dans Swift, il n'y a pas de fichier main.m, puisque le guide dit

"Le code écrit à portée globale est utilisé comme point d'entrée pour le programme, vous n'avez donc pas besoin d'une fonction principale."

Alors, comment sous-classer UIApplication dans Swift ?? Toute suggestion?

LombaX
la source
1
Pourquoi serait-il préférable de modifier les UIApplicationMain()paramètres, plutôt que d'ajouter le nom de la classe ci-dessous NSPrincipalClassdans le fichier app-info.plist?
Andreas

Réponses:

173

NOTE la syntaxe a été mis à jour pour Xcode 10.1 et Swift 5 en juin 2019 (crédits à la réponse de mat ici && réponse de Tung Fam ici ), si vous recherchez les syntaxes précédentes regardez la section d'édition.

Ok, j'ai trouvé la solution

Tout d'abord, j'ai remarqué qu'en haut du fichier AppDelegate.swift, il y a cette ligne

@UIApplicationMain

Puisque cette ligne est en dehors de toute portée (elle est au niveau du fichier), elle est exécutée immédiatement, et je suppose que le compilateur la traduit en une fonction principale standard.

Donc, j'ai fait cela, à partir d'une nouvelle application Swift-Only:

  • commenté @UIApplicationMain
  • ajouté un fichier main.swift comme celui-ci (FLApplication est ma sous-classe).
    IMPORTANT, le fichier DOIT ÊTRE NOMMÉ main.swift, car les instructions de niveau supérieur ne sont pas prises en charge sur les autres fichiers! Vous ne pouvez pas ajouter l'appel UIApplicationMain () dans un autre fichier, sinon vous recevrez cette erreur:

Les expressions ne sont pas autorisées au niveau supérieur

Ceci est le fichier main.swift

UIApplicationMain(
    CommandLine.argc, CommandLine.unsafeArgv, 
    NSStringFromClass(FLApplication.self), NSStringFromClass(AppDelegate.self)
)

Ensuite, créez un fichier swift pour la sous-classe UIApplication, FLApplication.swift, avec ce code:

import UIKit
import Foundation

class FLApplication: UIApplication {
    override func sendEvent(_ event: UIEvent) {
        super.sendEvent(event)
        print("send event")
    }
}

maintenant, UIApplication est correctement sous-classée et vous verrez les messages "envoyer l'événement" dans le journal


ANCIENNES MODIFICATIONS
Pour référence, puisque cela a beaucoup changé de la version 1 à la version 3, je laisse ici toutes les modifications précédentes


EDIT - MARS 2015

Comme l'a commenté Hu Junfeng maintenant, les explications sur UIApplicationMainet le fichier main.swift sont documentées dans la section Attributs de The Swift Language Reference: Link

Comme l'a commenté Thomas Verbeek Dans la version bêta de XCode 6.3, vous constaterez peut-être que C_ARGC et C_ARGV ont été renommés respectivement Process.argc et Process.unsafeArgv. Votre appel UIApplicationMain dans le fichier main.swift devra être mis à jour pour:

UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(FLApplication), NSStringFromClass(AppDelegate))

La syntaxe pré-XCode 8 était

import Foundation
import UIKit

UIApplicationMain(C_ARGC, C_ARGV, NSStringFromClass(FLApplication), NSStringFromClass(AppDelegate))

EDIT - DÉC 2016

Solution pour Xcode 8, avant la bêta 6

import Foundation
import UIKit

UIApplicationMain(
    CommandLine.argc,
    UnsafeMutableRawPointer(CommandLine.unsafeArgv)
        .bindMemory( 
            to: UnsafeMutablePointer<Int8>.self, 
            capacity: Int(CommandLine.argc)),
    NSStringFromClass(FLApplication.self),
    NSStringFromClass(AppDelegate.self)
)
LombaX
la source
J'essaie de comprendre s'il est possible d'appeler UIApplicationMain () directement dans le fichier AppDelegate.swift, car il semble qu'il existe une "version rapide" de cette méthode, mais j'ai une erreur de compilation, je vais faire quelques tests recherche d'une solution "rapide uniquement"
LombaX
Incroyablement cool. Je suis curieux de savoir quel est le cas d'utilisation de la substitution de sendEvent:nos jours (je me souviens avoir dû le faire dans iOS 3 ...)
mat
2
Au cas où quelqu'un voudrait savoir, UIApplicationMainet main.swiftsont documentés dans la section Attributs de The Swift Language Reference. developer.apple.com/library/ios/documentation/Swift/Conceptual/…
hujunfeng
Merci pour l'indice, je suis sûr à 99% que dans la première version du manuel Swift, il n'était pas documenté :-) cependant je mettrai à jour la réponse en ajoutant vos informations.
LombaX
5
Très bonne réponse. Dans la version bêta de XCode 6.3, vous pourriez trouver cela C_ARGCet C_ARGVavoir été renommé respectivement en Process.argcet Process.unsafeArgv. Votre appel UIApplicationMain dans le fichier main.swift devra être mis à jour versUIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(KBApplication), NSStringFromClass(AppDelegate))
Thomas Verbeek
4

Une alternative est de l'étendre UIApplicationau lieu de le sous-classer. Selon l' iBook publié par Apple, les extensions dans Swift peuvent:

Ajouter des propriétés calculées et des propriétés statiques calculées Définir des méthodes d'instance et des méthodes de type Fournir de nouveaux initialiseurs Définir des indices Définir et utiliser de nouveaux types imbriqués Rendre un type existant conforme à un protocole

Extrait de: Apple Inc. «Le langage de programmation Swift.

Si vos besoins en sous UIApplication- classification sont satisfaits par ces capacités, une extension peut être la solution.

Cezar
la source
5
bon conseil - pas de réponse à mon humble avis :)
Daij-Djan
1
  1. Créez une sous-classe de UIApplicationet ajoutez votre logique

    import UIKit
    
    class CustomUIApplication: UIApplication {
        override func sendEvent(_ event: UIEvent) {
            super.sendEvent(event)
        }
    }
  2. Créez un main.swiftfichier qui appelle la UIApplicationMain()fonction globale [About] , qui est le nouveau point d'entrée de votre application qui est appelé par le système d'exploitation. Cette fonction reçoit l'argument de la fonction appelée, du UIApplicationnom de la UIApplicationDelegateclasse, du nom de la classe et démarre la boucle d'exécution principale.

    import UIKit
    
    UIApplicationMain(
        CommandLine.argc,
        CommandLine.unsafeArgv,
    
        NSStringFromClass(CustomUIApplication.self), //was created at step 1
        NSStringFromClass(AppDelegate.self)
    )
  3. Supprimez / commentez l' @UIApplicationMainannotation par défaut AppDelegate.

    @UIApplicationMaingénère main.swift.

    Si vous ne le faites pas, vous obtiendrez une erreur de compilation:

    UIApplicationMain l'attribut ne peut pas être utilisé dans un module contenant du code de niveau supérieur

    //@UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        //...
    }
yoAlex5
la source