21

このルートView Controller's viewDidLoadが起動時に2回呼び出される理由を知っている人はいますか?それは私を狂わせています!

これが最初からのスタックトレース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

そして2回目:

#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
4

12 に答える 12

16

アプリを最初に起動したときにも同じ問題が発生しました。私が見つけたのは、MainWindow.xibファイルで、AppDelegateのviewControllerアウトレットとWindowのrootViewControllerアウトレットの両方をルートビューコントローラーに設定していたことです。Xcodeでビューベースのプロジェクトファイルをビルドすると、AppDelegateには次の情報didFinishLaunchingWithOptionsが事前に入力されます。

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

self.viewControllerivarは、呼び出される前にMainWindow.xibからインスタンス化されると思いますdidFinishLaunchingWithOptions。次に、上記の事前入力されたコードがウィンドウを設定しますrootViewController。したがって、組み合わせrootViewControllerてMainWindow.xibファイルでウィンドウのアウトレットを指定すると、ルートビューコントローラーが実際に2回作成され、ウィンドウのルートビューコントローラーとして2回追加されます。

于 2011-09-01T19:47:32.280 に答える
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

loadView メソッドの間にinitWithCoder:が呼び出され、 の新しいコピーviewControllerが作成されます。これは、いくつかのメソッド ( など) に渡されるものですviewDidLoad。コピーは後で dealloc 呼び出しで破棄されます。幸いなことに、このコピーでは保持アウトレットが構成されていないため、これをテストとして使用して、変数を初期化する必要があるかどうか、他のメソッドを呼び出す必要があるかどうか、最も重要なこととして、dealloc 中にオブジェクトを解放して破棄する必要があるかどうかを確認できます。

重要なポイント: realviewControllerには保持されたIBOutletプロパティが構成されます。複数回呼び出されるオーバーライドされたメソッドにいる場合は、保持されているIBOutletプロパティの1 つを確認してくださいNULL。である場合はNULL、すぐに戻ります。

なぜこれがこのように起こっているのか、誰にも手がかりがありますか?

これの副作用:awakeFromNib確実に使用できません。

于 2010-02-05T17:44:53.130 に答える
4

変。この特定のケースは見たことがありませんが、一般的に、viewDidLoad は複数回呼び出すことができると想定する必要があります。そのコントローラーを参照するnibファイルがロードされるたびに呼び出されます。

ペン先が 1 つしかない単純なアプリの場合、これは発生しないはずです。しかし、View Controller をロードおよびアンロードできるより複雑なアプリでは、これは常に発生します。

于 2009-07-03T23:41:03.387 に答える
3

viewDidLoad が 1 回だけ呼び出されると想定することはできません。オブジェクトを初期化していて保証が必要な場合は、init メソッドで初期化を行うか、awakeFromNib メソッドから nib ファイルからロードしている場合に行います。

于 2009-07-04T01:02:09.870 に答える
3

この問題がありましたが、修正できました。

解決策:

2 回ロードしているビュー コントローラー クラスの名前を変更します。

詳細

名前を変更し、新しい名前をまったく新しいものにします。ファイルの名前を変更しても、ロード 2 回の問題は停止しません。新しいプロジェクトを作成する(他の人が提案したように)はやり過ぎかもしれません.少なくとも最初はより簡単な解決策を試してください. 宛先 VC のクラスの名前を変更します。

ヒント: クラスの名前を変更することで問題が解決する場合は、明らかにそのクラスへのすべての参照を更新する必要があります。プロジェクト全体の検索に Command+Shift+F を使用すると、これを高速化できます。

于 2015-09-05T07:52:20.090 に答える
3

同様の問題があり、XIB ファイルとそのViewControllerクラス (ファイル所有者) の名前を変更した結果でした。そうしないでください。実際には、ビューとデリゲートが XML 内で誤って定義されており、回復できませんでした。その間、新しい VC になるはずだった元の VC をロードする方法について言及がありました。親がそれ自体を再作成し、次にVCを実際に呼び出そうとしたと思います。viewDidLoad基本的に、トレースに x2 エントリを持つ VC への間接再帰を作成しました。

