Aplicación de UIA de subclase con Swift

92

En Objective C era simple: era suficiente actualizar el archivo main.m y cambiar los parámetros UIApplicationMain ()

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

Pero en swift no hay un archivo main.m, ya que la guía dice

"El código escrito en el ámbito global se utiliza como punto de entrada para el programa, por lo que no necesita una función principal".

Entonces, ¿cómo subclase UIApplication en swift? ¿Cualquier sugerencia?

LombaX
fuente
1
¿Por qué sería preferible cambiar los UIApplicationMain()parámetros a agregar el nombre de la clase NSPrincipalClassen la aplicación-info.plist?
Andreas

Respuestas:

173

NOTA: la sintaxis se ha actualizado para XCode 10.1 y Swift 5 en junio de 2019 (créditos a la respuesta de Matt aquí y la respuesta de Tung Fam aquí ), si está buscando las sintaxis anteriores, consulte la sección de edición.

Ok, encontré la solución

Primero, me di cuenta de que, en la parte superior del archivo AppDelegate.swift, hay esta línea

@UIApplicationMain

Dado que esta línea está fuera de cualquier alcance (está a nivel de archivo), se ejecuta de inmediato y supongo que el compilador la traduce en una función principal estándar.

Entonces, hice esto, comenzando desde una nueva aplicación Swift-Only:

  • Comentado @UIApplicationMain
  • agregó un archivo main.swift como este (FLApplication es mi subclase).
    IMPORTANTE el archivo DEBE SER NOMBRADO main.swift, ya que las declaraciones de nivel superior no son compatibles con otros archivos. No puede agregar la llamada UIApplicationMain () dentro de ningún otro archivo, de lo contrario, recibirá este error:

No se permiten expresiones en el nivel superior

Este es el archivo main.swift

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

Luego, cree un archivo rápido para la subclase UIApplication, FLApplication.swift, con este código:

import UIKit
import Foundation

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

ahora, UIApplication se subclasifica correctamente y verá los mensajes "enviar evento" en el registro


EDICIONES ANTIGUAS
Como referencia, dado que esto ha cambiado mucho de la versión 1 a la versión 3, dejo aquí todas las ediciones anteriores


EDITAR - MARZO 2015

Como comentó Hu Junfeng, ahora las explicaciones sobre UIApplicationMainel archivo main.swift están documentadas en la sección Atributos de The Swift Language Reference: Enlace

Como comentó Thomas Verbeek en XCode 6.3 Beta, puede encontrar que C_ARGC y C_ARGV han sido renombrados como Process.argc y Process.unsafeArgv respectivamente. Su llamada UIApplicationMain en el archivo main.swift deberá actualizarse a:

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

La sintaxis anterior a XCode 8 era

import Foundation
import UIKit

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

EDITAR - DIC 2016

Solución para Xcode 8, antes de beta 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
fuente
Estoy tratando de entender si es posible llamar a UIApplicationMain () directamente en el archivo AppDelegate.swift, ya que parece que hay una "versión rápida" de este método, pero tengo un error del compilador, haré algunas pruebas buscando una solución "solo rápida"
LombaX
Increíblemente genial. Tengo curiosidad por saber cuál es el caso de uso para anular sendEvent:hoy en día (recuerdo tener que hacerlo en iOS 3 ...)
Matt
2
En caso de que alguien quiera saberlo, UIApplicationMainya main.swiftestá documentado en la sección Atributos de The Swift Language Reference. developer.apple.com/library/ios/documentation/Swift/Conceptual/…
hujunfeng
Gracias por la pista, estoy 99% seguro de que en la primera versión del manual de Swift no estaba documentado :-) sin embargo, actualizaré la respuesta agregando su información.
LombaX
5
Gran respuesta. En XCode 6.3 Beta, es posible que encuentre eso C_ARGCy C_ARGVse le haya cambiado el nombre a Process.argcy Process.unsafeArgvrespectivamente. Su llamada UIApplicationMain en el archivo main.swift deberá actualizarse aUIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(KBApplication), NSStringFromClass(AppDelegate))
Thomas Verbeek
4

Una alternativa es extenderlo en UIApplicationlugar de subclasificarlo. Según el iBook lanzado por Apple, las extensiones en Swift pueden:

Agregar propiedades calculadas y propiedades estáticas calculadas Definir métodos de instancia y métodos de tipo Proporcionar nuevos inicializadores Definir subíndices Definir y usar nuevos tipos anidados Hacer que un tipo existente se ajuste a un protocolo

Extracto de: Apple Inc. “El lenguaje de programación Swift.

Si sus necesidades en subclases UIApplicationse satisfacen con esas capacidades, una extensión podría ser el camino a seguir.

Cezar
fuente
5
buen consejo - no respondo en mi humilde opinión :)
Daij-Djan
1
  1. Crea una subclase de UIApplicationy agrega tu lógica

    import UIKit
    
    class CustomUIApplication: UIApplication {
        override func sendEvent(_ event: UIEvent) {
            super.sendEvent(event)
        }
    }
  2. Cree un main.swiftarchivo que llame a la UIApplicationMain()función global [Acerca de] , que es el nuevo punto de entrada de su aplicación a la que llama el sistema operativo. Esta función recibe el argumento de la función llamada, el UIApplicationnombre de la UIApplicationDelegateclase , el nombre de la clase e inicia el ciclo de ejecución principal.

    import UIKit
    
    UIApplicationMain(
        CommandLine.argc,
        CommandLine.unsafeArgv,
    
        NSStringFromClass(CustomUIApplication.self), //was created at step 1
        NSStringFromClass(AppDelegate.self)
    )
  3. Eliminar / comentar la @UIApplicationMainanotación por defecto AppDelegate.

    @UIApplicationMain genera main.swift .

    Si no lo hace, obtendrá un error de compilación:

    UIApplicationMain El atributo no se puede usar en un módulo que contiene código de nivel superior

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