viewDidLoad在启动时在rootViewController上被调用两次

Mel*_*emi 20 iphone cocoa-touch uiviewcontroller viewdidload

任何人都知道为什么这个根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
Run Code Online (Sandbox Code Playgroud)

第二次:

#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
Run Code Online (Sandbox Code Playgroud)

har*_*lee 16

我的应用程序首次启动时遇到了同样的问题.我发现在我的MainWindow.xib文件中,我将我的App Delegate的viewController插座和我的Window的rootViewController插座设置为我的根视图控制器.在Xcode中构建基于视图的项目文件时,您的App Delegate didFinishLaunchingWithOptions将预先填充:

self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
Run Code Online (Sandbox Code Playgroud)

我相信self.viewControllerdidFinishLaunchingWithOptions调用之前,ivar是从MainWindow.xib实例化的.然后上面预先填充的代码设置Window的rootViewController.因此,如果您rootViewController在MainWindow.xib文件中指定Window 的出口,则实际上将创建两次根视图控制器并将其添加为Window的根视图控制器两次.


小智 8

我做了一些调试,这是我发现的有关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
Run Code Online (Sandbox Code Playgroud)

在loadView方法期间,initWithCoder:调用它并viewController创建一个新副本.这是传递给一些方法(如viewDidLoad)的内容.稍后在dealloc调用中销毁副本.好消息是,在此副本中,未配置保留的插座,因此您可以将其用作测试,以了解是否应初始化变量,调用其他方法,最重要的是,如果您应在dealloc期间释放和销毁对象.

关键点:真实viewControllerIBOutlet配置其保留属性.如果您处于被多次调用的重写方法中,只需选中一个保留的IBOutlet属性即可NULL.如果是NULL,则立即返回.

任何人都知道为什么会这样发生?

这样的副作用:你不能awakeFromNib可靠使用.


Mar*_*sey 4

诡异的。我还没有见过这种特殊情况,但一般来说,您应该假设 viewDidLoad 可以被多次调用。每当加载引用该控制器的 nib 文件时,都会调用它。

对于一个只有一个笔尖的简单应用程序来说,这种情况不应该发生。但在可以加载和卸载视图控制器的更复杂的应用程序中,这种情况经常发生。

  • 这是不正确的。viewDidUnload 仅在内存不足的情况下调用。不保证每次调用 viewDidLoad 时都会调用它。 (3认同)