Вопрос по iphone – viewDidLoad вызывается дважды на rootViewController при запуске

18

Кто-нибудь знает, почему этот кореньView Controller's viewDidLoad вызывается дважды при запуске? Это сводит меня с ума!

здесь трассировка стека с первого раза доviewDidLoad:

#0  0x0000276a in -[RootViewController viewDidLoad] at RootViewController.m:71
#1  0x3097548f in -[UIViewController view]
#2  0x00002734 in -[RootViewController initWithCoder:] at RootViewController.m:39
#3  0x30ab5ce4 in -[UIClassSwapper initWithCoder:]
#4  0x30514636 in _decodeObjectBinary
#5  0x30514035 in _decodeObject
#6  0x30ab5a1d in -[UIRuntimeConnection initWithCoder:]
#7  0x30514636 in _decodeObjectBinary
#8  0x30515f27 in -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:]
#9  0x305163b0 in -[NSArray(NSArray) initWithCoder:]
#10 0x30514636 in _decodeObjectBinary
#11 0x30514035 in _decodeObject
#12 0x30ab4dde in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:]
#13 0x30ab6eb3 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:]
#14 0x308f85f1 in -[UIApplication _loadMainNibFile]
#15 0x30901a15 in -[UIApplication _runWithURL:sourceBundleID:]
#16 0x308fef33 in -[UIApplication handleEvent:withNewEvent:]
#17 0x308fad82 in -[UIApplication sendEvent:]
#18 0x309013e1 in _UIApplicationHandleEvent
#19 0x32046375 in PurpleEventCallback
#20 0x30245560 in CFRunLoopRunSpecific
#21 0x30244628 in CFRunLoopRunInMode
#22 0x308f930d in -[UIApplication _run]
#23 0x309021ee in UIApplicationMain
#24 0x000022e4 in main at main.m:14

и второй раз:

#0  0x0000276a in -[RootViewController viewDidLoad] at RootViewController.m:71
#1  0x30ab50cd in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:]
#2  0x30ab6eb3 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:]
#3  0x308f85f1 in -[UIApplication _loadMainNibFile]
#4  0x30901a15 in -[UIApplication _runWithURL:sourceBundleID:]
#5  0x308fef33 in -[UIApplication handleEvent:withNewEvent:]
#6  0x308fad82 in -[UIApplication sendEvent:]
#7  0x309013e1 in _UIApplicationHandleEvent
#8  0x32046375 in PurpleEventCallback
#9  0x30245560 in CFRunLoopRunSpecific
#10 0x30244628 in CFRunLoopRunInMode
#11 0x308f930d in -[UIApplication _run]
#12 0x309021ee in UIApplicationMain
#13 0x000022e4 in main at main.m:14

Ваш Ответ

10   ответов
1

что фактически назначил rootViewController дважды:

application:didFinishLaunchingWithOptions: а такжеapplicationDidBecomeActive:

4

но в целом вы должны предполагать, что viewDidLoad может быть вызван несколько раз. Он вызывается всякий раз, когда загружается nib-файл, который ссылается на этот контроллер.

Для простого приложения, содержащего только одно перо, этого не должно быть. Но в более сложном приложении, которое может загружать и выгружать контроллеры представления, это происходит постоянно.

Это неверно viewDidUnload вызывается только в ситуациях нехватки памяти. Не гарантируется, что он будет вызываться для каждого вызова viewDidLoad.
Да, но происходит то, что мои объекты восстанавливаются, и я получаю по два из каждого. Я мог только проверить, есть ли у них re! = Nil, но мне не приходилось делать это в предыдущих приложениях. Здесь происходит что-то странное. Какие-нибудь идеи, которые могли бы назвать это нерегулярно, чтобы я глубже искал причину? Meltemi
Я согласен, проверьте, если вы определили 2 экземпляра RootViewController
Во втором случае это разархивирование NSArray, который, очевидно, имеет ссылку на RootViewController. Возможно, у вас есть несколько ссылок на RootViewController в одном и том же файле пера?
Хотя Марк в основном прав, viewDidUnload и viewDidLoad являются аналогичными методами. По крайней мере, можно предположить, что для каждого вызова viewDidLoad будет другой вызов viewDidUnload. Таким образом, вы можете выполнить разбор настроек в viewDidLoad. Когда последний вызывается несколько раз подряд без промежуточного viewDidUnload, все может пойти ужасно неправильно. Это не должно происходить вообще.
1

