Bir uygulama arka plandan geldiğinde viewWillAppear neden çağrılmıyor?


280

Bir uygulama yazıyorum ve kullanıcı telefonda konuşurken uygulamaya bakıyorsa görünümü değiştirmem gerekiyor.

Aşağıdaki yöntemi uyguladım:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"viewWillAppear:");
    _sv.frame = CGRectMake(0.0, 0.0, 320.0, self.view.bounds.size.height);
}

Ancak uygulama ön plana döndüğünde çağrılmaz.

Uygulayabileceğimi biliyorum:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];

ama bunu yapmak istemiyorum. Tüm düzen bilgilerimi viewWillAppear: yöntemine koymayı tercih ederim ve tüm olası senaryoları ele almasına izin veririm.

Hatta viewWillAppear'ı çağırmayı denedim: applicationWillEnterForeground: 'dan, ancak bu noktada geçerli görünüm denetleyicisi olan tam yerini belirleyemiyorum.

Bununla başa çıkmanın doğru yolunu bilen var mı? Eminim bariz bir çözümü kaçırıyorum.


1
applicationWillEnterForeground:Uygulamanızın etkin duruma ne zaman yeniden girdiğini belirlemek için kullanmalısınız .
sudo rm -rf

Soruma göre denediğimi söyledim. Lütfen yukarıya bakın. Uygulama temsilcisinin içinden geçerli görünüm denetleyicisinin hangisi olduğunu belirlemenin bir yolunu sunabilir misiniz?
Philip Walton

İhtiyaçlarınıza bağlı olarak isMemberOfClassveya kullanabilirsiniz isKindOfClass.
sudo rm -rf

@sudo rm -rf Peki bu nasıl çalışır? İskindOfClass'ı ne arayacak?
okulus

@occulus: İyilik bilir, sadece sorusunu cevaplamaya çalışıyordum. Elbette bunu yapmanın yolu gitmektir.
sudo rm -rf

Yanıtlar:


202

Yöntem viewWillAppear, başka bir uygulamadan geri döndüğünüzde uygulamanızın ön plana yerleştirilmesi bağlamında değil, kendi uygulamanızda olup bitenler bağlamında alınmalıdır.

Başka bir deyişle, bir kişi başka bir uygulamaya bakar veya bir telefon görüşmesi yaparsa, daha önce arka planda olan uygulamanıza geri dönerse, uygulamanızdan ayrıldığınızda zaten görünen UIViewController'ınız tabiri caizse - söz konusu olduğunda, asla kaybolmaz ve hala görünür - ve bu yüzden viewWillAppearçağrılmaz.

viewWillAppearKendinizi aramaya karşı öneriyorum - yıkılmamanız gereken özel bir anlamı var! Aynı etkiyi elde etmek için yapabileceğiniz bir yeniden düzenleme aşağıdaki gibi olabilir:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self doMyLayoutStuff:self];
}

- (void)doMyLayoutStuff:(id)sender {
    // stuff
}

Ardından doMyLayoutStuffuygun bildirimden de tetiklersiniz :

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doMyLayoutStuff:) name:UIApplicationDidChangeStatusBarFrameNotification object:self];

Bu arada 'güncel' UIViewController'ın hangisi olduğunu anlamanın bir yolu yok. Ancak bunun yollarını bulabilirsiniz, örneğin UIViewController'ın ne zaman sunulduğunu öğrenmek için UINavigationController temsilci yöntemleri vardır. Sunulan en son UIViewController'ı izlemek için böyle bir şey kullanabilirsiniz.

Güncelleme

Kullanıcı arayüzlerini çeşitli bitlerde uygun otomatikleştirme maskeleriyle düzenlerseniz, bazen kullanıcı arayüzünüzden 'manuel' olarak ilgilenmeniz bile gerekmez - sadece ele alınır ...


101
Bu çözüm için teşekkürler. Aslında UIApplicationDidBecomeActiveNotification için gözlemci eklemek ve çok iyi çalışıyor.
Wayne Liu

