2つのビューコントローラーを備えたnavコントローラースタックがあるとします。VC2が上にあり、VC1が下にあります。 VC2がスタックからポップされたことを検出するコードをVC1に含めることができますか?
VC1のコード内からVC2のポップを検出しようとしているので、viewWillAppearまたはviewDidAppearのようなものは機能しないようです。 VC1は、スタックに最初にプッシュされたときを含めて表示されます。
編集:元の質問ではあまり明確ではなかったようです。ここで私がやろうとしていることは次のとおりです。VC2がスタックの一番上からポップされたためにVC1がいつ表示されるかを決定します。ここで私がやろうとしていないことは次のとおりです。VC1がスタックの一番上にプッシュされたために表示されているかどうかを判断します。最初のアクションを検出し、2番目のアクションは検出しない方法が必要です。
注:VC2については特に気にしません。スタックからポップされる他のVCがいくつあってもかまいません。気にするのは、VC1が他のVCは上部からポップされ始めます。
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:ロジックを反転し、早期に戻らないことにより、例をより明確にしました。
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スタックを所有するデリゲートとより緊密に結合することになり、よりスタンドアロンのソリューションが必要になります。これは動作します。
これにアプローチできる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 。
ポップされているView Controllerで検出することもできます
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController]) {
....
}
}
これは私のために働いています
UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey];
if (![[self.navigationController viewControllers] containsObject:fromViewController] && !self.presentedViewController)
{
//Something is being popped and we are being revealed
}
スイフト3
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if self.isMovingToParentViewController {
print("View is moving to ParentViewControll")
}
}
はい、VC1でVC2がポップされているかどうかを確認できます。 UINavigationControllerには、1つのメソッドviewControllersがあります。これは、プッシュされた配列を返しますControllersは、スタック内にあります(つまり、プッシュされています)。
したがって、クラスを比較してループを反復処理します。 VC2が存在する場合は一致しますが、そうでない場合は一致しません。
具体的に何をしようとしていますか?
VC1が表示されようとしていることを検出しようとしている場合は、 this answerが役立ちます。 INavigationControllerDelegate を使用します。
VC2が隠されようとしていることを検出しようとしている場合は、 viewWillDisappear:
VC2の。
同じ状況になりましたが、少し具体的なユースケースがあります。私の場合、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")
}
}