viewDidLoad вызывается дважды на rootViewController при запуске
кто-нибудь знает, почему этот корень 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 ответов
странно. Я не видел этого конкретного случая, но в целом вы должны предположить, что viewDidLoad можно вызвать несколько раз. Он будет вызываться всякий раз, когда загружается файл nib, который ссылается на этот контроллер.
для простого приложения с одним наконечником этого не должно произойти. Но в более сложном приложении, которое может загружать и выгружать контроллеры представления, это происходит все время.
у меня была такая же проблема, когда мое приложение было впервые запущено. То, что я нашел, было в моем главном окне.xib-файл, я устанавливал оба делегата моего приложения viewController
выход, и мое окно rootViewController
выход к моему контроллеру корневого представления. Когда вы создаете файл проекта на основе представления в Xcode, делегат вашего приложения didFinishLaunchingWithOptions
будет предварительно заполнено:
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
Я считаю, что self.viewController
экземпляр ivar создается из главного окна.xib перед didFinishLaunchingWithOptions
вызывается. Затем предварительно заполненный код выше устанавливает окно rootViewController
. Поэтому, если в сочетании вы укажете rootViewController
выход для окна в главном окне.xib-файл, ваш контроллер корневого вида будет фактически создан дважды и добавлен в качестве контроллера корневого вида окна два раза.
Я сделал некоторую отладку, и вот что я нашел о 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:
называется и новая копия!-Создан -3--> - это. это то, что передается в несколько методов (например,viewDidLoad
). копия уничтожается позже в вызове dealloc. хорошей новостью является то, что в этой копии сохраненные розетки не настроены, поэтому вы можете использовать это как тест, чтобы узнать, следует ли инициализировать переменные, вызывать другие методы и большинство важно, если вы должны освободить и уничтожить объекты во время dealloc.
ключ на вынос: реальный viewController
придется ее сохранить IBOutlet
свойства настроен. если вы находитесь в переопределенном методе, который вызывается несколько раз, просто проверьте один из сохраненных IBOutlet
свойства NULL
. если это так!--8-->, тут же вернуться.
у кого-нибудь есть подсказки, почему это происходит таким образом?
побочный эффект: вы не можете использовать awakeFromNib
надежно.
вы не можете предположить, что viewDidLoad будет вызываться только один раз. Если вы инициализируете объекты и хотите получить гарантию, выполните инициализацию либо в методе init, либо при загрузке из файла nib из метода awakeFromNib.
у меня была аналогичная проблема, и это было результатом переименования моего XIB-файла и его ViewController
класс (владелец файла). Не надо, так как он действительно получил представления и делегаты misdefined внутри XML и он не был восстановлен. Между тем, у меня была ссылка на загрузку оригинального VC, который должен был быть моим новым VC. Я считаю, что это заставило родителя воссоздать себя, а затем VC, который я действительно пытался вызвать. В принципе, я создал косвенную рекурсию к VC, которая имеет x2 viewDidLoad
записи в моем следе.
Я не думаю, что есть какая-либо веская причина для x2 viewDidLoad
поскольку это генезис и может вызывать другую инициализацию с неправильными предполагаемыми предварительными условиями. Каждый раз, когда я видел Х2 метод viewDidLoad, это была ошибка с моей стороны-довольно часто, когда я был рефакторинга и движется ВК-классы по.
если есть веская причина для более чем на viewDidLoad
позвоните, пожалуйста, кто-нибудь (Apple Dev вы слушаете) объясните это в технических деталях - у меня есть я искал этот ответ уже несколько месяцев.
У меня была эта проблема, но я смог ее исправить.
решение:
переименуйте класс контроллера вида, который загружается дважды.
подробности:
переименуйте его и сделайте новое имя чем-то совершенно новым. переименование файла не останавливает нагрузку-дважды вопрос. Создание нового проекта (как предлагают другие) может быть излишним, по крайней мере, сначала попробуйте более простые решения! Переименовать класс пунктом ВК.
подсказка: Если переименование класса устраняет вашу проблему, вы, очевидно, должны обновить все свои ссылки на этот класс. Вы можете ускорить это, используя Command+Shift+F для поиска по всему проекту.
я столкнулся с той же проблемой, что и при перепроектировании 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
вид имущества:
если вы получить доступ к этому свойству и его в настоящее время значение равно nil, представление контроллер автоматически вызывает
loadView
метод и возвращает результирующий вид. Значение по умолчаниюloadView
метод пытается загрузить представление из файл nib, связанный с представлением контроллер (если есть). Если ваш взгляд контроллер не связан файл nib, вы должны переопределитьloadView
метод и использовать его для создания корневое представление и все его подвиды.
в моем случае я не заметил, что я фактически назначил rootViewController дважды в:
application:didFinishLaunchingWithOptions:
и applicationDidBecomeActive:
просто добавьте к этому, если вы используете системную функцию, такую как TouchID, то applicationWillResignActive в вашем AppDelegate будет вызываться, и если вы говорите, сброс контроллеров на безопасный корневой контроллер, то вы получите повторно, и performSegueWithIdentifier (self.MAIN_SEGUE, отправитель: self) не будет стрелять!
Это произошло со мной, когда я объединил проект с раскадровки на старый способ, используя xibs для построения представлений. Основной причиной для переключения назад был тот факт, что я не мог правильно настроить модальный вид должным образом. Как я обычно это делаю, имея метод делегата из UIButton, создайте экземпляр определенного viewcontroller, установите некоторые из его свойств (наиболее импортным из них является делегат, поэтому я могу правильно отклонить контроллер модального представления снова), а затем представить его в модальный способ. В новом раскадровке это предположительно делается с помощью segue. Настройка перехода возможна только путем создания пользовательского класса, который расширяет класс UIStoryboardSegue. Я нахожу этот способ слишком много хлопот по сравнению с простым способом, которым он был, поэтому я слился обратно.
Как это заставило меня дважды загрузить viewcontroller? При передаче кода из проекта раскадровки в проект xib я сделал пару xibs (по одному для каждого ViewController) и скопировал объект viewcontroller из раскадровки. Это привело к xib С в нем не viw, а viewcontroller; это означает, что я поместил viewcontroller в viewcontroller (так как владелец файла также является экземпляром viewcontroller). Я не думаю, что в вашем случае у вас была эта проблема, но я надеюсь, что это может помочь кому-то когда-нибудь.
чтобы исправить это, переместите представление из контроллера вида из контроллера вида и на корневой уровень раздела объекты. Оба контроллер вида и его навигационный элемент должны быть удалены. Постройте и запустите, и вы увидите только одно распределение для контроллера представления. Это владелец файла.