2
Bu kesinlikle doğru cevap. Bununla birlikte, "mevcut 'UIViewController'ın hangisi olduğunu söylemenin bir yolu yok" şeklinde yanıt olarak, self.navigationController.topViewControlleretkili bir şekilde sağladığına ya da en azından yığının üstünde, Bu kod, bir görünüm denetleyicisindeki ana iş parçacığında tetikleniyorsa geçerli olanıdır. (Yanlış olabilir, çok fazla oynamadı, ama işe yarıyor gibi görünüyor.)
Matthew Frederick

appDelegate.rootViewControllerçok işe yarayacak, ancak bir geri dönebilir UINavigationControllerve sonra .topViewController@MatthewFrederick'in dediği gibi ihtiyacınız olacak.
samson

7
UIApplicationDidBecomeActiveNotification yanlış (tüm oy kullananlara rağmen). Uygulama başlangıcında (ve yalnızca uygulama başlangıcında!) Bu bildirim farklı şekilde çağrılır - viewWillAppear'a ek olarak çağrılır, bu nedenle bu cevapla iki kez çağrılırsınız. Apple bunu doğru bir şekilde yapmayı gereksiz hale getirdi - dokümanlar hala eksik (2013 itibariyle!).
Adam

1
Ben geldi çözüm statik bir değişken ('statik BOOL girilenBackground;' ile bir sınıf kullanmak oldu sonra sınıf yöntemleri ayarlayıcılar ve alıcılar ekledim. ApplicationDidEnterBackground, değişken true olarak ayarlayın. Sonra applicationDidBecomeActive statik statik ve doğruysa, "doMyLayoutStuff" ı değiştirir ve değişkeni "NO" olarak sıfırlarım.
vejmartin

197

hızlı

Kısa cevap

Bunun NotificationCenteryerine bir gözlemci kullanın viewWillAppear.

override func viewDidLoad() {
    super.viewDidLoad()

    // set observer for UIApplication.willEnterForegroundNotification
    NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)

}

// my selector that was defined above
@objc func willEnterForeground() {
    // do stuff
}

Uzun cevap

Bir uygulamanın arka plandan ne zaman geri döndüğünü öğrenmek için, NotificationCenteryerine bir gözlemci kullanın viewWillAppear. İşte hangi olayların ne zaman gerçekleştiğini gösteren örnek bir proje. (Bu, bu Objective-C cevabının bir uyarlamasıdır .)

import UIKit
class ViewController: UIViewController {

    // MARK: - Overrides

    override func viewDidLoad() {
        super.viewDidLoad()
        print("view did load")

        // add notification observers
        NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)

    }

    override func viewWillAppear(_ animated: Bool) {
        print("view will appear")
    }

    override func viewDidAppear(_ animated: Bool) {
        print("view did appear")
    }

    // MARK: - Notification oberserver methods

    @objc func didBecomeActive() {
        print("did become active")
    }

    @objc func willEnterForeground() {
        print("will enter foreground")
    }

}

Uygulamayı ilk başlattığınızda, çıktı sırası:

view did load
view will appear
did become active
view did appear

Ana ekran düğmesine bastıktan sonra uygulamayı tekrar ön plana getirdikten sonra çıktı sırası:

will enter foreground
did become active 

Başlangıçta kullanmaya çalıştığınız Yani eğer viewWillAppearo zaman UIApplication.willEnterForegroundNotificationne istediğinizi muhtemelen.

Not

İOS 9 ve sonraki sürümler itibarıyla gözlemciyi kaldırmanıza gerek yoktur. Dokümantasyon durumları:

Uygulamanız iOS 9.0 ve sonraki sürümlerini veya macOS 10.11 ve sonraki sürümlerini hedefliyorsa, deallocyönteminde bir gözlemcinin kaydını silmenize gerek yoktur .


6
Hızlı 4.2'de bildirim adı artık
UIApplication.willEnterForegroundNotification

140

viewDidLoad:Bir yöntemi çağırmak için ViewController yönteminde Bildirim Merkezi'ni kullanın ve oradan yönteminizde yapmanız gerekeni yapın viewWillAppear:. viewWillAppear:Doğrudan aramak iyi bir seçenek değildir.

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"view did load");

    [[NSNotificationCenter defaultCenter] addObserver:self 
        selector:@selector(applicationIsActive:) 
        name:UIApplicationDidBecomeActiveNotification 
        object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self 
        selector:@selector(applicationEnteredForeground:) 
        name:UIApplicationWillEnterForegroundNotification
        object:nil];
}

