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

Какая связь между AppDelegate, RootViewController и UIApplication?

Я пытаюсь выяснить взаимосвязь между appdelegate, RootViewControoler и UIApplication. Вот что я догадался до сих пор:

При запуске приложения main.m загружается.

Здесь загружается ваш MainWindow.xib.

В вашем MainWindow.xib владелец файла имеет тип UIApplication.

Вы назначили делегата UIApplication в AppDelegate.

В исходном коде AppDelegate вы можете установить, что ваш RootViewController является первым показанным видом.

Правильно ли это? Что подсказывает AppDelegate для его первоначального запуска

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { }

метод?

4b9b3361

Ответ 1

При запуске приложения Objective-C он запускается с помощью функции main(). Это не должно быть в файле "main.m", но это то, как мастер Xcode устанавливает вещи.

Внутри функции main(), созданной мастером, есть следующая строка:

int retVal = UIApplicationMain(argc, argv, nil, nil);

Это то, что запускает структуру "UIKit", которая составляет все приложение. Внутри UIApplicationMain создается объект типа UIApplication. И часть того, что UIApplication делает при запуске приложения, вызывает метод applicationDidFinishLaunchingWithOptions для члена делегата класса UIApplication. Этот делегат настроен в файле MainWindow.xib как экземпляр вашего класса ProjectAppDelegate, подкласса NSObject, который соответствует протоколу UIApplicationDelegate.

Что подсказывает AppDelegate изначально запустите его...

Так как в вашем файле MainWindow.xib вы подключились (ну, собственно, мастер проекта действительно подключил соединение) File Owner (который является объектом UIApplication), "делегировать" выход объекту UIApplicationDelegate в файле .xib, а класс UIApplicationDelegate настроен для вашего подкласса UIApplicationDelegate.

И нет ничего волшебного в отношении "MainWindow.xib", его можно было бы назвать "Foo.xib", что важно, что свойство в вашем файле Info.plist под названием "Main nib file base name" является "MainWindow". Попробуйте переименовать MainWindow.xib в Foo.xib и измените "Основное имя файла основного файла" в вашем Info.plist на "Foo", и вы увидите, что он все еще работает.

EDIT: больше о RootController

Опять же, нет ничего волшебного в так называемом "RootController". Это просто имя подкласса UIViewController, созданного для вас мастером нового проекта Xcode.

Мастер помещает код в проект для двух классов: ProjectAppDelegate и ProjectViewController. Класс ProjectAppDelegate содержит два члена:

IBOutlet UIWindow *window;
IBOutlet ProjectViewController *viewController;

в файле MainWindow.xib, размещаются экземпляры как UIWindow, так и ProjectViewController и подключены к вышеуказанным выходам в ProjectAppDelegate.

Что вы получаете на экране, это этот код в вашем классе ProjectAppDelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    // Override point for customization after application launch.

    // Add the view controller view to the window and display.
    [self.window addSubview:viewController.view];
    [self.window makeKeyAndVisible];

    return YES;
}

Опять же, в этом нет ничего удивительного: мастер проекта создал код, который добавляет ваш "вид" ViewController к представлению окна и делает окно видимым. Ваш "корневой" контроллер представлений был создан в файле .xib и подключен к выходу ProjectAppDelegate.

Очень поучительно пытаться самостоятельно создать приложение самостоятельно, не используя ни одного из файлов мастера. Вы узнаете много о том, как работают файлы .xib и как они относятся к объектам кода.

Ответ 2

Исходной точкой приложений iOS всегда является функция main() (спасибо @bogatyr), которая обычно содержит код, похожий на

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

Последние два параметра UIApplicationMain важны и указывают имя основного класса и делегат приложения. Если они nil, тогда Info.plist будет искать главное окно xib (обычно MainWindow.xib).

// If nil is specified for principalClassName, the value for NSPrincipalClass
// from the Info.plist is used. If there is no NSPrincipalClass key specified, the
// UIApplication class is used. The delegate class will be instantiated 
// using init.
.. UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);

Нет необходимости устанавливать File Owner через xib, и они могут быть указаны непосредственно в этой функции UIApplicationMain.

principalClassName может быть строкой UIApplication или подклассом UIApplication. Аналогично delegateClassName может быть непосредственно задан в этом методе. Класс делегата создается с использованием init, как говорят документы. Предположим, что мы укажем наш класс делегата - MyAppDelegate как строку,

UIApplicationMain(int argc, char *argv[], nil, @"MyAppDelegate");

Сначала создается экземпляр экземпляра UIApplication, который затем создает класс делегата из этой строки, используя NSClassFromString Я полагаю.

После того как экземпляр делегированного объекта был создан, и приложение готово, этот делегат-объект будет проинформирован с использованием метода делегирования didFinishLaunchingWithOptions.

