2つのタブを持つtabBarControllerがあり、最初のタブにはNavigatorControllerのインスタンスが含まれています。 navigatorControllerは、tableView上のすべてのネットワークピアを一覧表示するカスタムviewController「peersViewController」で開始されます。ピアを選択すると、「FilesListViewController」(c:\ディレクトリ内のファイルを一覧表示する)のインスタンスがnavigationControllerスタックにプッシュされます。
このfilesListViewControllerには、ドキュメントディレクトリに移動するためのボタンがあります。これを行うには、rootViewControllerのgotoDirectory:(NSString *)pathメソッドを呼び出すようにインターフェイスを配線しました。
- (void)gotoDirectory:(NSString*)path {
[[self navigationController] popToRootViewControllerAnimated:YES];
NSArray *files = [self getFilesFromPeerAtPath:path];
FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files];
[[self navigationController] pushViewController:filesVC animated:YES];
[filesVC release];
}
ただし、そのボタンを押すと、navigationControllerはビューをルートView Controllerにポップしましたが、インスタンス化したFilesListViewControllerは表示されませんでした。ログから、カスタムinitWithFilesメソッドが実際に呼び出され、ネットワーク関連のものがファイル名を取得したことがわかります。
他の何かがこれについて厄介です。 2番目のタブをクリックしてから、最初のタブに戻って、hualaを試してみました。必要なファイル名はそこにあります。データとfilesListViewControllerが実際にnavigatorControllerスタックにプッシュされたように見えますが、表示は更新されず、rootViewController(peersViewController)の画面でスタックしました。
私は何か間違ったことをしていますか?
-ベン。
-質問を投稿してから15分後に編集しました。回避策を見つけましたが、ポップしてからプッシュが機能しないのが気になります。
- (void)gotoDirectory:(NSString*)path {
PeersListViewController *rootViewController = (PeersListViewController*)[[[self navigationController] viewControllers] objectAtIndex:0];
[[self navigationController] setViewControllers:[NSArray arrayWithObject:rootViewController]];
FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files];
[[self navigationController] pushViewController:filesVC animated:YES];
[filesVC release];
}
この方法でnavigationControllerを回避する必要はないようです。おそらく、元のスタックにあったすべてのviewControllerを解放する必要があります。ただし、これはiphone3.0シミュレーターでは機能します。
ただし、このコードを使用している場合、メモリ解放はどのように処理する必要がありますか?ビューコントローラの元のNSArrayを取得して、すべてを解放する必要がありますか?
この問題の問題と解決策は、実際には非常に単純です。
[self.navigationController popToRootViewControllerAnimated:YES]
を呼び出すと、self.navigationController
がnil
に設定されます。その後[self.navigationController pushViewController:someOtherViewController]
を呼び出すと、事実上nil
にメッセージが送信されますが、これは何もしません。
回避するには、navigationControllerへのローカル参照を設定し、代わりにそれを使用します。
UINavigationController * navigationController = self.navigationController;
[navigationController popToRootViewControllerAnimated:NO];
[navigationController pushViewController:someOtherViewController animated:YES];
Jasonが述べたように、これが正しく機能するには、popToRootViewControllerをアニメーションなしで実行する必要があります。
これを指摘してくれた jpimbert on Apple forums に感謝します。
非常によく似た問題が発生しました(ただし、タブを使用していません)。
3つのviewController : main(root)
、フォーム、結果を取得しました。 UINavigationController
スタックが
"main -> result"
btnClickで、popToRootViewControllerAnimated
を実行してから、formViewCtrlをプッシュします。持っているために
"main -> form"
ナビゲーションバーのタイトルと戻るボタンのラベルが正しく、formViewCtrlのイベントが呼び出されます。しかし、私はまだメインビューを見ています。
これが私の「解決策」です
いくつかのテストを行った後、私はrootViwCtrlに移動するアニメーションなしでこれは正常に機能するであることがわかりました。そのため、アニメーションを使用してviewCtrlをプッシュするだけです。
iPhone 3.0、デバイスとシミュレータで問題が見つかりました。
何か新しいものがあれば、投稿を更新/コメントします。
ルートにポップしてから新しいViewControllerをプッシュすることに関するこの質問はかなり一般的であり、この投稿は頻繁に表示されるので、他の新しい人、特にXcode4とストーリーボードを使用している人を助けるために少し追加したいと思いました。
Xcode 4には、ストーリーボードがあります。次のビューコントローラがあるとします:HomeViewController、FirstPageViewController、SecondPageViewController。必ずそれぞれをクリックし、[ユーティリティ]ペイン-> [属性インスペクター]に移動して識別子に名前を付けてください。それらの名前は、Home、First、およびSecondと言います。
あなたはホームです、次にファーストに行き、次にセカンドに行き、戻るボタンを押してホームに戻ることができるようにしたいです。これを行うには、FirstPageViewControllerのコードを変更します。
例を拡張するには、ストーリーボードのFirstPageViewControllerにボタンを作成します。 Ctrlキーを押しながらそのボタンをFirstPageViewController.mにドラッグします。そこでは、次のコードが目的の結果を達成します。
// Remember to add #import "SecondPageViewController.h" at the top
SecondPageViewController *secondView = [self.storyboard instantiateViewContorllerWithIdentifier:@"Second"];
UINavigationController *navigationController = self.navigationController;
NSArray *array = [navigationController viewControllers];
// [array objectAtIndex:0] is the root view controller
NSArray *viewControllersStack = [NSArray arrayWithObjects:[array objectAtIndex:0], secondView, nil];
[navigationController setViewControllers:viewControllersStack animated:YES];
基本的には、View Controllerを取得し、必要な順序でスタックに配置してから、ナビゲーションコントローラーにそのスタックをナビゲーションに使用させることになります。これは、プッシュとポップの代替手段です。
回避策を見つけましたが、なぜ機能するのか説明できません。1。最初に必要なコントローラーをプッシュします。 2.次に、目的の場所にポップします。
これは完全に非論理的ですが、私の場合はうまくいきます。明確にするために、私は次のシナリオでそれを使用しています:最初の画面->ロード画面に移動-> 2番目の画面2番目の画面にいるとき、ロード画面をスタックに入れたくないクリックして戻ると、最初の画面に移動する必要があります。
よろしく、ベスココレフ
Nick Streetの答えは、popToRootViewControllerを実行してから、別のVCをプッシュする場合に役立ちます。
VC1-> VC2-> VC3:VC3から戻るボタンを押す=> VC2、次にVC1、ここではOK
ただし、VC1がVC2をプッシュし、次にVC3がプッシュされると、VC3から直接VC1に戻ることは期待どおりに機能しません。
VC3の-(void)viewWillDisappear:(BOOL)animated
に実装しました:
-(void)viewWillDisappear:(BOOL)animated{
...
[self.navigationController popToRootViewControllerAnimated:YES];
}
また、「戻るボタン」に実装しようとしましたが、同じ結果です。VC3から戻るボタンを押してVC1に戻ると、壊れます。実際のVCはVC1ですが、ナビゲーションバーはVC2のままです。他の組み合わせで遊んでいると、VC2にVC1のnavBarが表示されます。
Lodaはタイミングについて何か言及しました。それがここでの主な問題だと思います。私はいくつかのことを試したので、ここで何かを見逃しているかもしれませんが、これが私にとってついにうまくいったことです:
VC3の場合:
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// notify VC2
[[NSNotificationCenter defaultCenter] postNotificationName:backFromV3 object:self];
}
VC2の場合:
-(void)viewDidLoad {
...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backFromV3)
name:@"BackFromV3"
object:nil];
}
-(void)backFromV3{
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:@selector(backToRootViewController)
userInfo:nil
repeats:NO];
}
-(void)backToVC1 {
self.navigationItem.rightBarButtonItem = nil;
[self.navigationController popToRootViewControllerAnimated:YES];
}
もちろん、必要な清掃を行ってください。
ここではタイマーが重要です。 0の場合、壊れます。 0.5は大丈夫のようです。
それは私にとって完璧に機能します。少し重いですが、うまくいくものは何も見つかりませんでした。
基本的に、ポップアニメーションが完了するまでプッシュアニメーションを遅らせることで、実際に「戻る」アニメーションを維持し、続いて「進む」アニメーションを維持することができます。次に例を示します。
(注:appDelegateに "transitionTo"というNSString変数があり、最初は@ ""に設定されています)...まず、後で検出できるように、その変数をNSStringに設定します。次に、コントローラーをポップして、ルートに戻る素敵な画面遷移を提供します。
appDelegate.transitionTo = @"Another";
[detailNavigationController popToRootViewControllerAnimated:YES];
次に、rootviewcontrollerのクラス内で、viewDidAppearメソッドを使用します。
-(void)viewDidAppear:(BOOL)animated
{
AppDelegate *appDelegate =(AppDelegate*) [UIApplication sharedApplication].delegate;
if([appDelegate.transitionTo isEqualToString:@"Another"])
{
[self transitionToAnotherView];
appDelegate.transitionTo = @"";
}
}
-(void)transitionToAnotherView
{
// Create and Push new view controller here
AnotherViewController *controller = [[AnotherViewController alloc] init];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:nil action:nil];
[self.navigationItem setBackBarButtonItem:backButton];
[[self navigationController] pushViewController:controller animated:YES];
}
したがって、基本的には、ルートにポップします...遷移が「viewDidAppear」で終了したら...次に次のビューをプッシュします。たまたま、どのビューに移行するかを示す変数を保持しました(@ ""は、この画面にとどまりたい場合に移行を行わないことを意味します)。