- (void)applicationIsActive:(NSNotification *)notification {
    NSLog(@"Application Did Become Active");
}

- (void)applicationEnteredForeground:(NSNotification *)notification {
    NSLog(@"Application Entered Foreground");
}

9
O zaman deallocyöntemde gözlemciyi kaldırmak için iyi bir fikir olabilir .
AncAinu

2
viewDidLoad kendini gözlemci olarak eklemek için en iyi yöntem değil, öyleyse viewDidUnload'daki gözlemciyi kaldırın
Injectios

kendini gözlemci eklemenin en iyi yöntemi nedir?
Piotr Wasilewicz

Görünüm denetleyicisi yalnızca bir bildirim, yani UIApplicationWillEnterForegroundNotification için gözlemleyemiyor. Neden ikisini de dinliyorsunuz?
zulkarnain shah

34

viewWillAppear:animated:Bence iOS SDK'larındaki en kafa karıştırıcı yöntemlerden biri, böyle bir durumda, yani uygulama geçişinde asla çağrılmaz. Bu yöntem yalnızca görünüm denetleyicisinin görünümü ile uygulamanın penceresi arasındaki ilişkiye göre çağrılır , yani ileti görünüm denetleyicisine yalnızca görünümü ekranda değil uygulama penceresinde görünürse gönderilir.

Uygulamanız arka plana geçtiğinde, uygulama penceresinin en üst görünümleri artık kullanıcı tarafından görülemez. Bununla birlikte, uygulama pencerenizin bakış açısından, yine de en üst görünümlerdir ve bu nedenle pencereden kaybolmamışlardır. Bunun yerine, uygulama penceresi kaybolduğu için bu görünümler kayboldu. Onlar kayboldu çünkü kayboldu vermedi gelen pencerede.

Bu nedenle, kullanıcı uygulamanıza geri döndüğünde, ekranda tekrar göründüğü açıktır, çünkü pencere tekrar görünür. Ama pencerenin bakış açısına göre, hiç yok olmadılar. Bu nedenle, görünüm denetleyicileri viewWillAppear:animatediletiyi hiçbir zaman almaz .


2
Ayrıca, -viewWillDisappear: animated: uygulama çıkışında çağrıldığından beri durumu kaydetmek için uygun bir yerdi. Ancak uygulama arka planlandığında çağrılmaz ve arka plan uygulaması uyarı yapılmadan öldürülebilir.
tc.

6
Gerçekten kötü adlandırılmış başka bir yöntem viewDidUnload. ViewDidLoad'ın tam tersi olduğunu düşünürdünüz, ama hayır; yalnızca görünümün boşalmasına neden olan düşük bir bellek durumu olduğunda çağrılır ve görünüm her zaman dealloc zamanında kaldırıldığında değil.
okulus

@Occulus'a kesinlikle katılıyorum. viewWillAppear'ın mazereti vardır, çünkü (bir çeşit) çoklu görev orada değildi, ancak viewDidUnload kesinlikle daha iyi bir isme sahip olabilir.
MHC

Benim için uygulama iOS7'de arka plan oluşturulduğunda viewDidDisappear IS çağrılır. Onay alabilir miyim?
Mike Kogan

4

Hızlı 4.2 / 5

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground),
                                           name: Notification.Name.UIApplicationWillEnterForeground,
                                           object: nil)
}

@objc func willEnterForeground() {
   // do what's needed
}

3

Mümkün olduğunca kolay hale getirmeye çalışırken aşağıdaki kodu inceleyin:

- (void)viewDidLoad
{
   [self appWillEnterForeground]; //register For Application Will enterForeground
}


- (id)appWillEnterForeground{ //Application will enter foreground.

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(allFunctions)
                                                 name:UIApplicationWillEnterForegroundNotification
                                               object:nil];
    return self;
}


-(void) allFunctions{ //call any functions that need to be run when application will enter foreground 
    NSLog(@"calling all functions...application just came back from foreground");


}
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.