Class delegateClass = NSClassFromString(@"MyAppDelegate");
id <UIApplicationDelegate> delegateObject = [[delegateClass alloc] init];

// load whatever else is needed, then launch the app
// once everything is done, call the delegate object to
// notify app is launched
[delegateObject application:self didFinishLaunchingWithOptions:...];

Вот как UIApplication будет обрабатывать его программно, если не использовать ниб. Использование ножа посередине не сильно отличается.

Ответ 3

MainWindow.xib определен в вашем info.plist как Main nib file base name. В вашем MainWindow.xib вы определяете первый контроллер, который вы хотите загрузить, в вашем случае RootViewController.

didFinishLaunchingWithOptions: является частью протокола UIApplicationDelegate. Этот метод (в iOS4.0 +) всегда известен как первый, который будет вызываться при запуске приложения.

Ответ 4

Так как ваш AppDelegate является делегатом UIApplication - он прослушивает все уведомления, которые UIApplication публикует сообщения класса во время жизненного цикла. didFinishLaunching уведомление является одним из них, и это приводит к тому, что ваш AppDelegate вызывает вышеупомянутый метод.

Ответ 5

Для Universal - iPhone + iPad - приложения вы можете указать, что разные загрузки NIB на каждой платформе либо на целевой информационной панели, либо путем добавления ключей NSMainNibFile~ipad и NSMainNibFile~iphone к вашему Info.plist. Кроме того, вы можете добавить NIB MainWindow~ipad.xib к своей цели, он будет загружен на iPad вместо MainWindow.xib на основе ключа NSMainNibFile в Info.plist.

Если вам нужно больше контроля и настройки для универсального приложения, вы можете загрузить стартовый NIB вручную. Шаблон проекта "Универсальный" имеет шаблон для этого метода, поэтому самый быстрый способ начать использовать эту технику - это просто создать новый проект iOS с универсальным профилем.

В приведенных выше примерах Main NIB File устанавливается в Info.plist (целевые настройки), так что вы уже будете загружать NIB при вызове делегата приложения. Обычно в этой установке объект MyAppDelegate также будет архивироваться в NIB (с некоторым IBOutlets), а NIB File Owner будет установлен в UIApplication.

Для универсального проекта, позволяющего разместить два альтернативных макета, ключ основного файла NIB остается вне Info.plist. Затем он программным образом создает объект делегирования приложения в UIApplicationMain:

#import "MYAppDelegate.h"

int main(int argc, char *argv[])
{
  @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([MYAppDelegate class]));
  }
}

Затем проверьте свою среду и настройки и загрузите соответствующий NIB в application:DidFinishLaunchingWithOptions:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  _window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
  // Override point for customization after application launch.
  if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
    _viewController = [[[MYViewController alloc] initWithNibName:@"MYViewController_iPhone" bundle:nil] autorelease];
  } else {
    _viewController = [[[MYViewController alloc] initWithNibName:@"MYViewController_iPad" bundle:nil] autorelease];
  }
  _window.rootViewController = _viewController;
  [_window makeKeyAndVisible];
  return YES;
}

- (void)dealloc {
  [_window release];
  [_viewController release];
  [super dealloc];
}

Новый шаг - создать root MYViewController вручную, загрузив соответствующий NIB. В этой настройке File Owner - ваш новый новый MYViewController, а не UIApplication. Если вы хотите, MYViewController может принять большую часть того, что вы, возможно, использовали для делегирования вашего приложения, что часто заключается в инкапсуляции класса базовой модели приложения, выступать в качестве источника данных и делегировать для представлений и других вещей в СИБ.

Таким образом, вы ожидаете, что в NIB есть корень UIView, и он должен быть подключен к выходу view File Owner (MYViewController).

Обратите внимание, что NIB MYViewController фактически не загружается до тех пор, пока не будет доступ к свойству MYViewController.view. Только тогда будет называться [MyViewController viewDidLoad]! Вероятнее всего, это произойдет, когда вы добавите его в корневое окно.

В приведенном выше шаблоне код root UIWindow создается делегатом приложения, но нет причин, по которым вы не могли бы включить его в свой NIB. Если вы решите сделать это, будьте осторожны. Если вы установите rootViewController окна в NIB владельцу файла в этом случае, это приведет к тому, что представление контроллера будет добавлено в окно при активации окна. Будьте осторожны, построив первый NIB в любом случае.

Делегат приложения необязательно должен иметь ссылку на ваш root UIWindow, если вы хотите, чтобы MYViewController управлял им, но может быть более чистым в целом, чтобы оставить корневое окно из ваших NIB и управлять им в приложении делегировать.

Вне этого (!) не сильно отличается от одноплатформенного подхода.