если вы используете системную функцию, такую как TouchID, тоapplicationWillResignActive в вашем AppDelegate будет вызываться, и если вы, скажем, сбросить контроллеры в Secure Root Controller, то вы будете повторно вызваны, иperformSegueWithIdentifier(self.MAIN_SEGUE ,sender: self) не будет стрелять!

да, использование TouchID заставляет вызывать applicationWillResignActive и активировать снова.
15

когда мое приложение запускалось впервые. Я обнаружил, что в моем файле MainWindow.xib я настраивал оба делегата приложения.viewController розетка и мое окноrootViewController выход на мой корневой контроллер просмотра. Когда вы создаете файл проекта View Based в XCode, ваши делегаты приложенияdidFinishLaunchingWithOptions будет предварительно заполнен:

self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;

Я считаю, чтоself.viewController ivar создается из MainWindow.xib передdidFinishLaunchingWithOptions вызывается. Затем предварительно заполненный код выше устанавливает окноrootViewController, Так что, если в сочетании, вы указываетеrootViewController В случае выхода окна в вашем файле MainWindow.xib ваш корневой контроллер вида будет фактически создан дважды и добавлен в качестве корневого контроллера окна дважды.

Это именно та проблема, которая у меня была.
Всеthat случайный жирныйmakes это действительно сложноto читать.
Та же проблема. Это была больная сделка. Спасибо, Харрисонли.
просто изменилbold вpre
В моем случае метод инициализации VC вызывается один раз, но viewDidLoad вызывается дважды
3

Solution:

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

Details:

Переименуйте его и сделайте новое имя чем-то совершенно новым.Renaming the file не останавливает проблему двойной загрузки. Создание нового проекта (как предлагают другие) может быть излишним, по крайней мере, сначала попробуйте простые решения! Переименуйте класс назначения VC.

Hint: If renaming the class fixes your issue, you then obviously have to update all your references to that class. You can speed this up by using Command+Shift+F for project-wide find.

У меня была похожая проблема с одним из моих взглядов. Переименование контроллера представления само по себе не работает. Я должен был удалить и воссоздать переход к представлению. Это должно быть ошибка в XCode, так как я ранее не переименовывал и не менял раскадровку.
Спасатель! Это решило мою проблему!
Действительно странно и спасибо за это. Если вы видите это сообщение DaveG или другие - это былоfirst один илиsecond тот, который был настоящим? в моем случае это былfirst один. Мне интересно, если это та же самая проблема.
3

что viewDidLoad будет вызываться только один раз. Если вы инициализируете объекты и хотите получить гарантию, выполните инициализацию либо в методе init, либо, если вы загружаете из файла nib из метода awakeFromNib.

0

когда я слил проект из раскадровки со старым способом, используя xibs для построения представлений. Основной причиной переключения назад был тот факт, что я не смог правильно настроить модальное представление должным образом. Обычно я делаю это с помощью метода делегата из UIButton, создающего экземпляр определенного viewcontroller, устанавливающего некоторые из его свойств (наиболее импортным из которых является делегат, чтобы я мог снова корректно закрыть модальный контроллер представления), а затем представляю это модально. В новом способе раскадровки это предположительно сделано с помощью перехода. Настройка перехода возможна только путем создания пользовательского класса, который расширяет класс UIStoryboardSegue. Я считаю, что это слишком много хлопот по сравнению с простым, как это было раньше, поэтому я слился обратно.

Как это заставило меня загрузить viewcontroller дважды? При переносе кода из проекта раскадровки в проект xib я сделал пару xibs (по одному для каждого ViewController) иcopied объект viewcontroller из раскадровки. Это привело к xib с не viw, а viewcontroller; то есть я поместил viewcontroller в viewcontroller (поскольку владелец файла также является экземпляром viewcontroller). Я не думаю, что в вашем случае у вас была эта проблема, но я надеюсь, что она может кому-нибудь когда-нибудь помочь.

Чтобы исправить это, переместите представление из контроллера представления из контроллера представления в корневой уровень раздела объектов. И контроллер представления, и его элемент навигации должны быть удалены. Создайте и запустите, и вы должны увидеть только одно выделение для контроллера представления. Это владелец файла.

2

ViewController с нуля избавиться от файла XIB и сделать класс многоразовым. У меня был второйViewController экземпляр, который получитviewDidLoad сообщение, сопровождаемое сообщением dealloc.

