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
Anyone know why this root View Controller's
viewDidLoad
is being called twice at launch? It's driving me nuts!
here's the stack trace from first time through 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
and the second time:
#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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
当我的应用程序首次启动时,我遇到了同样的问题。 我发现在我的 MainWindow.xib 文件中,我将应用程序代理的
viewController
出口和窗口的rootViewController
出口设置为我的根视图控制器。 当您在 Xcode 中构建基于视图的项目文件时,您的 App Delegate 的didFinishLaunchingWithOptions
将预先填充:我相信
self.viewController
ivar 是从 MainWindow.xib 实例化的在didFinishLaunchingWithOptions
被调用之前。 然后上面预先填充的代码设置窗口的rootViewController
。 因此,如果您在 MainWindow.xib 文件中同时指定 Window 的rootViewController
出口,那么您的根视图控制器实际上将被创建两次,并两次添加为 Window 的根视图控制器。I had this same issue when my app was first launching. What I found was that in my MainWindow.xib file, I was setting both my App Delegate's
viewController
outlet, and my Window'srootViewController
outlet to my root view controller. When you build a View Based project file in Xcode, your App Delegate'sdidFinishLaunchingWithOptions
will be pre-populated with:I believe that the
self.viewController
ivar is instantiated from MainWindow.xib beforedidFinishLaunchingWithOptions
gets called. Then the pre-populated code above sets the Window'srootViewController
. So if, in conjunction, you specify therootViewController
outlet for the Window in your MainWindow.xib file, your root view controller will actually be created twice and added as the Window's root view controller two times.我做了一些调试,以下是我发现的有关
ViewController
加载顺序的信息:在 loadView 方法期间,调用
initWithCoder:
并生成viewController
的新副本代码>已创建。 这是传递给一些方法的内容(例如 viewDidLoad)。 该副本稍后在 dealloc 调用中被销毁。 好消息是,在此副本中,未配置保留的出口,因此您可以使用它作为测试来了解是否应该初始化变量、调用其他方法,最重要的是,是否应该在 dealloc 期间释放和销毁对象。关键要点:真正的
viewController
将配置其保留的IBOutlet
属性。 如果您处于被多次调用的重写方法中,只需检查保留的IBOutlet
属性之一是否为NULL
。 如果它们是NULL
,则立即返回。有人知道为什么会这样吗?
这样做的副作用:您无法可靠地使用
awakeFromNib
。I did some debugging and here's what I found about the
ViewController
loading order:During the loadView method,
initWithCoder:
is called and a new copy of theviewController
is created. this is what is passed into a few of the methods (likeviewDidLoad
). the copy is destroyed later in a dealloc call. the good news is that in this copy, retained outlets are not configured, so you can use this as a test to know if you should initialize variables, call other methods, and most importantly, if you should release and destroy objects during dealloc.Key takeaway: the real
viewController
will have its retainedIBOutlet
properties configured. if you are in an overridden method that is getting called multiple times, just check one of your retainedIBOutlet
properties forNULL
. if they areNULL
, then return immediately.Anybody got any clues as to why this is happening this way?
Side effect of this: you can't use
awakeFromNib
reliably.诡异的。 我还没有见过这种特殊情况,但一般来说,您应该假设 viewDidLoad 可以被多次调用。 每当加载引用该控制器的 nib 文件时,都会调用它。
对于一个只有一个笔尖的简单应用程序来说,这种情况不应该发生。 但在可以加载和卸载视图控制器的更复杂的应用程序中,这种情况经常发生。
Weird. I haven't seen this particular case, but in general, you ought to assume that viewDidLoad can be called multiple times. It'll get called whenever a nib file that references that controller gets loaded.
For a simple app with only one nib, that shouldn't happen. But in a more-complex app that can load and unload view controllers, this happens all the time.
您不能假设 viewDidLoad 只会被调用一次。 如果您正在初始化对象并希望保证在 init 方法中进行初始化,或者如果您正在通过 awakeFromNib 方法从 nib 文件加载,则可以进行初始化。
You can't assume viewDidLoad will be called only once. If you are initializing objects and want a guarantee do the initialization either in the init method or if you are loading from a nib file from the awakeFromNib method.
我遇到了类似的问题,这是重命名我的 XIB 文件及其
ViewController
类(文件所有者)的结果。 不要这样做——因为它确实在 XML 中错误定义了视图和委托,并且无法恢复。 同时,我引用了加载原始 VC,它应该是我的新 VC。 我相信这会导致父级重新创建自身,然后我真正尝试调用 VC。 基本上,我创建了一个对 VC 的间接递归,该 VC 在我的跟踪中具有 x2viewDidLoad
条目。我认为 x2 viewDidLoad 没有任何有效的理由,因为它是一个起源,并且可以使用错误的假设前提条件调用其他初始化。 每次我看到 x2 viewDidLoad 时,这都是我的编码错误——通常是在我重构和移动 VC 类时。
如果有正当理由超过
viewDidLoad
调用,请有人(Apple Dev 你在听吗)详细解释一下技术细节 - 我几个月来一直在寻找这个答案。I had a similar problem and it was a result of renaming my XIB file and its
ViewController
class (File Owner). Don't do that -- as it really got the views and delegates misdefined inside the XML and it was not recoverable. Meanwhile, I had a reference to the load the original VC that was supposed to be my new VC. I believe that caused the parent to recreate itself and then the VC I was really tried to invoke. Basically, I created an indirect recursion to the VC that has x2viewDidLoad
entries in my trace.I don't think there is any valid reason for x2
viewDidLoad
as it is a genesis and can invoke other initialization with the wrong assumed pre-conditions. Every time I have seen the x2 viewDidLoad, it was a coding error on my part -- quite often when I was refactoring and moving VC classes around.If there is a valid reason for more than on
viewDidLoad
call, please someone (Apple Dev are you listening) explain it in technical detail -- I have been searching for that answer for months now.我遇到了这个问题,但能够解决它。
解决方案:
重命名加载两次的视图控制器类。
详细信息:
重命名它并使新名称焕然一新。 重命名文件并不能解决两次加载问题。 创建一个新项目(按照其他人的建议)可能有点矫枉过正,至少首先尝试更简单的解决方案! 重命名目标 VC 的类。
提示:
如果重命名该类可以解决您的问题,那么您显然必须更新对该类的所有引用。 您可以使用 Command+Shift+F 进行项目范围的查找来加快速度。
I had this problem but was able to fix it.
Solution:
Rename the view controller class that is loading twice.
Details:
Rename it and make the new name something entirely new. Renaming the file doesn't stop the load-twice issue. Creating a new project (as suggested by others) might be overkill, at least try the simpler solutions first! Rename the class of the destination 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.
当我从头开始重新设计 ViewController 以摆脱 XIB 文件并使该类可重用时,我遇到了同样的问题。 我有第二个
ViewController
实例,它将接收一个viewDidLoad
消息,后跟一条 dealloc 消息。我发现这是由于
loadView
方法没有在ViewController
中重新定义的结果。 默认的loadView
称为awakeFromNib
,其中nibName
属性设置为类名。 尽管我已经从项目中删除了 XIB 文件,但它仍然位于模拟器的应用程序目录中。因此,即使您可以重置模拟器的内容和设置来摆脱第二个
viewDidLoad
,更好的方法可能是重新定义loadView
,如下所示:如果您考虑 UIViewController 的 view 属性的文档,就会明白:
I ran into the same problem as I was redesigning a
ViewController
from scratch to get rid of the XIB file and to make the class reusable. I had this secondViewController
instance which would receive aviewDidLoad
message followed by a dealloc message.I found out this was the result of the
loadView
method not being redefined in theViewController
. The defaultloadView
calledawakeFromNib
, with thenibName
property set to the class name. Even though I had removed the XIB file from the project, it was still in the application directory on the simulator.So even though you could just reset the contents and settings of the simulator to get rid of the second
viewDidLoad
, a better way may be to just redefineloadView
like this:It makes sense if you consider the documentation for the
UIViewController's
view property:中分配了两次 rootViewController
就我而言,我没有注意到我实际上在
application:didFinishLaunchingWithOptions:
和applicationDidBecomeActive:
In my case, I didn't notice that I have actually assigned the rootViewController twice in:
application:didFinishLaunchingWithOptions:
andapplicationDidBecomeActive:
除此之外,如果您使用的是系统功能,例如 TouchID,那么您的 AppDelegate 中的 applicationWillResignActive 将被调用,如果您说,将控制器重置为保护根控制器,然后您将被重新调用,并且 performSegueWithIdentifier(self.MAIN_SEGUE ,sender: self) 将不会触发!
Just to add to this, if you are using a system function, such as TouchID, then applicationWillResignActive in your AppDelegate will get invoked and if you are say, resetting controllers to a Secure Root Controller then you get reinvoked, and performSegueWithIdentifier(self.MAIN_SEGUE ,sender: self) will not fire!
当我将故事板中的项目合并到使用 xibs 构建视图的旧方法时,就发生了这种情况。 切换回来的主要原因是我无法正确地正确放置模态视图。 我通常这样做的方式是通过 UIButton 的委托方法构造某个视图控制器的实例,设置它的一些属性(最重要的是委托,这样我就可以再次正确地关闭模式视图控制器),然后呈现以模态方式。 在新的故事板方式中,这应该是通过转场完成的。 自定义转换只能通过创建扩展 UIStoryboardSegue 类的自定义类来实现。 我发现这种方式与以前的简单方式相比太麻烦了,所以我合并了回来。
这怎么导致我的视图控制器加载两次? 将代码从 Storyboard 项目传输到 xib 项目时,我制作了几个 xib(每个 ViewController 一个)并从 Storyboard 中复制 viewcontroller 对象。 这导致 xib 中没有视图,而是视图控制器; 这意味着我已将视图控制器放入视图控制器中(因为文件的所有者也是视图控制器的实例)。 我不认为您遇到这个问题,但我希望有一天它可能对某人有所帮助。
要解决此问题,请将视图从视图控制器移出视图控制器并移动到对象部分的根级别。 视图控制器及其导航项都应该被删除。 构建并运行,您应该只看到视图控制器的一种分配。 这是文件所有者。
This happened to me when I merged a project from the storyboard to the old way using xibs for constructing views. The main reason for switching back was the fact I couldn't properly put up a modal view properly. The way I usually do it is by having a delegate method from a UIButton construct an instance of a certain viewcontroller, set some of its properties (the most import one being the delegate so i can properly dismiss the modal view controller again) and then present it in a modal way. In the new storyboard way, this is supposedly done with a segue. Customizing the transition is only doable by making a custom class that extends the UIStoryboardSegue class. I find this way too much hassle compared to the simple way it used to be so I merged back.
How did this cause me to have a viewcontroller load twice? When transferring the code from the storyboard project to the xib project, I made a couple of xibs (one for each ViewController) and copied the viewcontroller object from the storyboard. This led to a xib with in it not a viw, but a viewcontroller; meaning i had put a viewcontroller in a viewcontroller (since the file's owner is also an instance of the viewcontroller). I don't think in your case that you had this problem but I hope it maybe helps someone some day.
To fix this move the view from the view controller out of the view controller and to the root level of the objects section. Both the view controller and it's navigation item should be deleted. Build and run and you should see only one allocation for the view controller. This is the file owner.
如果您的代码在尚未加载时访问了视图属性,视图控制器将仅创建空视图,并且可能会意外触发
view did load
。最常见的错误是在初始化期间访问视图属性。 可能是 xib 调用的某些属性访问器(setter)应该意外访问视图属性。
如果某些属性用
IBInspectable
注释,您应该在将某些值应用于视图之前检查isViewLoaded
该怎么办。What if your code did access the view property when it is not loaded yet, the view controller will create just empty view and it could trigger
view did load
accidentally.Most common error is accessing view property during initialization. May be some property accessor(setter) that is invoked by xib should access view property accidentally.
What if some property is annotated with
IBInspectable
you should have to checkisViewLoaded
before apply some value to view.我确实在 SceneDelegate 中做了类似的事情来检查某些内容并忘记删除它。
然后我发现最终再次调用 viewDidLoad 。
I did make something like this in SceneDelegate to check something and forget removing it.
Then I find out that ends up calling viewDidLoad again.