Aplicação de subclasse UIA com Swift

91

Em Objective C era simples: bastava atualizar o arquivo main.m e alterar os parâmetros UIApplicationMain ()

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

Mas no swift não há arquivo main.m, já que o guia diz

“O código escrito em escopo global é usado como ponto de entrada para o programa, então você não precisa de uma função principal.”

Então, como criar uma subclasse de UIApplication em swift ?? Alguma sugestão?

LombaX
fonte
1
Por que seria preferível alterar os UIApplicationMain()parâmetros, em vez de adicionar o nome da classe NSPrincipalClassem app-info.plist?
Andreas,

Respostas:

172

NOTA a sintaxe foi atualizado para XCode 10.1 e Swift 5 em junho de 2019 (créditos a resposta de Matt aqui && resposta de Tung Fam aqui ), se você está procurando as sintaxes anteriores olhar para a seção de edição.

Ok, eu encontrei a solução

Primeiro, notei que, no topo do arquivo AppDelegate.swift, há esta linha

@UIApplicationMain

Como essa linha está fora de qualquer escopo (está no nível do arquivo), ela é executada imediatamente e suponho que o compilador a traduza em uma função principal padrão.

Então, eu fiz isso, começando com um novo aplicativo apenas para Swift:

  • comentado @UIApplicationMain
  • adicionei um arquivo main.swift como este (FLApplication é minha subclasse).
    IMPORTANTE o arquivo DEVE SER NOMEADO main.swift, uma vez que as instruções de nível superior não são suportadas em outros arquivos! Você não pode adicionar a chamada UIApplicationMain () dentro de qualquer outro arquivo, caso contrário, receberá este erro:

Expressões não são permitidas no nível superior

Este é o arquivo main.swift

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

Em seguida, crie um arquivo swift para a subclasse UIApplication, FLApplication.swift, com este código:

import UIKit
import Foundation

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

agora, UIApplication tem uma subclasse correta e você verá as mensagens de "evento de envio" no log


EDIÇÕES ANTIGAS
Para referência, já que isso mudou muito da versão 1 para a versão 3, deixo aqui todas as edições anteriores


EDITAR - MARÇO 2015

Conforme comentado por Hu Junfeng agora, as explicações sobre UIApplicationMaino arquivo main.swift estão documentadas na seção Atributos da Referência da Linguagem Swift: Link

Conforme comentado por Thomas Verbeek No XCode 6.3 Beta, você pode descobrir que C_ARGC e C_ARGV foram renomeados para Process.argc e Process.unsafeArgv respectivamente. Sua chamada UIApplicationMain no arquivo main.swift precisará ser atualizada para:

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

A sintaxe pré-XCode 8 era

import Foundation
import UIKit

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

EDITAR - DEZ 2016

Solução para Xcode 8, antes do 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
fonte
Estou tentando entender se é possível chamar UIApplicationMain () diretamente no arquivo AppDelegate.swift, pois parece que existe uma "versão rápida" deste método, mas tenho um erro do compilador, farei alguns testes em busca de uma solução "apenas rápida"
LombaX
Incrivelmente legal. Estou curioso para saber qual é o caso de uso para substituir sendEvent:hoje em dia (lembro-me de ter que fazer isso no iOS 3 ...)
matt
2
Caso alguém queira saber, UIApplicationMaine main.swiftestão documentados na seção Atributos do The Swift Language Reference. developer.apple.com/library/ios/documentation/Swift/Conceptual/…
hujunfeng
Obrigado pela dica, tenho 99% de certeza que na primeira versão do manual do Swift isso não foi documentado :-) no entanto, irei atualizar a resposta adicionando suas informações.
LombaX,
5
Ótima resposta. No XCode 6.3 Beta, você pode descobrir que C_ARGCe C_ARGVfoi renomeado para Process.argce Process.unsafeArgvrespectivamente. Sua chamada UIApplicationMain no arquivo main.swift precisará ser atualizada paraUIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(KBApplication), NSStringFromClass(AppDelegate))
Thomas Verbeek
4

Uma alternativa é estender em UIApplicationvez de subclassificá-lo. De acordo com o iBook lançado pela Apple, as extensões em Swift podem:

Adicionar propriedades computadas e propriedades estáticas computadas Definir métodos de instância e métodos de tipo Fornecer novos inicializadores Definir subscritos Definir e usar novos tipos aninhados Tornar um tipo existente em conformidade com um protocolo

Trecho de: Apple Inc. “The Swift Programming Language.

Se suas necessidades de subclasse UIApplicationforem satisfeitas por esses recursos, uma extensão pode ser o caminho a percorrer.

Cezar
fonte
5
bom conselho - não responda imho :)
Daij-Djan
1
  1. Crie uma subclasse de UIApplicatione adicione sua lógica

    import UIKit
    
    class CustomUIApplication: UIApplication {
        override func sendEvent(_ event: UIEvent) {
            super.sendEvent(event)
        }
    }
  2. Crie um main.swiftarquivo que chame a UIApplicationMain()função global [Sobre] , que é o novo ponto de entrada de seu aplicativo que é chamado pelo SO. Esta função recebe o argumento da função chamada, UIApplicationnome da UIApplicationDelegateclasse , nome da classe e inicia o loop de execução principal.

    import UIKit
    
    UIApplicationMain(
        CommandLine.argc,
        CommandLine.unsafeArgv,
    
        NSStringFromClass(CustomUIApplication.self), //was created at step 1
        NSStringFromClass(AppDelegate.self)
    )
  3. Remova / comente a @UIApplicationMainanotação no padrão AppDelegate.

    @UIApplicationMaingera main.swift.

    Do contrário, você receberá um erro de compilação:

    UIApplicationMain atributo não pode ser usado em um módulo que contém código de nível superior

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