9

タブ付きのアプリケーションテンプレートから作成したアプリケーションがあります。(ARC、iOS 4)

  • いくつかのタブがあり、2。タブviewcontroller.view(ViewCont2)にボタンがあります。
  • このボタンは、presentModalViewControllerメソッドによって別のviewcontrollerの(ModalViewCont)ビューをロードします。
  • ModalViewContには、dismissModalViewControllerAnimatedを呼び出す閉じるボタンがあります。
  • ViewCont2のviewDidDisappearで、ビューをアンロードするためにself.view = nilおよびその他のアウトレットをnilに設定しているので、次に画面に表示されたときにビューが新しくロードされます。これを行っているのは、ビューコントローラのいくつかの一般的なプロパティを初期化し、viewDidLoadメソッドにいくつかのボタンやラベルなどを追加する基本クラス(BaseViewCont)を継承しているためです。したがって、この基本クラスから継承するViewControllerは、viewDidLoadメソッドで必要に応じてこれらのプロパティを異なる方法で構成できます。

問題

これで、ModalViewContが画面に表示されているときに、ホームボタンを押してアプリケーションをバックグラウンドに戻し、アプリケーションを元に戻した後、ModalViewContを閉じると、ViewCont2のビューは返されませんが、下部にタブバーがある黒い画面になります。アプリケーションのバックグラウンド/フォアグラウンドを設定しなくても同じことが起こります。2.タブをタップする前に他のタブをタップした場合(編集:これは、viewDidDisappearではなくviewWillDisappearでself.viewがnilに設定されている場合にのみ発生します。)

ViewCont2が新しいビューをロードすると判断しました(参照を確認しました)が、ビューのスーパービューがnilであるため、新しいビューは表示されず、黒い画面が表示されます。

うまくいかなかったこと

  • [self.viewremoveFromSuperview]を使用します。self.view = nilを設定する前に、
  • viewWillAppearで、親にビューを追加します。[self.parentViewController.view addSubview:self.view]; これはスムーズに機能しませんでした。ビューは画面の少し上に配置されました。これは、階層に他のいくつかのスーパービューがあるためです。

私が検討したソリューション。

  • 1-スーパービューがviewDidLoadでnilの場合、viewWillAppear (仮定)で使用可能になります。したがって、ViewCont2のviewWillAppearメソッドを使用して、次の方法でスーパービューを正しくロードできます。

_

if (self.view.superview == nil)
{
    self.tabBarController.selectedViewController = nil;
    self.tabBarController.selectedViewController = self;
}
  • 2-基本クラスのviewWillAppearメソッドを代わりに初期化に使用できるため、ビューをアンロードする必要はありません。したがって、パフォーマンスを最適化することができ、ビューが消えるたびにアンロードされることはありません。また、フラグが表示されるたびに実行するのではなく、フラグをチェックして初期化を1回だけ実行することをお勧めします。

質問

  • 1-スーパービューが復元されないのはなぜですか?私はそれのために何をすべきですか?(これは、代替案を試すのではなく、理解して解決したい主な問題です...)
  • 2-アンロードするために表示するnilを割り当てることで、何か問題が発生していますか?もしそうなら、このような場合(タブ付きアプリケーション)にビューを適切にアンロードするにはどうすればよいですか?
  • 3- 1.ソリューションに何か問題がありますか?応急修理のように見えますか?superviewとviewWillAppearに関するその仮定は正しいですか?

編集: viewDidLoadが必要以上に早く呼び出された場合(つまり、viewDidDisappearではなくviewWillDisappearでビューがnilledされた場合)、スーパービューが設定されていないようです。

4

6 に答える 6

7

奇妙に思えますが、あなたの提案(1)は、この問題の正しい回避策です。

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    if (!self.view.superview) { // check if view has been added to view hierarchy
        self.tabBarController.selectedViewController = nil;
        self.tabBarController.selectedViewController = self;
    }
}

2番目の提案はパフォーマンスに適しています(ビューの読み込みはコストのかかる操作であるため)が、問題は解決しません。次の状況では、ビューをnilに設定せずに画面が黒くなることもあります(iOSシミュレーターでこれをテストしてください)。

  1. モーダルビューを開く
  2. メモリ警告をシミュレートします->これによりタブバーコントローラーのビューがアンロードされます
  3. ホームボタンを押して、アプリをもう一度開きます
  4. モーダルビューを閉じる->黒い画面

一般に、viewDidLoadではviewプロパティが設定されており、viewWillAppear+viewDidAppearではビューがビュー階層に追加されていると想定できます。したがって、スーパービューはその時点で存在する必要があります(ここで、スーパービューはクラスUIViewControllerWrapperViewのタブバーコントローラーのプライベートビューです)。ただし、この場合、ビューは(アプリの再開時に)再ロードされますが、ビュー階層に追加されないため、画面が黒くなります。これはUITabBarControllerのバグのようです。

回避策により、外観セレクターが再度実行されます。そのため、今回はスーパービューが設定された状態で、viewWillAppearが再度呼び出されます。また、viewDidAppearは2回呼び出されます!

