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?


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)
)

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.


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 {
        //...
    }
    
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.