3つのView Controllerを備えたシンプルなアプリケーションを書いています。ルートビューコントローラーはitem listing
、基本的なテーブルビュー。このビューコントローラーから、ユーザーの操作に基づいて2つの異なるビューコントローラーをプッシュします-create item
ビューコントローラまたはview item
ビューコントローラ。
したがって、ストーリーボードセグエはVのように見えます。
私の〜の上に create item
ビューコントローラー、ユーザーが新しいアイテムを作成したときにルートビューコントローラーにポップバックし、view item
コントローラ。新しく作成したアイテムを確認できます。
これが機能しないようです。ルートビューコントローラーに戻るのは簡単ですが、それをプッシュすることはできませんview item
コントローラ。
何か案は?以下にコードを貼り付けました。 pop関数は機能しますが、新しいビューは表示されません。
- (void) onSave:(id)sender {
CLLocation *currentLocation = [[LocationHelper sharedInstance] currentLocation];
// format the thread object dictionary
NSArray* location = @[ @(currentLocation.coordinate.latitude), @(currentLocation.coordinate.longitude) ];
NSDictionary* thread = @{ @"title": _titleField.text, @"text": _textField.text, @"author": @"mustached-bear", @"location": location };
// send the new thread to the api server
[[DerpHipsterAPIClient sharedClient] postPath:@"/api/thread"
parameters:thread
success:^(AFHTTPRequestOperation *operation, id responseObject) {
// init thread object
Thread *thread = [[Thread alloc] initWithDictionary:responseObject];
// init view thread controller
ThreadViewController *viewThreadController = [[ThreadViewController alloc] init];
viewThreadController.thread = thread;
[self.navigationController popToRootViewControllerAnimated:NO];
[self.navigationController pushViewController:viewThreadController animated:YES];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self.navigationController popToRootViewControllerAnimated:YES];
}];
}
やりたいことを簡単に行う方法は、いくつかの単純なロジックをメインのルートビューコントローラー-(void)viewWillAppearメソッドに組み込み、デリゲートコールバックを使用してロジックスイッチを切り替えることです。基本的には、ルートコントローラへの「後方参照」です。これは簡単な例です。
メインルートコントローラー(このコントローラーaを検討してください)-コントローラーという名前を付けて、ジャンプステータスを追跡するプロパティを設定します
@property (nonatomic) BOOL jumpNeeded;
ロジックをセットアップする
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.jumpNeeded ? NSLog(@"jump needed") : NSLog(@"no jump needed");
if (self.jumpNeeded) {
NSLog(@"jumping");
self.jumpNeeded = NO;
[self performSegueWithIdentifier:@"controllerC" sender:self];
}
}
今、あなたのメインルートコントローラーでは、テーブルビューの行が選択されているときに、テーブルビューのcontrollerBにプッシュするときに次のようなことを行いますselectメソッド
[self performSegueWithIdentifer@"controllerB" sender:self];
次に、segueメソッドの準備を実装します
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
//setup controller B
if([segue.identifier isEqualTo:@"controllerB"]){
ControllerB *b = segue.destinationViewController;
b.delegate = self; //note this is the back reference
}
//implement controller c here if needed
}
次に、controllerBに移動します。「delegate」というプロパティを設定して、後方参照を保持し、ヘッダーファイルをルートコントローラーからインポートする必要があります。
#import "controllerA"
@property (nonatomic,weak) controllerA *delegate;
その後、controllerAに戻る直前に、フラグを設定します
self.delegate.jumpNeeded = YES;
[self.navigationController popViewControllerAnimated:YES];
そしてそれはそれについてです。 controllerCで何もする必要はありません。他にもいくつかの方法がありますが、これはあなたのニーズにとってかなり簡単です。それがあなたのためにうまくいくことを願っています。
私があなたを正しく理解していれば、View Controllerのスタックがあります。
A (root) - B - C - D - E
そして、あなたはそれがなりたいと思っています:
A (root) - F
正しい?その場合:
NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *newViewControllers = [NSMutableArray array];
// preserve the root view controller
[newViewControllers addObject:[viewControllers objectAtIndex:0]];
// add the new view controller
[newViewControllers addObject:viewThreadController];
// animatedly change the navigation stack
[self.navigationController setViewControllers:newViewControllers animated:YES];
Swift 4
// get current view controllers in stack and replace them
let viewControllers = self.navigationController!.viewControllers
let newViewControllers = NSMutableArray()
// preserve the root view controller
newViewControllers.add(viewControllers[0])
// add the new view controller
newViewControllers.add(viewThreadController)
// animatedly change the navigation stack
self.navigationController?.setViewControllers(newViewControllers as! [UIViewController], animated: true)
おもう[self.navigationController pushViewController:viewThreadController animated:YES];
は、その前のステートメントとは異なるNavigationControllerを使用しています。ルートビューコントローラーにポップした後、ナビゲーションコントローラーが失われるためです。代わりにこのコードを使用して解決してください。
UINavigationController *nav = self.navigationController;
[self.navigationController popToRootViewControllerAnimated:NO];
[nav pushViewController:viewThreadController animated:YES];
これはあなたの問題全体を解決しないと私は思います。おそらく、2つの高速ポップとプッシュがNavigationControllerを無効にする可能性があるというエラーが表示されます。
そしてそれを解決するには、2番目のビューコントローラーのviewDidDissappearメソッドでNavigationControllerをプッシュするか、メインビューコントローラー(アイテムリスト)のviewDidAppearメソッドでプッシュします。
アプリケーションで使用するDave DeLongの回答に基づいてUINavigationControllerでカテゴリを共有し、必要に応じて常に戻るボタンを機能させます。
@implementation UINavigationController (PushNewAndClearNavigationStackToParent)
- (void) pushNewControllerAndClearStackToParent:(UIViewController*)newCont animated:(BOOL)animated
{
NSArray *viewControllers = self.viewControllers;
NSMutableArray *newViewControllers = [NSMutableArray array];
// preserve the root view controller
[newViewControllers addObject:[viewControllers firstObject]];
// add the new view controller
[newViewControllers addObject:newCont];
// animatedly change the navigation stack
[self setViewControllers:newViewControllers animated:animated];
}
@end
NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *newViewControllers = [NSMutableArray array];
// preserve the root view controller
for(int i = 0; i < [viewControllers count];i++){
if(i != [viewControllers count]-1)
[newViewControllers addObject:[viewControllers objectAtIndex:i]];
}
// add the new view controller
[newViewControllers addObject:conversationViewController];
// animatedly change the navigation stack
[self.navigationController setViewControllers:newViewControllers animated:YES];
私はデイブの答えをインスピレーションとして使用し、これをスウィフトのために作成しました:
let newViewControllers = NSMutableArray()
newViewControllers.addObject(HomeViewController())
newViewControllers.addObject(GroupViewController())
let swiftArray = NSArray(array:newViewControllers) as! Array<UIViewController>
self.navigationController?.setViewControllers(swiftArray, animated: true)
同じナビゲーションコントローラ内で何らかの方法でナビゲートしたい場合は、navigationStack A.K.Aにアクセスできます。 viewControllersを実行してから、viewcontrollersを必要な順序で設定するか、いくつかを追加または削除します...これは、最もクリーンでネイティブな方法です。
UINavigationController* theNav = viewControllerToDismiss.navigationController;
UIViewController* theNewController = [UIViewController new];
UIViewController* rootView = theNav.viewControllers[0];
[theNav setViewControllers:@[
rootView,
theNewController
] animated:YES];
必要な検証を行って、例外が発生しないようにします。
ポップバックするとすべての割り当てが解除されるため、これは可能ではないと思います。
より良い方法は、データをモデルシングルトンクラスに配置し、rootviewcontrollerにポップして、ポップが終了するまでリッスンすることです。次に、モデルにデータが保存されているかどうかを確認して、新しいビューコントローラーをプッシュする必要があるかどうかを確認します。