24

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によってビューがルートビューコントローラーにポップされましたが、インスタンス化したFilesListViewControllerが表示されませんでした。ログから、カスタムinitWithFilesメソッドが実際に呼び出され、ネットワークスタッフがファイル名を取得したことがわかります。

他の何かがこれについて厄介です。2番目のタブをクリックしてから、最初のタブに戻ってクリックしてみました。必要なファイル名はそこにあります。データと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を取得して、すべてを解放する必要がありますか?

4

6 に答える 6

86

この問題の問題と解決策は、実際には非常に単純です。

呼び出しはに[self.navigationController popToRootViewControllerAnimated:YES]設定self.navigationControllernilます。その後電話をかける[self.navigationController pushViewController:someOtherViewController]と、効果的にメッセージをに送信しますがnil、これは何もしません。

回避するには、navigationControllerへのローカル参照を設定し、代わりにそれを使用します。

UINavigationController * navigationController = self.navigationController;
[navigationController popToRootViewControllerAnimated:NO];
[navigationController pushViewController:someOtherViewController animated:YES];

Jasonが述べたように、これが正しく機能するには、popToRootViewControllerをアニメーションなしで実行する必要があります。

これを指摘してくれたAppleフォーラムのjpimbertに感謝します。

于 2010-12-11T02:18:28.723 に答える
11

非常によく似た問題が発生しました(ただし、タブを使用していません)。

viewController : main(root)form と resultの 3 つを取得しました。UINavigationControllerスタックが

"main -> result"

btnClickpopToRootViewControllerAnimatedで、formViewCtrl をプッシュします。持つために

"main -> form"

navbar のタイトルと戻るボタンのラベルが正しく、formViewCtrl のイベントが呼び出されます。しかし、私はまだメインビューを見ています。

これが私の「解決策」です

いくつかのテストを行った後、rootViwCtrl に移動するアニメーションがなくても、これは正常に機能することがわかりました。そのため、アニメーションを使用してviewCtrlを押すだけです。

iPhone 3.0、デバイスとシミュレータで問題が見つかりました。

何か新しいことがあれば、投稿を更新/コメントします。

于 2009-09-17T12:55:40.620 に答える
4

ルートにポップしてから新しい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を取得し、必要な順序でスタックに配置してから、ナビゲーションコントローラーにそのスタックをナビゲーションに使用させることです。これは、プッシュとポップの代替手段です。

于 2012-05-10T05:47:57.713 に答える
1

回避策を見つけましたが、それが機能している理由を説明できません。1.最初に必要なコントローラーをプッシュします。2.次に、目的の場所にポップします。

これは完全に非論理的ですが、私の場合は機能します。わかりやすくするために、次のシナリオで使用しています。最初の画面->ロード画面に移動-> 2番目の画面2番目の画面を表示しているときに、ロード画面をスタックに入れたくないクリックして戻ると、最初の画面に移動する必要があります。

よろしく、ベスココレフ

于 2009-10-29T13:45:23.687 に答える
1

popToRootViewController を作成し、その後別の VC をプッシュしたい場合は、Nick Street の回答がうまく機能します。

VC1 -> VC2 -> VC3: VC3 => VC2、次に VC1 から戻るボタンを押して、ここで OK

ただし、VC1 が VC2 をプッシュし、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なら大丈夫そうです。

それは私にとって完璧に機能します。少し重いですが、トリックを行うものを見つけることができませんでした.

于 2011-10-10T13:58:36.810 に答える
1

基本的に、ポップ アニメーションが完了するまでプッシュ アニメーションを遅らせることで、「戻る」アニメーションを保持し、その後に「進む」アニメーションを続けることができます。次に例を示します。

(注: 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」でトランジションが終了したら、次のビューをプッシュします。どのビューに遷移したいかを示す変数をたまたま保持していました (@"" は、この画面にとどまりたい場合に遷移を行わないことを意味します)。

于 2012-03-22T19:16:19.750 に答える