Я узнал, что это было результатомloadView метод не переопределяется вViewController, По умолчаниюloadView называетсяawakeFromNibсnibName свойство, установленное на имя класса. Несмотря на то, что я удалил файл XIB из проекта, он все еще находился в каталоге приложения на симуляторе.

Таким образом, даже если вы можете просто сбросить содержимое и настройки симулятора, чтобы избавиться от второгоviewDidLoad, лучший способ может быть просто переопределитьloadView как это:

- (void)loadView {
    self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease];
    self.view.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; 
}

Это имеет смысл, если вы рассматриваете документацию дляUIViewController's просмотреть свойство:

If you access this property and its value is currently nil, the view controller automatically calls the loadView method and returns the resulting view. The default loadView method attempts to load the view from the nib file associated with the view controller (if any). If your view controller does not have an associated nib file, you should override the loadView method and use it to create the root view and all of its subviews.

3

и это было результатом переименования моего файла XIB и егоViewController класс (Владелец файла). Не делайте этого - так как он действительно неправильно определил представления и делегаты внутри XML, и это не удалось восстановить. Между тем, у меня была ссылка на загрузку исходного VC, который должен был стать моим новым VC. Я считаю, что это заставило родителя воссоздать себя, а затем VC, который я действительно пытался вызвать. По сути, я создал косвенную рекурсию к VC, который имеет х2viewDidLoad Записи в моем следе.

Я не думаю, что есть веская причина для х2viewDidLoad поскольку это генезис и может вызывать другую инициализацию с неверно принятыми предварительными условиями. Каждый раз, когда я видел x2 viewDidLoad, это была ошибка кодирования с моей стороны - довольно часто, когда я занимался рефакторингом и перемещением классов VC.

Если есть веская причина для более чем наviewDidLoad позвоните, пожалуйста, кто-нибудь (Apple Dev вы слушаете) объяснить это в технических деталях - я искал этот ответ в течение нескольких месяцев.

Возникла такая же проблема после переименования некоторых файлов в проекте. Закончилось создание нового проекта.
@ Бемму Думаю, это и моя проблема. Я на 99,9% уверен, что у меня нет двух сегментов или каких-либо других объяснений двойной нагрузки, которую я вижу. Это был единственный контроллер представления, где я помню, как играл с именем и, возможно, удалял / воссоздал файл. Есть ли способ обойти создание совершенно нового проекта? Копирование кода в новые файлы было бы хорошо, но у меня есть много работы в моем файле раскадровки, и я не хотел бы заново создавать ограничения дизайна / макета каждого VC и т. Д.
7

ViewController порядок загрузки:

initWithNibName:bundle:     self = <original instance>, retainedOutlet = 0x0  
loadView >>>                self = <original instance>, retainedOutlet = 0x0  
      initWithCoder:        self = <coder instance>,    retainedOutlet = 0x0  
      initWithCoder:        self = <coder instance>,    retainedOutlet = 0x0  
      setView:              self = <original instance>, retainedOutlet = 0x0  
      setRetainedOutlet:    self = <original instance>, retainedOutlet = 0x1613c40  
      viewDidLoad           self = <coder instance>,    retainedOutlet = 0x0  
      awakeFromNib          self = <coder instance>,    retainedOutlet = 0x0  
loadView <<<  
viewDidLoad                 self = <original instance>, retainedOutlet = 0x1613c40  
viewWillAppear:             self = <original instance>, retainedOutlet = 0x1613c40  
dealloc                     self = <coder instance>,    retainedOutlet = 0x0
viewDidAppear:              self = <original instance>, retainedOutlet = 0x1613c40

Во время метода loadView,initWithCoder: называется и новая копияviewController создано. это то, что передается в несколько методов (например,viewDidLoad). копия уничтожается позже при вызове dealloc. Хорошая новость заключается в том, что в этой копии сохраненные выходы не настроены, поэтому вы можете использовать это в качестве теста, чтобы узнать, следует ли инициализировать переменные, вызывать другие методы и, что наиболее важно, должны ли вы освобождать и уничтожать объекты во время dealloc.

Ключ на вынос: настоящийviewController сохранитсяIBOutlet свойства настроены. если вы находитесь в переопределенном методе, который вызывается несколько раз, просто отметьте один из ваших сохраненныхIBOutlet свойства дляNULL, если ониNULL, а затем немедленно вернитесь.

Кто-нибудь получил какие-либо подсказки относительно того, почему это происходит таким образом?

Побочный эффект этого: вы не можете использоватьawakeFromNib надежно.

Похожие вопросы