Подтвердить что ты не робот

В AppDelegate, как создается экземпляр основного UIWindow?

Фрагмент кода по умолчанию в проекте Xcode Master-Detail


AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
 UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;  // *** here ***
    MasterViewController *controller = (MasterViewController *)navigationController.topViewController;
    controller.managedObjectContext = self.managedObjectContext;
    return YES;
}

AppDelegate.h

@property (strong, nonatomic) UIWindow *window;

Мне известно, что @synthesize просто устанавливает методы доступа, и никакая инициализация не происходит автоматически. Но как window имеет не-nil rootViewController, если он никогда не инициализируется явно? Является ли это просто Xcode init'ing за кулисами?

4b9b3361

Ответ 1

Из моей книги:

Если вы выберете опцию Storyboard при указании шаблона, процесс будет работать несколько иначе. Приложение получает основную раскадровку, на которую указывает ключ Info.plist "Основное имя файла основной раскадровки" (UIMainStoryboardFile). После UIApplicationMain создает экземпляр класса делегата приложения, он запрашивает делегат приложения для значения его свойства window; если это значение равно нулю, окно создается и присваивается назначению делегатов window. Затем контроллер исходного представления раскадровки создается и присваивается свойству windows rootViewController, в результате его представление помещается в окно в виде его корневого представления; затем окно отправляется сообщением makeKeyAndVisible. Все это делается за кулисами UIApplicationMain, без видимого кода. Вот почему в шаблоне раскадровки реализация application:didFinishLaunchingWithOptions: пуста.

Ответ 2

Из документации UIWindow:

Примечание. Когда вы используете раскадровки и шаблоны приложений XCode для создания приложения, для вас создается окно.

Если вы не используете раскадровки, окно создается явно, хотя все стандартные шаблоны проектов делают это из коробки. Вы увидите строку, аналогичную этой, в делегате приложения:

self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

Используя раскадровки, окно создается за кулисами при загрузке основной раскадровки (см. Руководство по программированию View Controller для получения дополнительной информации).

Ответ 3

Из документов Apple (в разделе "Использование контроллеров просмотра в вашем приложении" ):

Основная раскадровка инициализирует пользовательский интерфейс вашего приложения

Основная раскадровка определена в файле списка свойств информации приложений. Если в этом файле объявлена ​​основная раскадровка, то при запуске приложения iOS выполняет следующие действия:

Он создает окно для вас. Он загружает основную раскадровку и запускает свой первоначальный контроллер. Он назначает новый контроллер представления свойству Windows rootViewController, а затем делает окно видимым на экране.

Ответ 4

В вашей раскадровке есть небольшая стрелка, которую вы можете перетащить:

arrow

Если вместо этого вы использовали xibs/nibs, поле "Main Interface" будет заполнено.

interface

В конце концов, yep, it iOS/Xcode magic.

Ответ 5

Вышеуказанные ответы только на то, кто задает переменную окна, не отвечая на основные вопросы: "Но как у окна есть не-nil rootViewController, если он никогда не инициализируется явно? Является ли это просто началом Xcode за кулисами?" и кажется, что есть волшебство. Не удовлетворительный ответ для меня, и поэтому с небольшим рытьем все становится ясным.

Сгенерированный код определяет AppDelegate как

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
     ...
}

При поиске в проекте нет другой ссылки на окно, поэтому, по-видимому, она должна оставаться нулевой, но на самом деле она установлена ​​на правильное значение (по описанным выше методам). "Магия" заключается в том, что AppDelegate соответствует UIApplicationDelegate, который включает объявление:

    optional public var window: UIWindow? { get set }

Часть, соответствующая UIApplicationDelegate, является обновлением открытого окна переменных. Когда основное приложение ссылается на окно переменной в протоколе, оно фактически связано с окном переменной в нашем классе. Когда вызывающее приложение обновляет это окно переменной в протоколе, оно фактически обновляет наше окно переменных. Поэтому, когда нам нужно получить доступ к значению в нашей программе, он готов и ждет.

Это не Xcode magic, но неотъемлемая часть языка Swift. При использовании протоколов мы можем использовать те же методы в наших собственных программах Swift. Это то же самое, что и наши реализации различных функций в наших классах, которые мы делаем все время: например. UIApplicationDelegate определяет

optional public func applicationDidEnterBackground(_ application: UIApplication)

чтобы мы могли написать свою собственную реализацию, которая затем "магически" называется!

Для полноты обратите внимание на тег @UIApplicationMain в классе. Это определяет точку входа для приложения и является тем, что заставляет все работать вместе. Фактическое имя класса не имеет значения и может быть предоставлено любое требуемое имя, если оно имеет тип UIResponder и соответствует UIApplicationDelegate.