Podklasa UIApplication w języku Swift

92

W celu C było to proste: wystarczyło zaktualizować plik main.m i zmienić parametry UIApplicationMain ()

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

Ale szybko nie ma pliku main.m, jak mówi przewodnik

„Kod napisany w zakresie globalnym jest używany jako punkt wejścia do programu, więc nie potrzebujesz funkcji głównej”.

Jak więc podklasować UIApplication w szybki? Jakieś sugestie?

LombaX
źródło
1
Dlaczego lepsza byłaby zmiana UIApplicationMain()parametrów, niż dodanie nazwy klasy NSPrincipalClassw app-info.plist?
Andreas

Odpowiedzi:

173

UWAGA składnia została zaktualizowana dla XCode 10.1 i Swift 5 w czerwcu 2019 r. (Podziękowania za odpowiedź Matta tutaj i odpowiedź Tung Fam tutaj ), jeśli szukasz poprzednich składni, spójrz na sekcję edycji.

Ok, znalazłem rozwiązanie

Po pierwsze, zauważyłem, że na górze pliku AppDelegate.swift znajduje się ta linia

@UIApplicationMain

Ponieważ ta linia jest poza jakimkolwiek zakresem (na poziomie pliku), jest wykonywana natychmiast i zakładam, że kompilator tłumaczy ją na standardową funkcję główną.

Tak więc zrobiłem to, zaczynając od nowej aplikacji Swift-Only:

  • skomentowane @UIApplicationMain
  • dodał plik main.swift taki jak ten (FLApplication to moja podklasa).
    WAŻNE plik MUSI BYĆ NAZWANY main.swift, ponieważ instrukcje najwyższego poziomu nie są obsługiwane w innych plikach! Nie możesz dodać wywołania UIApplicationMain () w żadnym innym pliku, w przeciwnym razie otrzymasz ten błąd:

Wyrażenia nie są dozwolone na najwyższym poziomie

To jest plik main.swift

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

Następnie utwórz plik Swift dla podklasy UIApplication, FLApplication.swift, z następującym kodem:

import UIKit
import Foundation

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

teraz UIApplication jest poprawnie podzielona na podklasy, a w dzienniku zobaczysz komunikaty o wysyłaniu zdarzeń


STARE EDYCJE
Dla odniesienia, ponieważ wiele się zmieniło od wersji 1 do wersji 3, zostawiam tutaj wszystkie poprzednie edycje


EDYCJA - MARZEC 2015

Jak skomentował Hu Junfeng, teraz wyjaśnienia dotyczące UIApplicationMainpliku main.swift są udokumentowane w sekcji Attributes w The Swift Language Reference: Link

Jak skomentował Thomas Verbeek W wersji beta XCode 6.3 może się okazać, że nazwy C_ARGC i C_ARGV zostały zmienione odpowiednio na Process.argc i Process.unsafeArgv. Twoje wywołanie UIApplicationMain w pliku main.swift będzie wymagało aktualizacji do:

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

Składnia pre-XCode 8 brzmiała

import Foundation
import UIKit

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

EDYCJA - grudzień 2016 r

Rozwiązanie dla Xcode 8, przed wersją 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
źródło
Próbuję zrozumieć, czy możliwe jest wywołanie UIApplicationMain () bezpośrednio w pliku AppDelegate.swift, ponieważ wygląda na to, że istnieje "szybka wersja" tej metody, ale mam błąd kompilatora, zrobię kilka testów szukanie „tylko szybkiego” rozwiązania
LombaX
Niesamowicie fajne. Ciekawe, jaki jest przypadek użycia do zastąpienia w sendEvent:dzisiejszych czasach (pamiętam, że musiałem to zrobić w iOS 3 ...)
mat.
2
Na wypadek, gdyby ktoś chciał wiedzieć, UIApplicationMaini main.swiftsą udokumentowane w sekcji Atrybuty w The Swift Language Reference. developer.apple.com/library/ios/documentation/Swift/Conceptual/…
hujunfeng
Dzięki za podpowiedź, jestem w 99% pewien, że w pierwszym wydaniu instrukcji Swift nie było to udokumentowane :-), jednak zaktualizuję odpowiedź dodając Twoje informacje.
LombaX
5
Świetna odpowiedź. W XCode 6.3 Beta, może się okazać, że C_ARGCi C_ARGVzostał przemianowany na Process.argci Process.unsafeArgvodpowiednio. Twoje wywołanie UIApplicationMain w pliku main.swift będzie wymagało aktualizacji doUIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(KBApplication), NSStringFromClass(AppDelegate))
Thomas Verbeek
4

Jedną z alternatyw jest rozszerzenie UIApplicationzamiast podklasy. Według iBooka wydanego przez Apple, rozszerzenia w Swift mogą:

Dodaj obliczone właściwości i obliczone właściwości statyczne Definiuj metody instancji i metody typu Dostarczaj nowe inicjatory Definiuj indeksy dolne Definiuj i używaj nowych zagnieżdżonych typów Dostosuj istniejący typ do protokołu

Fragment z: Apple Inc. „Swift Programming Language.

Jeśli Twoje potrzeby w zakresie tworzenia podklas UIApplicationsą zaspokajane przez te możliwości, najlepszym rozwiązaniem może być rozszerzenie.

Cezar
źródło
5
fajna rada - nie odpowiadam
imho
1
  1. Utwórz podklasę UIApplicationi dodaj swoją logikę

    import UIKit
    
    class CustomUIApplication: UIApplication {
        override func sendEvent(_ event: UIEvent) {
            super.sendEvent(event)
        }
    }
    
  2. Utwórz main.swiftplik, który wywołuje funkcję UIApplicationMain()globalną [About] , która jest nowym punktem wejścia aplikacji wywoływanej przez system operacyjny. Ta funkcja otrzymuje argument z wywołanej funkcji, UIApplicationnazwę UIApplicationDelegateklasy, nazwę klasy i uruchamia główną pętlę uruchamiania.

    import UIKit
    
    UIApplicationMain(
        CommandLine.argc,
        CommandLine.unsafeArgv,
    
        NSStringFromClass(CustomUIApplication.self), //was created at step 1
        NSStringFromClass(AppDelegate.self)
    )
    
  3. Usuń / skomentuj @UIApplicationMaindomyślnie adnotacjęAppDelegate .

    @UIApplicationMain generuje main.swift .

    Jeśli tego nie zrobisz, pojawi się błąd kompilacji:

    UIApplicationMain atrybutu nie można użyć w module, który zawiera kod najwyższego poziomu

    //@UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        //...
    }
    
yoAlex5
źródło