web-dev-qa-db-ja.com

iOSはトップビューコントローラーがポップされたときにプログラムで検出する方法は?

2つのビューコントローラーを備えたnavコントローラースタックがあるとします。VC2が上にあり、VC1が下にあります。 VC2がスタックからポップされたことを検出するコードをVC1に含めることができますか?

VC1のコード内からVC2のポップを検出しようとしているので、viewWillAppearまたはviewDidAppearのようなものは機能しないようです。 VC1は、スタックに最初にプッシュされたときを含めて表示されます。

編集:元の質問ではあまり明確ではなかったようです。ここで私がやろうとしていることは次のとおりです。VC2がスタックの一番上からポップされたためにVC1がいつ表示されるかを決定します。ここで私がやろうとしていないことは次のとおりです。VC1がスタックの一番上にプッシュされたために表示されているかどうかを判断します。最初のアクションを検出し、2番目のアクションは検出しない方法が必要です。

注:VC2については特に気にしません。スタックからポップされる他のVCがいくつあってもかまいません。気にするのは、VC1が他のVCは上部からポップされ始めます。

52
JMLdev

iOS 5では、この種の状況を正確に処理するための2つの新しい方法が導入されました。探しているのは_-[UIViewController isMovingToParentViewController]_です。 docs から:

isMovingToParentViewController

View Controllerが親に追加されている途中であることを示すブール値を返します。

- (BOOL)isMovingToParentViewController

戻り値
View ControllerがコンテナView Controllerの子として追加されたために表示されている場合はYES、そうでない場合はNO。

ディスカッション
このメソッドは、次のメソッド内から呼び出された場合にのみYESを返します。

_-viewWillAppear:_
_-viewDidAppear:_

あなたの場合、次のように_-viewWillAppear:_を実装できます:

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

    if (self.isMovingToParentViewController == NO)
    {
        // we're already on the navigation stack
        // another controller must have been popped off
    }
}
_

EDIT:ここで考慮すべき微妙なセマンティックの違いがあります。特にVC2がスタックからポップしたという事実に興味がありますか? anyコントローラーのポップの結果としてVC1が明らかにされるたびに通知されますか?前者の場合、委任がより良い解決策です。 VC2を再利用するつもりがない場合は、VC1へのまっすぐな弱参照も機能します。

EDIT 2:ロジックを反転し、早期に戻らないことにより、例をより明確にしました。

63
Ryder Mackay

isMovingTo/FromParentViewControllerは、Navigation Controllerスタックへのプッシュおよびポップでは機能しません。

(デリゲートを使用せずに)信頼できる方法を次に示しますが、おそらくiOS 7以降のみです。

UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey];

if ([[self.navigationController viewControllers] containsObject:fromViewController])
{
    //we're being pushed onto the nav controller stack.  Make sure to fetch data.
} else {
    //Something is being popped and we are being revealed
}

私の場合、デリゲートを使用すると、View Controllerの動作がnavスタックを所有するデリゲートとより緊密に結合することになり、よりスタンドアロンのソリューションが必要になります。これは動作します。

15
snarshad

これにアプローチできる1つの方法は、VC2のデリゲートプロトコルを次のように宣言することです。

vC1.hで

@interface VC1 : UIViewController <VC2Delegate> {
...
}

vC1.mで

-(void)showVC2 {
    VC2 *vc2 = [[VC2 alloc] init];
    vc2.delegate = self;
    [self.navigationController pushViewController:vc2 animated:YES];
}

-(void)VC2DidPop {
    // Do whatever in response to VC2 being popped off the nav controller
}

vC2.hで

@protocol VC2Delegate <NSObject>
-(void)VC2DidPop;
@end

@interface VC2 : UIViewController {

    id<VC2Delegate> delegate;
}

@property (nonatomic, assign) id delegate;

...

@end

VC2.m

-(void)viewDidUnload {
    [super viewDidUnload];
    [self.delegate VC2DidPop];
}

プロトコルとデリゲートの基本に関する良い記事があります here

7
Brad Eaton

ポップされているView Controllerで検出することもできます

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

    if ([self isMovingFromParentViewController]) {
        ....
    }
}
4
Saren Inden

これは私のために働いています

UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey];
if (![[self.navigationController viewControllers] containsObject:fromViewController] && !self.presentedViewController)
{
  //Something is being popped and we are being revealed 
}
1
chuanfeng

スイフト3

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if self.isMovingToParentViewController {
            print("View is moving to ParentViewControll")
        }
}
0
iParesh

はい、VC1VC2がポップされているかどうかを確認できます。 UINavigationControllerには、1つのメソッドviewControllersがあります。これは、プッシュされた配列を返しますControllersは、スタック内にあります(つまり、プッシュされています)。

したがって、クラスを比較してループを反復処理します。 VC2が存在する場合は一致しますが、そうでない場合は一致しません。

0
Sandy

具体的に何をしようとしていますか?

VC1が表示されようとしていることを検出しようとしている場合は、 this answerが役立ちます。 INavigationControllerDelegate を使用します。

VC2が隠されようとしていることを検出しようとしている場合は、 viewWillDisappear: VC2の。

0
darvids0n

同じ状況になりましたが、少し具体的なユースケースがあります。私の場合、VC2がVC1上のnavigationControllerにプッシュされているVC2の戻るボタンをタップしたときにVC1が表示/表示されるかどうかを判断したいと考えました。

そこで、 snarshad's answer の助けを借りて、必要に応じてカスタマイズしました。 VC1のviewDidAppear inSwift 3のコードは次のとおりです。

// VC1: ParentViewController
// VC2: ChildViewController

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        if let transitionCoordinator = navigationController?.transitionCoordinator,
            let fromVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.from),
            let toVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.to),
            fromVC is ChildViewController,
            toVC is ParentViewController {

            print("Back button pressed on ChildViewController, and as a result ParentViewController appeared")
        }
    }
0
BLC