self.viewをnilに設定することは問題ありませんが、ほとんどの場合必要ではありません。ビューをアンロードするタイミングをシステムに決定させます(メモリが少なくなると、iOSはビューをアンロードできます)。ビューコントローラのコードは、ビューをリロードせずにいつでもUIを再構成できるように設計する必要があります。

于 2012-08-24T21:46:55.217 に答える
1

ビューがいつロードおよびアンロードされるかを完全に制御することはできません。また、ビューを手動でロード/アンロードすることは想定されていません。

UIViewController代わりに、ビューのロード/アンロードは完全に自分の責任であり、次のことだけを担当するものと考える必要があります。

  • UIViewControllerサブクラスをnibファイルに関連付けるか、手動で実装することにより、実際の読み込みを実装しますloadView
  • オプションでviewDidLoadviewWillUnloadおよびコールバックを実装します。これらは、ビューのロード/アンロードを決定したときviewDidUnloadビューコントローラーによって呼び出されます。

上記のコールバックがいつ呼び出されるかを完全に制御できないという事実は、それらに何を入れるべきかについての意味合いを持っています。

あなたの場合、私が正しく理解していれば、ViewCont2のビューが消えたときはいつでも、再表示されたときに「クリーン」な状態になるようにリセットする必要があります。この状態リセットをいくつかのメソッドで実装し、fromviewDidLoadとfromの両方で呼び出しますviewDidDisappear。または、に「クリーン」ロジックを含めることもできますviewWillAppear

または、現在のボタンがタップされたときにのみViewCont2のビューをクリーンアップしたいですか?viewDidLoadその場合は、とボタンをタップしたときの両方でビューをクリーンアップします。

于 2012-08-24T22:05:01.030 に答える
1

私が提供するのは、モーダルビューコントローラーがアクティブで、ビューを閉じたときに、ナビゲーションビューコントローラーのviewControllersに新しいビューを追加すると、そのビューはその前のビューを削除するように指示されるということです。

あなたは私のプロジェクトで遊んで、それがあなたのために働くと思うかどうか見ることができます。

編集:選択された答えに対する私のコメントは、このテクニックは明らかに今は機能しているということですが、私自身はそれをフォローするのに苦労しています。私のプロジェクトのコードは、システムをシンプルで直接的な方法で使用しています-モーダルビューがそれ自体を閉じるように指示されると、ナビゲーションコントローラーの配列に新しいビューを追加するメソッド(任意のクラスにある可能性があります)を呼び出してから、それ自体を閉じます。しばらくの間、同じ時間の2つのView Controllerがあり、新しいものが古いものの上にスタックされています。新しいViewControllerが表示されると、フラグが静かに表示され、舞台裏で不要なviewControllerがnabバーのスタックから削除され、poofが消えます。

于 2012-08-25T02:26:13.167 に答える
1

UITabBarControllerのバグに対する実際の解決策を見つけました(メモリ警告、アプリがバック/フォアグラウンドに入る、モーダルを閉じる)。ルートビューコントローラーとしてUITabBarControllerを使用すると、バグの原因になります。したがって、別のView ControllerをルートViewControllerとして使用し、そこからタブバーを表示することができます。iOS5.1シミュレーターでテストしました。

もちろん、追加のUIViewControllerのオーバーヘッドについては議論の余地があります。また、それはAppleのドキュメントに反します。

他のViewControllerとは異なり、タブバーインターフェイスを別のViewControllerの子としてインストールしないでください。UITabBarControllerクラスリファレンス

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // A root view controller other than the actual UITabBarController is required.
    self.window.rootViewController = [[UIViewController alloc] init];
    [self.window makeKeyAndVisible];    
    self.tabBarController = [[UITabBarController alloc] init];
    self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, ..., nil];

    [self.window.rootViewController 
        presentModalViewController:self.tabBarController animated:NO];
}
于 2012-08-27T15:52:03.683 に答える
0

私は他の解決策を見つけました。

  • 最初のものは警告を引き起こします:ルートビューコントローラーがありますが、「アプリケーションウィンドウはアプリケーション起動の終わりにルートビューコントローラーを持っていると予想されます」。

  • ぎこちないように見えますが、一時的なビューコントローラは最初のものでリリースされます。

  • 2番目のものはより合理的なようです。

- (void) tabBarBlankScreenFix1
{
    self.window.rootViewController = [[UIViewController alloc] init];
    [self.window makeKeyAndVisible];
    [self.window addSubview:self.tabBarController.view];            
    self.window.rootViewController = self.tabBarController;

}

- (void) tabBarBlankScreenFix2
{
    self.window.rootViewController = [[UIViewController alloc] init];
    [self.window makeKeyAndVisible];
    [self.window addSubview:self.tabBarController.view];
}
于 2012-08-31T16:56:08.660 に答える
-1

ビューをnilに割り当てるべきではないと思います。私があなたの言うことを正しく理解しているなら、あなたはビューが表示されるたびにコンテンツを更新/再ロードしたいと思うでしょう。したがって、ビューをnilに設定する代わりに、ビューを更新してみてください。次を追加することでそれを行うことができます:

    - (void)viewWillAppear{
    [self.view setNeedsDisplay];}

私があなたの問題を正しく理解しているかどうか教えてください

于 2012-08-19T00:04:03.600 に答える