x2 には正当な理由はないと思います。これはviewDidLoadジェネシスであり、前提条件が間違っていると他の初期化を呼び出す可能性があるためです。x2 の viewDidLoad を見るたびに、それは私の側のコーディング エラーでした。VC クラスのリファクタリングや移動を行っているときによく見られます。

オンコール以上の正当な理由がある場合は、viewDidLoad誰か (Apple Dev が聞いていますか) 技術的な詳細について説明してください。私は何ヶ月もの間その答えを探してきました。

于 2010-02-19T19:27:04.273 に答える
2

ViewControllerXIB ファイルを削除してクラスを再利用可能にするために をゼロから再設計していたときと同じ問題に遭遇しました。この 2 番目ViewControllerのインスタンスは、viewDidLoadメッセージの後に dealloc メッセージを受け取ります。

これは、loadViewメソッドが で再定義されていないことが原因であることがわかりましたViewController。プロパティがクラス名に設定されたloadViewデフォルトawakeFromNibの。nibNameプロジェクトから XIB ファイルを削除しても、シミュレーターのアプリケーション ディレクトリに残っていました。

そのため、シミュレーターの内容と設定をリセットして second を取り除くこともできviewDidLoadますが、より良い方法は次のloadViewように再定義することです。

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

UIViewController'sビュー プロパティのドキュメントを考慮すると、それは理にかなっています。

このプロパティにアクセスし、その値が現在 nil の場合、View Controller は自動的に loadViewメソッドを呼び出し、結果のビューを返します。デフォルトのloadView メソッドは、View Controller (存在する場合) に関連付けられた nib ファイルからビューをロードしようとします。ビュー コントローラに nib ファイルが関連付けられていない場合は、 loadViewメソッドをオーバーライドし、それを使用してルート ビューとそのすべてのサブビューを作成する必要があります。

于 2011-02-09T15:10:38.447 に答える
1

私の場合、rootViewController を実際に 2 回割り当てたことに気付きませんでした。

application:didFinishLaunchingWithOptions:applicationDidBecomeActive:

于 2014-03-18T03:11:38.520 に答える
1

これに加えて、TouchID などのシステム関数を使用している場合、 AppDelegate のapplicationWillResignActiveが呼び出されます。たとえば、コントローラーをセキュア ルート コントローラーにリセットすると、再度呼び出され、performSegueWithIdentifier(self.MAIN_SEGUE) ,sender: self)は起動しません!

于 2016-02-18T07:43:58.480 に答える
0

これは、ビューを構築するためにxibsを使用して、プロジェクトをストーリーボードから古い方法にマージしたときに発生しました。元に戻す主な理由は、モーダルビューを適切に表示できなかったためです。私が通常行う方法は、UIButtonからのデリゲートメソッドで特定のビューコントローラーのインスタンスを構築し、そのプロパティの一部を設定して(最も重要なものはデリゲートであるため、モーダルビューコントローラーを再度適切に閉じることができます)、次に表示することです。モーダルな方法で。新しいストーリーボードの方法では、これはおそらくセグエで行われます。遷移のカスタマイズは、UIStoryboardSegueクラスを拡張するカスタムクラスを作成することによってのみ実行できます。以前の単純な方法と比較して、この方法は非常に面倒であることがわかったので、マージして戻しました。

これにより、ViewControllerが2回ロードされるようになりましたか?ストーリーボードプロジェクトからxibプロジェクトにコードを転送するときに、いくつかのxib(ViewControllerごとに1つ)を作成し、ストーリーボードからviewcontrollerオブジェクトをコピーしました。これにより、viwではなくviewcontrollerを含むxibが作成されました。つまり、ビューコントローラーをビューコントローラーに配置しました(ファイルの所有者もビューコントローラーのインスタンスであるため)。あなたの場合、あなたがこの問題を抱えているとは思いませんが、いつか誰かに役立つことを願っています。

これを修正するには、ビューをビューコントローラからビューコントローラからオブジェクトセクションのルートレベルに移動します。ビューコントローラとそのナビゲーションアイテムの両方を削除する必要があります。ビルドして実行すると、ViewControllerの割り当てが1つだけ表示されます。これはファイルの所有者です。

于 2011-11-21T08:15:06.150 に答える