Подкласс UIApplication с Swift

92

В Objective C все было просто: достаточно было обновить файл main.m и изменить параметры UIApplicationMain ().

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

Но в swift нет файла main.m, так как в руководстве говорится

«Код, написанный в глобальной области видимости, используется как точка входа для программы, поэтому вам не нужна основная функция».

Итак, как быстро создать подкласс UIApplication ?? Любое предложение?

LombaX
источник
1
Почему предпочтительнее изменить UIApplicationMain()параметры, а не добавить имя класса NSPrincipalClassв app-info.plist?
Андреас

Ответы:

173

ОБРАТИТЕ ВНИМАНИЕ, что синтаксис был обновлен для XCode 10.1 и Swift 5 в июне 2019 года (кредиты на ответ Мэтта здесь и ответ Тунг Фама здесь ), если вы ищете предыдущие синтаксисы, посмотрите раздел редактирования.

Хорошо, я нашел решение

Во-первых, я заметил, что в верхней части файла AppDelegate.swift есть строка

@UIApplicationMain

Поскольку эта строка выходит за рамки какой-либо области (она находится на уровне файла), она выполняется немедленно, и я предполагаю, что компилятор переведет ее в стандартную основную функцию.

Итак, я сделал это, начиная с нового приложения Swift-Only:

  • закомментирован @UIApplicationMain
  • добавил такой файл main.swift (FLApplication - мой подкласс).
    ВАЖНО, файл ДОЛЖЕН НАЗВАТЬСЯ main.swift, поскольку операторы верхнего уровня не поддерживаются в других файлах! Вы не можете добавить вызов UIApplicationMain () внутри любого другого файла, иначе вы получите эту ошибку:

Выражения не разрешены на верхнем уровне

Это файл main.swift

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

Затем создайте быстрый файл для подкласса UIApplication, FLApplication.swift, с этим кодом:

import UIKit
import Foundation

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

теперь UIApplication правильно разделен на подклассы, и вы увидите сообщения «отправить событие» в журнале


СТАРЫЕ РЕДАКЦИИ
Для справки, так как это сильно изменилось с версии 1 до версии 3, я оставляю здесь все предыдущие правки.


РЕДАКТИРОВАТЬ - МАРТ 2015

Как прокомментировал Ху Цзюньфэн, теперь объяснения UIApplicationMainфайла main.swift и файла main.swift задокументированы в разделе «Атрибуты» справочника по языку Swift: ссылка

Как прокомментировал Томас Вербеек. В бета-версии XCode 6.3 вы можете обнаружить, что C_ARGC и C_ARGV были переименованы в Process.argc и Process.unsafeArgv соответственно. Ваш вызов UIApplicationMain в файле main.swift необходимо обновить до:

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

Синтаксис до XCode 8 был

import Foundation
import UIKit

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

РЕДАКТИРОВАТЬ - ДЕКАБРЬ 2016 г.

Решение для Xcode 8, до бета 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
источник
Я пытаюсь понять, можно ли вызвать UIApplicationMain () непосредственно в файле AppDelegate.swift, так как кажется, что есть «быстрая версия» этого метода, но у меня ошибка компилятора, сделаю несколько тестов поиск «только быстрого» решения
LombaX
Невероятно круто. Мне любопытно, каковы варианты использования для переопределения в sendEvent:настоящее время (я помню, что приходилось делать это в iOS 3 ...)
Мэтт
2
В случае , если кто - то хочет знать, UIApplicationMainи main.swiftописаны в разделе Атрибуты Swift Language Reference. developer.apple.com/library/ios/documentation/Swift/Conceptual/…
hujunfeng 01
Спасибо за подсказку, я на 99% уверен, что в первом выпуске руководства Swift это не было задокументировано :-), однако я обновлю ответ, добавив вашу информацию.
LombaX 02
5
Отличный ответ. В бета-версии XCode 6.3 вы можете найти это C_ARGCи C_ARGVбыли переименованы в Process.argcи Process.unsafeArgvсоответственно. Ваш вызов UIApplicationMain в файле main.swift необходимо будет обновить доUIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(KBApplication), NSStringFromClass(AppDelegate))
Thomas Verbeek
4

Одна альтернатива - расширить его, UIApplicationа не создавать подклассы. Согласно iBook, выпущенному Apple, расширения в Swift могут:

Добавление вычисляемых свойств и вычисляемых статических свойств Определение методов экземпляра и методов типа Обеспечение новых инициализаторов Определение индексов Определение и использование новых вложенных типов Обеспечение соответствия существующего типа протоколу

Отрывок из: Apple Inc. «Быстрый язык программирования.

Если ваши потребности в подклассах UIApplicationудовлетворяются этими возможностями, расширение может быть подходящим вариантом.

Цезарь
источник
5
хороший совет - не отвечайте имхо :)
Daij-Djan
1
  1. Создайте подкласс UIApplicationи добавьте свою логику

    import UIKit
    
    class CustomUIApplication: UIApplication {
        override func sendEvent(_ event: UIEvent) {
            super.sendEvent(event)
        }
    }
    
  2. Создайте main.swiftфайл, который вызывает UIApplicationMain()глобальную функцию [About] , которая является новой точкой входа в ваше приложение, вызываемое ОС. Эта функция получает аргумент от вызываемой функции, UIApplicationимя UIApplicationDelegateкласса, имя класса и запускает основной цикл выполнения.

    import UIKit
    
    UIApplicationMain(
        CommandLine.argc,
        CommandLine.unsafeArgv,
    
        NSStringFromClass(CustomUIApplication.self), //was created at step 1
        NSStringFromClass(AppDelegate.self)
    )
    
  3. Удалить / прокомментировать @UIApplicationMainаннотацию по умолчанию AppDelegate.

    @UIApplicationMainгенерирует main.swift.

    Если вы этого не сделаете, вы получите ошибку компиляции:

    UIApplicationMain атрибут не может использоваться в модуле, который содержит код верхнего уровня

    //@UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        //...
    }
    
yoAlex5
источник