[ios] 앱이 백그라운드에서 돌아올 때 viewWillAppear가 호출되지 않는 이유는 무엇입니까?

앱을 작성 중이며 전화 통화 중 사용자가 앱을보고있는 경우보기를 변경해야합니다.

다음 방법을 구현했습니다.

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

그러나 앱이 포 그라운드로 돌아올 때 호출되지 않습니다.

구현할 수 있음을 알고 있습니다.

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

그러나 나는 이것을하고 싶지 않습니다. 오히려 모든 레이아웃 정보를 viewWillAppear : 메서드에 넣고 가능한 모든 시나리오를 처리하도록하십시오.

applicationWillEnterForeground :에서 viewWillAppear :를 호출하려고 시도했지만 해당 시점의 현재 뷰 컨트롤러를 정확하게 파악할 수 없습니다.

아무도 이것을 처리하는 올바른 방법을 알고 있습니까? 분명한 해결책이 빠져 있다고 확신합니다.



답변

이 방법 viewWillAppear은 다른 응용 프로그램에서 다시 전환 할 때 포 그라운드에 놓이는 응용 프로그램의 컨텍스트가 아니라 자신의 응용 프로그램에서 진행되는 상황에서 취해야합니다.

즉, 누군가 다른 응용 프로그램을 보거나 전화를받는 경우 이전에 백그라운드에 있던 앱으로 다시 전환합니다. 그것이 우려되는 한, 그것은 결코 사라지지 않고 여전히 볼 수 있으며 그렇게 viewWillAppear불리지 않습니다.

나는 viewWillAppear당신 자신 을 부르지 말 것을 권합니다. 그것은 당신이 파괴해서는 안되는 특정한 의미를 가지고 있습니다! 동일한 효과를 얻기 위해 수행 할 수있는 리팩토링은 다음과 같습니다.

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

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

그런 다음 doMyLayoutStuff적절한 알림에서 트리거 합니다.

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

그런데 ‘현재’UIViewController가 무엇인지 알 수있는 방법은 없습니다. 그러나 UIViewController가 언제 제공되는지 알아내는 UINavigationController의 대리자 메소드가 있습니다. 그런 것을 사용하여 제시 된 최신 UIViewController를 추적 할 수 있습니다.

최신 정보

다양한 비트에 적절한 자동 크기 조정 마스크를 사용하여 UI를 레이아웃하면 UI에 배치 된 ‘수동’을 처리 할 필요조차없는 경우가 있습니다.


답변

빠른

짧은 답변

NotificationCenter대신 관찰자를 사용하십시오 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
}

긴 대답

앱이 백그라운드에서 언제 돌아 오는지 알아 보려면 NotificationCenter대신 관찰자를 사용하십시오 viewWillAppear. 다음은 언제 어떤 이벤트가 발생하는지 보여주는 샘플 프로젝트입니다. (이것은 이 Objective-C 답변 의 적응입니다 .)

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")
    }

}

앱을 처음 시작할 때 출력 순서는 다음과 같습니다.

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

홈 버튼을 누른 다음 앱을 다시 포 그라운드로 가져온 후 출력 순서는 다음과 같습니다.

will enter foreground
did become active 

원래 사용하려고한다면 그래서 viewWillAppear다음 UIApplication.willEnterForegroundNotification당신이 원하는 아마.

노트

iOS 9 이상에서는 관찰자를 제거 할 필요가 없습니다. 설명서 에는 다음 이 명시되어 있습니다.

앱이 iOS 9.0 이상 또는 macOS 10.11 이상을 대상으로하는 경우 해당 dealloc방법으로 옵저버를 등록 해제 할 필요가 없습니다 .


답변

viewDidLoad:ViewController 의 메소드 에서 알림 센터를 사용하여 메소드를 호출하고 메소드에서 수행해야 할 작업을 수행하십시오 viewWillAppear:. viewWillAppear:직접 전화 하는 것은 좋은 방법이 아닙니다.

- (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");
}


답변

viewWillAppear:animated:필자의 의견으로는 iOS SDK에서 가장 혼란스러운 방법 중 하나 인 응용 프로그램 전환과 같은 상황에서 호출되지 않습니다. 이 메소드는 뷰 컨트롤러의보기와 응용 프로그램의 창 사이의 관계에 따라서 만 호출됩니다 . 즉, 메시지가 화면이 아닌 응용 프로그램의 창에 나타나는 경우에만 메시지가 뷰 컨트롤러로 전송됩니다.

응용 프로그램이 배경이되면 응용 프로그램 창의 최상위 뷰가 더 이상 사용자에게 보이지 않습니다. 그러나 응용 프로그램 창의 관점에서는 여전히 최상위 뷰이므로 창에서 사라지지 않았습니다. 오히려 응용 프로그램 창이 사라져서 해당 뷰가 사라졌습니다. 그들은 창 에서 사라져 사라지지 않았다 .

따라서 사용자가 응용 프로그램으로 다시 전환하면 창이 다시 나타나기 때문에 분명히 화면에 나타나는 것처럼 보입니다. 그러나 창문의 관점에서 그들은 전혀 사라지지 않았습니다. 따라서 뷰 컨트롤러는 viewWillAppear:animated메시지를 받지 않습니다 .


답변

스위프트 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
}


답변

가능한 한 쉽게 만들기 위해 아래 코드를 참조하십시오.

- (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");


}


답변