viewWillDisappear: Görünüm denetleyicisinin atmış olup olmadığını veya bir alt görünüm denetleyicisi gösterip göstermediğini belirleme


134

Bu soruna iyi bir çözüm bulmak için uğraşıyorum. Bir görünüm denetleyicisinin -viewWillDisappear:yönteminde, bir görünüm denetleyicisinin gezinti denetleyicisinin yığınına itilmiş olup olmadığını veya görünüm denetleyicisinin atmış olduğu için kaybolup kaybolmadığını belirlemenin bir yolunu bulmam gerekir.

Şu anda bayraklar ayarlıyorum isShowingChildViewControllerama oldukça karmaşıklaşıyor. Bunu algılayabileceğimi düşündüğüm tek -deallocyöntem yöntemde.

Yanıtlar:


228

Aşağıdakileri kullanabilirsiniz.

- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  NSArray *viewControllers = self.navigationController.viewControllers;
  if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
    // View is disappearing because a new view controller was pushed onto the stack
    NSLog(@"New view controller was pushed");
  } else if ([viewControllers indexOfObject:self] == NSNotFound) {
    // View is disappearing because it was popped from the stack
    NSLog(@"View controller was popped");
  }
}

Bu elbette mümkündür, çünkü UINavigationController'ın görünüm denetleyicisi yığını (viewControllers özelliği aracılığıyla gösterilmektedir) viewWillDisappear çağrıldığında güncellenmiştir.


2
Mükemmel! Neden böyle düşünmediğimi bilmiyorum! Sanırım kaybolma yöntemleri çağrılıncaya kadar yığının değiştirileceğini düşünmemiştim! Teşekkürler :-)
Michael Waterfall

1
Ben sadece aynı şeyi gerçekleştirmek için çalışıyorum ama içinde viewWillAppearve görünüm denetleyicisi itiliyor ya da üzerinde bir şey attı tarafından ifşa olup olmadığını, viewControllers dizi her iki şekilde aynı gibi görünüyor! Herhangi bir fikir?
Michael Waterfall

Ayrıca, görünüm denetleyicisinin uygulamanın ömrü boyunca kalıcı olduğunu da not etmeliyim, bu yüzden eylemlerimi viewDidLoadsadece bir kez çağrıldığı için yapamıyorum ! Hmm, zor olan!
Michael Waterfall

4
@Sbrocket ![viewControllers containsObject:self]bunun yerine yapmadığınız bir sebep var [viewControllers indexOfObject:self] == NSNotFoundmı? Stil seçimi?
zekel

24
Bu yanıt iOS 5'ten beri kullanılmıyor. Aşağıdaki -isMovingFromParentViewControlleryöntem, görünümün açıkça atlanıp atlanmadığını test etmenizi sağlar.
grahamparks

136

Bence en kolay yol:

 - (void)viewWillDisappear:(BOOL)animated
{
    if ([self isMovingFromParentViewController])
    {
        NSLog(@"View controller was popped");
    }
    else
    {
        NSLog(@"New view controller was pushed");
    }
    [super viewWillDisappear:animated];
}

Swift:

override func viewWillDisappear(animated: Bool)
{
    if isMovingFromParent
    {
        print("View controller was popped")
    }
    else
    {
        print("New view controller was pushed")
    }
    super.viewWillDisappear(animated)
}

İOS 5'ten itibaren bu cevap, belki de kontrol edinBeingDismissed
d370urn3ur

4
İOS7 için [self.navigationController.viewControllers indexOfObject: self] == NSNotFound öğesini tekrar kontrol etmeliyim çünkü uygulamanın arka planı bu testi geçecek, ancak kendini navigasyon yığınından kaldırmayacak.
Eric Chen

3
Apple bunu yapmak için belgelenmiş bir yol sağladı - stackoverflow.com/a/33478133/385708
Shyam Bhat

ViewWillDisappear kullanmayla ilgili sorun, görünüm zaten kaybolmuş durumdayken denetleyicinin yığından çıkarılmasıdır. Örneğin, başka bir viewcontroller yığının üstüne itilebilir ve daha sonra popToRootViewControllerAnimated çağrısı görüntülenebilir.
John K

Gezinme yığınınızda iki denetleyiciniz olduğunu (kök vc ve başka bir itilmiş) varsayalım. Üçüncüsü itildiğinde viewWillDisappear, görünümü kaybolacak olan ikincisinde çağrılır, değil mi? Bu nedenle, kök görünüm denetleyicisine (üçüncü ve ikinci pop) pop yaptığınızda viewWillDisappear, üçüncü görünümde yani yığındaki son vc'de çağrılır, çünkü görünümü üstte ve şu anda kaybolacak ve saniyenin görünümü zaten kaybolmuş olacaktır. Bu yüzden bu yönteme viewControllerWillBePopped değil, viewWillDisappear denir.
RTasche

61

Apple'ın UIViewController.h içindeki Dokümantasyonundan:

"Bu dört yöntem, bir görünüm denetleyicisinin görünüm geri çağrılarında, bir alt görüntüleme denetleyicisi olarak sunulup sunulmadığını, işten çıkarılmadığını veya eklenip kaldırılmadığını belirlemek için kullanılabilir. Örneğin, bir görünüm denetleyicisi, işten çıkarıldığı için yok olup olmadığını kontrol edebilir veya viewWillDisappear: yöntemini ([self isBeingDismissed] || [self isMovingFromParentViewController]) ifadesini kontrol ederek kendisini sorarak attı. "

- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0);

- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0);

- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0);

- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0);

Yani evet, bunu yapmanın tek belgelenmiş yolu şu şekildedir:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if ([self isBeingDismissed] || [self isMovingFromParentViewController]) {
    }
}

Swift 3 sürümü:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    if self.isBeingDismissed || self.isMovingFromParentViewController { 
    }
}

19

Eğer sadece görünüm attı elde olup olmadığını bilmek istiyorsanız, sadece keşfetti self.navigationControllerolduğu niliçinde viewDidDisappearo denetleyicilerin yığını kaldırıldığında,. Yani bu basit bir alternatif test.

(Bu, diğer her türlü bükülmeyi denedikten sonra keşfettim. Pop'larda bildirilmek üzere bir görünüm denetleyicisini kaydetmek için gezinme denetleyici protokolü olmadığına şaşırdım. UINavigationControllerDelegateGerçek ekran çalışması gerçekten işe yaradığından kullanamazsınız .)


16

Hızlı 4

override func viewWillDisappear(_ animated: Bool)
    {
        super.viewWillDisappear(animated)
        if self.isMovingFromParent
        {
            //View Controller Popped
        }
        else
        {
            //New view controller pushed
        }
    }

6

Swift'te:

 override func viewWillDisappear(animated: Bool) {
    if let navigationController = self.navigationController {
        if !contains(navigationController.viewControllers as! Array<UIViewController>, self) {
        }
    }

    super.viewWillDisappear(animated)

}

Olarak kullandığınızdan emin olun! as
dfmuir

2

Apple'ın bu konudaki belgelerini anlamak zor. Bu uzantı, her gezinmede durumları görmenize yardımcı olur.

extension UIViewController {
    public func printTransitionStates() {
        print("isBeingPresented=\(isBeingPresented)")
        print("isBeingDismissed=\(isBeingDismissed)")
        print("isMovingToParentViewController=\(isMovingToParentViewController)")
        print("isMovingFromParentViewController=\(isMovingFromParentViewController)")
    }
}

1

Bu soru oldukça eski ama kazara gördüm, bu yüzden en iyi uygulamayı göndermek istiyorum (afaik)

sadece yapabilirsin

if([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
 // view controller popped
}

1

Bu iOS7 için geçerlidir, başkaları için geçerli olup olmadığı hakkında bir fikir yoktur. Bildiğim kadarıyla, viewDidDisappeargörünümde zaten patladı. Yani sorguladığınızda self.navigationController.viewControllersbir nil. Yani bunun sıfır olup olmadığını kontrol edin.

TL; DR

 - (void)viewDidDisappear:(BOOL)animated
 {
    [super viewDidDisappear:animated];
    if (self.navigationController.viewControllers == nil) {
        // It has been popped!
        NSLog(@"Popped and Gone");
    }
 }

1

Segues, iOS 6+ sürümünde bu sorunu çözmenin çok etkili bir yolu olabilir. Belirli bir segue'e Interface Builder'da bir tanımlayıcı verdiyseniz, bunu kontrol edebilirsiniz prepareForSegue.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"LoginSegue"]) {
       NSLog(@"Push");
       // Do something specific here, or set a BOOL indicating
       // a push has occurred that will be checked later
    }
}

1

Ryan Henry, Swift 5'te hala çalışıyor

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let controllers = navigationController?.children{
            if controllers.count > 1, controllers[controllers.count - 2] == self{
                // View is disappearing because a new view controller was pushed onto the stack
                print("New view controller was pushed")
            }
            else if controllers.firstIndex(of: self) == nil{
                // View is disappearing because it was popped from the stack
                print("View controller was popped")
            }
        }

    }

-1

Demek istediğim, yığına doğru ittiğinizde yeni bir görünüm iterek görünümünüzün gezinti denetleyicisinin yığınından aşağıya doğru hareket ettiğini kastediyorum. Ben kullanarak öneririm viewDidUnloadbir ekleme yöntemi NSLogsize neler olduğunu görebilmek için konsola yazma şeye deyimi, bir eklemek isteyebilir NSLogiçin viewWillDissappeer.


-1

İşte sbrocket'ın cevabı ile aynı şeyi başarmak için bir kategori:

Başlık:

#import <UIKit/UIKit.h>

@interface UIViewController (isBeingPopped)

- (BOOL) isBeingPopped;

@end

Kaynak:

#import "UIViewController+isBeingPopped.h"

@implementation UIViewController (isBeingPopped)

- (BOOL) isBeingPopped {
    NSArray *viewControllers = self.navigationController.viewControllers;
    if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
        return NO;
    } else if ([viewControllers indexOfObject:self] == NSNotFound) {
        return YES;
    }
    return NO;
}

@end
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.