iPhone viewWillAppear가 실행되지 않음


116

나는 문제 가진 사람들에 대해 많은 글을 읽은 viewWillAppear당신이 당신의 뷰 계층을 생성하지 않는 경우 단지 권리를. 내 문제는 그것이 무엇을 의미하는지 이해할 수 없다는 것입니다.

해당 컨트롤러를 만들고 RootViewController호출 addSubView하면 추가 된 뷰가 viewWillAppear이벤트에 연결될 것으로 예상 합니다.

누구든지 viewWillAppear모든 수준에서 이벤트 를 성공적으로 수신하는 복잡한 프로그래밍 방식의 뷰 계층 구조의 예를 가지고 있습니까?

Apple의 문서 상태 :

경고 : 뷰 컨트롤러에 속한 뷰가 뷰 계층 구조에 직접 추가되면 뷰 컨트롤러는이 메시지를받지 않습니다. 뷰 계층에 뷰를 삽입하거나 추가하고 뷰 컨트롤러가있는 경우 연결된 뷰 컨트롤러에이 메시지를 직접 보내야합니다. 뷰 컨트롤러를 보내지 않으면이 메시지가 관련 애니메이션이 표시되지 않도록합니다.

문제는 그들이 이것을하는 방법을 설명하지 않는다는 것입니다. "직접"이란 무엇을 의미합니까? 뷰를 "간접적으로"추가하는 방법은 무엇입니까?

저는 Cocoa와 iPhone을 처음 접했기 때문에 기본적인 Hello World 쓰레기 외에 Apple의 유용한 예제가 있다면 좋을 것입니다.


일반적으로 UIViewController 하위 클래스의 의도 된 사용을 오해하고 있다는 것을 깨달을 때까지이 문제가 발생했습니다. 이 질문을 확인하십시오. stackoverflow.com/questions/5691226/…
averydev 2011

7
조심하세요 !!! iOS 5에서는 더 이상 사실이 아닙니다! viewWillAppear 및 viewDidAppear를 자동으로 호출
Vilém Kurz

답변:


55

탐색 컨트롤러를 사용하고 해당 대리자를 설정하면 view {Will, Did} {Appear, Disappear} 메서드가 호출되지 않습니다.

대신 탐색 컨트롤러 대리자 메서드를 사용해야합니다.

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:

2
내 탐색 컨트롤러의 대리자를 설정하지 않았는데도 메서드가 호출되지 않았습니다. 어쨌든 나는 그것을 설정하고 위에서 언급 한 방법을 사용했습니다. 감사.
Dimitris

나는 Dimitris와 같은 것을보고 있습니다
jkp

7
방금 iOS4 및 iOS5에서 테스트했습니다. 이것은 사실이 아닙니다. navigationController의 델리게이트를 설정 한 다음 뷰를 푸시하면 viewWillAppear가 실행됩니다. 등
DaGaMs

Swift 3 : func navigationController (_ navigationController : UINavigationController, willShow viewController : UIViewController, animated : Bool) {} AND 있는 navigationController FUNC (_있는 navigationController : UINavigationController가, didShow의 ViewController : UIViewController에 애니메이션 : BOOL) {}
Naloiko 유진

28

나는이 같은 문제에 부딪쳤다. viewWillAppear서브 뷰로 추가하기 전에 뷰 컨트롤러에 메시지를 보내 십시오. (애니메이션이 표시되는지 여부를 뷰 컨트롤러에 알려주는 BOOL 매개 변수가 하나 있습니다.)

[myViewController viewWillAppear:NO];

Metronome 예제에서 RootViewController.m을보십시오.

(실제로 Apple의 예제 프로젝트가 훌륭하다는 것을 알았습니다. HelloWorld보다 훨씬 많은 것이 있습니다.)


3
사실, subview에 추가 한 후에 viewWillAppear를 호출해야합니다. 그렇지 않으면 IBOutlets / IBActions가 연결되지 않습니다.
4thSpace

2
예, 나중에. XIB에서 하위보기를 만들었지 만 viewWillAppear가 호출되지 않았습니다. 혼자서 전화하면 모든 것이 잘 작동합니다.
JOM

감사합니다! 이것은 정확히 나를위한 것이었다. 을 통해 수동으로 하위 뷰를 추가했습니다 [scrollView addSubview:controller.view];. 나는 [controller viewWillAppear:NO];나중에 줄을 추가 하고 짜잔! 매력처럼 작동했습니다.
Rob S.

아마도 이것은 UIViewController가 다른 UIViewController에 의해 제어되는 뷰의 하위 뷰인 뷰를 제어하고 있기 때문입니다. 이것은 의도 된 디자인 패턴이 아닙니다. 자세한 설명은이 게시물을 확인하십시오. stackoverflow.com/questions/5691226/…
averydev 2011

6
조심하세요 !!! iOS 5에서는 더 이상 사실이 아닙니다! viewWillAppear 및 viewDidAppear를 자동으로 호출합니다. 수동으로 호출하면 두 번 호출됩니다.
Vilém Kurz 2011

18

마침내 이것에 대한 해결책을 찾았습니다.

UINavigationControllerDelegate

그 요점은 탐색 컨트롤의 델리게이트를 뷰 컨트롤러에 설정하고 구현하는 UINavigationControllerDelegate것이며 두 가지 방법이라고 생각합니다. 훌륭한! 나는 마침내 해결책을 찾았습니다!


rootviewcontroller를 navigationcontroller의 대리인으로 할당하는 방법은 무엇입니까?
Gargo

1
작동하지 않습니다! 응용 프로그램을 최소화하려고하고 그것을 극대화
Vyachaslav Gerchicov

8

나는 똑같은 문제가 있었다. 내 응용 프로그램에는 두 개의 탐색 컨트롤러가 있으며 각 컨트롤러에서 동일한 뷰 컨트롤러를 푸시하면 다른 경우가 아니라 한 경우에서 작동했습니다. 나는 처음에 동일한 뷰 컨트롤러를 밀어 때 의미 UINavigationController, viewWillAppear두 번째 탐색 컨트롤러 밀어 때 호출하지만하지 않았다.

그런 다음이 게시물 UINavigationController가 viewWillAppear / viewWillDisappear 메서드를 호출해야 함을 발견했습니다.

그리고 두 번째 내비게이션 컨트롤러가 viewWillAppear. 코드를 검사 한 결과 내가 전화를 걸지 않았다는 것을 알 수있었습니다.

[super viewWillAppear:animated];

나는 그것을 추가하고 작동했습니다!

문서는 다음과 같이 말합니다.

이 메서드를 재정의하는 경우 구현의 어느 시점에서 super를 호출해야합니다.


여기도 마찬가지입니다. 슈퍼를 부르지 않아서 혼란스러워.
olivaresF

5

내비게이션 컨트롤러를 사용하고 있습니다. 다른 수준의 데이터로 내려가거나 내 사용자 지정보기를 표시하려면 다음을 사용합니다.

[self.navigationController pushViewController:<view> animated:<BOOL>];

이렇게하면 viewWillAppear함수가 실행됩니다. 내가 실제 addSubView메서드를 직접 호출하지 않기 때문에 이것이 "간접적"이라고 생각합니다. 내비게이션 컨트롤러를 사용하고 있는지 알 수 없기 때문에 이것이 귀하의 응용 프로그램에 100 % 적용되는지는 모르겠지만 아마도 단서를 제공 할 것입니다.


5

감사합니다 iOS 13

ViewWillDisappear, ViewDidDisappear, ViewWillAppearViewDidAppear전체 화면을 커버하지 않는 새로운 모달 프리젠 테이션을 사용하는 아이폰 OS 13에 제시 뷰 컨트롤러에서 호출되지 않습니다.

크레딧은 Arek Holko에게 있습니다. 그는 정말로 내 하루를 구했습니다.

여기에 이미지 설명 입력


4

첫째, 탭 막대는 Apple 문서에 명시된대로 루트 수준에 있어야합니다. 즉, 창에 추가되어야합니다. 이것은 올바른 행동의 핵심입니다.

둘째, / 를 사용 하여 수동으로 알림을 전달할 있지만 전체 뷰 호출 계층이 올바르게 작동하도록하려면 수동으로 호출하면됩니다.UITabBarDelegateUINavigationBarDelegate

[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];

[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];

.. 해당 컨트롤러에서 뷰 컨트롤러를 설정하기 전에 한 번만 수행합니다 (할당 직후). 그때부터 자식 뷰 컨트롤러에서 이러한 메서드를 올바르게 호출했습니다.

내 계층 구조는 다음과 같습니다.

window
    UITabBarController (subclass of)
        UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
            UINavigationController (subclass of)
                UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods

탭 / 내비게이션 컨트롤러에서 언급 된 메서드를 처음 호출하기 만하면 모든 이벤트가 올바르게 전달되었는지 확인할 수 있습니다. UINavigationBarDelegate/ UITabBarControllerDelegate메소드 에서 수동으로 호출 할 필요가 없었습니다 .

사이드 노트 : 이상하게도 작동하지 않았을 때 사적인 방법

- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController 

.. 작동하는 구현에 대한 호출 스택에서 볼 수 있으며 일반적으로 viewWill/Did..메서드를 호출 하지만 위의 작업을 수행 할 때까지 호출 되지 않았습니다.

나는 그것이 UITabBarController창 수준에 있고 문서가 이것을 백업 하는 것이 매우 중요하다고 생각합니다 .

더 많은 질문에 답해 드리겠습니다.


3

대답이 받아 들여지지 않고 사람들이 (내가 한 것처럼) 여기에 착륙하기 때문에 나는 내 변형을 준다. 그것이 원래 문제인지는 모르겠지만. 탐색 컨트롤러가 다른보기에 하위보기로 추가되면 다음과 같이 viewWillAppear / Dissappear 등 메서드를 직접 호출해야합니다.

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

    [subNavCntlr viewWillAppear:animated];
}

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

    [subNavCntlr viewWillDisappear:animated];
}

예제를 완성하기 위해서입니다. 이 코드는 뷰에 배치 한 뷰에 탐색 컨트롤러를 만들고 추가 한 ViewController에 나타납니다.

- (void)viewDidLoad {

    // This is the root View Controller
    rootTable *rootTableController = [[rootTable alloc]
                 initWithStyle:UITableViewStyleGrouped];

    subNavCntlr = [[UINavigationController alloc]   
                  initWithRootViewController:rootTableController];

    [rootTableController release];

    subNavCntlr.view.frame = subNavContainer.bounds;

    [subNavContainer addSubview:subNavCntlr.view];

    [super viewDidLoad];
}

.h는 다음과 같습니다

@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
    IBOutlet UIView *subNavContainer;
    UINavigationController *subNavCntlr;
}

@end

nib 파일에는 뷰가 있고이 뷰 아래에는 레이블이있는 이미지와 컨트롤러를 넣은 컨테이너 (다른 뷰)가 있습니다. 모양은 다음과 같습니다. 나는 이것이 클라이언트를위한 일이기 때문에 몇 가지를 뒤섞어 야했다.

대체 텍스트


3

뷰는 다음을 호출하여 "직접"추가됩니다. [view addSubview:subview] . 뷰는 하위 뷰를 교체하는 탭 막대 또는 탐색 막대와 같은 방법에 의해 "간접적으로"추가됩니다.

전화 할 때마다 [view addSubview:subviewController.view], 당신은 호출해야합니다[subviewController viewWillAppear:NO] (또는 귀하의 경우에 YES).

게임의 하위 화면에 대한 자체 사용자 지정 루트 뷰 관리 시스템을 구현할 때이 문제가 발생했습니다. viewWillAppear에 대한 호출을 수동으로 추가하면 문제가 해결되었습니다.


3

이를 수행하는 올바른 방법은 UIViewController 포함 API를 사용하는 것입니다.

- (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     UIViewController *viewController = ...;
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
     [viewController didMoveToParentViewController:self];
}

이것은 절대적으로 올바른 최신 솔루션입니다 (iOS 9,8,7). 또한 임베드 된 뷰 컨트롤러를 즉시 변경하려면 [viewController willMoveToParentViewController : nil]을 호출해야합니다. [viewController.view removeFromSuperview]; [viewController removeFromParentViewController];
Eli Burke

1
이 경우는 viewWillAppear:아직 호출 할 수 없습니다
Vyachaslav Gerchicov

2

푸시 및 팝 뷰 컨트롤러에이 코드를 사용합니다.

푸시:

[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];

팝:

[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];

.. 잘 작동합니다.


2

매우 일반적인 실수는 다음과 같습니다. 하나의보기 UIView* a및 다른 보기가 있습니다 UIView* b. b를 a에 하위보기로 추가합니다. b에서 viewWillAppear를 호출하려고하면 a의 하위 뷰이기 때문에 실행되지 않습니다.


2

여기 엉덩이에 iOS 13 비트 내 앱. iOS 13에서 동작이 변경된 것을 발견 한 경우 푸시하기 전에 다음을 설정하십시오.

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

속성 관리자의 .storyboard에서 설정해야 할 수도 있습니다 (프레젠테이션을 전체 화면으로 설정).

이렇게하면 이전 버전의 iOS에서와 같이 앱이 작동합니다.


1

100 % 확실하지는 않지만 뷰 계층 구조에 뷰를 추가하는 것은 새 뷰 컨트롤러를 탐색 컨트롤러의 스택에 푸시하는 대신 -addSubview:뷰 컨트롤러의 뷰 (예 :)를 직접 호출 하는 것을 의미한다고 생각합니다 [viewController.view addSubview:anotherViewController.view].


1

하위 뷰를 추가한다고해서 뷰가 반드시 나타나는 것은 아니므로 클래스의 메서드를 자동으로 호출하지 않아도됩니다.


1

그들이 "직접적으로"의미하는 것은 xcode "Navigation Application"템플릿이하는 것과 똑같은 방식으로 연결하여 UINavigationController를 응용 프로그램의 UIWindow의 유일한 하위보기로 설정하는 것이라고 생각합니다.

해당 템플릿을 사용하는 것은 UINavigationController에서 해당 컨트롤러의 푸시 / 팝시 개체 ViewController에서 호출 된 Will / Did / Appear / Disappear 메서드를 가져올 수있는 유일한 방법입니다. 여기 답변의 다른 솔루션은 RootController에서 구현하고 (자식) NavigationController로 전달하는 것을 포함하여 나를 위해 일하지 않았습니다. 이러한 함수 (will / did / appear / disappear)는 내비게이션 컨트롤러의 하위 VC가 아닌 최상위 VC, 내 "로그인"및 내비게이션 VC를 표시 / 숨길 때만 내 RootController에서 호출되었으므로 나는 기회가 없었습니다. Nav VC에 "전달"합니다.

결국 UINavigationController의 델리게이트 기능을 사용하여 내 앱에서 후속 기능이 필요한 특정 전환을 찾고 작동하지만 사라지고 나타나는 기능을 "시뮬레이션"하려면 약간 더 많은 작업이 필요합니다.

또한 오늘 몇 시간 동안이 문제에 머리를 두드린 후 작동하도록하는 것이 원칙 문제입니다. 사용자 정의 RootController 및 하위 탐색 VC를 사용하는 모든 작동 코드 스 니펫은 많은 도움이 될 것입니다.


1

이것이 누구에게나 도움이 될 경우. 에서 ViewWillAppear해고되지 않는 비슷한 문제 가 발생했습니다 UITableViewController. 여러 번 놀아 본 결과, 문제는 UINavigationController내 제어자가 UITableView루트 뷰에 있지 않다는 것임을 깨달았습니다 . 내가 그것을 고치면 이제 챔피언처럼 작동합니다.


"어떻게"그랬는지 공유해 주시겠습니까?
Brabbeldas

1

나는 방금이 문제가 있었고 그것을 고치는 데 3 시간이 걸렸습니다 (이 중 2 시간은 인터넷 검색).

도움이 된 것은 단순히 장치 / 시뮬레이터에서 앱을 삭제하고 정리 한 다음 다시 실행 하는 것이 었 습니다. 입니다.

도움이되는 희망


1
[self.navigationController setDelegate:self];

델리게이트를 루트 뷰 컨트롤러로 설정합니다.


1

Swift를 위해. 먼저 viewWillAppear에서 호출하려는 것을 호출하는 프로토콜을 만듭니다.

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

둘째, 클래스 생성

class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
    if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
        updatedCntllr.myViewWillAppear()
    }
}

}

셋째, ForceUpdateOnViewAppear의 인스턴스를 탐색 컨트롤러에 대한 액세스 권한이 있고 탐색 컨트롤러가있는 한 존재하는 적절한 클래스의 구성원이되도록합니다. 예를 들어 탐색 컨트롤러의 루트 뷰 컨트롤러 또는이를 생성하거나 표시하는 클래스 일 수 있습니다. 그런 다음 ForceUpdateOnViewAppear 인스턴스를 가능한 한 빨리 Navigation Controller 대리자 속성에 할당합니다.


0

제 경우에는 사용자 지정 전환 애니메이션에 문제가있었습니다. 설정시modalPresentationStyle = .custom viewWillAppear 되지라는

사용자 전환 애니메이션 클래스 필요 호출 방법에 : beginAppearanceTransitionendAppearanceTransition


0

제 경우에는 ios 12.1 에뮬레이터의 이상한 버그였습니다. 실제 기기에서 실행 후 사라졌습니다.


0

이 문제를 해결하는 수업을 만들었습니다. 내비게이션 컨트롤러의 델리게이트로 설정하고 뷰 컨트롤러에서 간단한 하나 또는 두 개의 메서드를 구현하면됩니다.이 메서드는 뷰가 표시 되려고하거나 NavigationController를 통해 표시 될 때 호출됩니다.

다음은 코드를 보여주는 GIST입니다.


0

ViewWillAppear는 UIViewController 클래스의 재정의 메서드이므로 subView를 추가하면 viewWillAppear가 호출되지 않지만 표시 할 때 viewController에서 push, pop, show, setFront 또는 popToRootViewController 다음 표시되는 viewController에 대한 viewWillAppear가 호출됩니다.


0

내 문제는 segue에서 풀 때 viewWillAppear가 호출되지 않았다는 것입니다. 대답은 다시 segueing하는 View Controller의 unwind segue에서 viewWillAppear (true)를 호출하는 것입니다.

@IBAction func unwind (for unwindSegue : UIStoryboardSegue, ViewController laterVC : Any) {

   viewWillAppear(true)
}

-2

이것이 내가 해결 한 것과 같은 문제인지 잘 모르겠습니다.
경우에 따라 "[self methodOne]"과 같은 일반적인 방법으로 메서드가 실행되지 않습니다.

시험

- (void)viewWillAppear:(BOOL)animated
{
    [self performSelector:@selector(methodOne) 
           withObject:nil afterDelay:0];
}

문제가되는 viewWillAppear전혀 호출되지 않습니다
Vyachaslav Gerchicov

-3

항상 하나의 UIViewController 만 활성화해야합니다. 조작하려는 모든 하위보기는 정확히 subVIEWS, 즉 UIView 여야합니다.

보기 계층 구조를 관리하기 위해 간단한 기술을 사용하지만 이런 식으로 작업을 시작한 이후로 아직 문제가 발생하지 않았습니다. 두 가지 핵심 사항이 있습니다.

  • 단일 UIViewController를 사용하여 앱의 "화면 가치"를 관리해야합니다.
  • 뷰 변경을 위해 UINavigationController 사용

"화면 가치"란 무엇을 의미합니까? 의도적으로 약간 모호하지만 일반적으로 앱의 기능 또는 섹션입니다. 배경 이미지는 같지만 오버레이 / 팝업이 다른 화면이 몇 개있는 경우에는보기 컨트롤러 1 개와 하위보기 여러 개 여야합니다. 2 개의 뷰 컨트롤러로 작업하는 것을 결코 발견해서는 안됩니다. 한 뷰 컨트롤러에서 UIView를 인스턴스화하고 여러 뷰 컨트롤러에 화면의 특정 영역을 표시하려는 경우 다른 뷰 컨트롤러의 하위 뷰로 추가 할 수 있습니다.

UINavigationController-이것은 당신의 가장 친한 친구입니다! 내비게이션 바를 끄고 애니메이션에 대해 아니오를 지정하면 요청시 화면을 전환하는 훌륭한 방법이 있습니다. 계층 구조에있는 경우 뷰 컨트롤러를 푸시하고 팝하거나, 뷰 컨트롤러 배열 (단일 VC를 포함하는 배열 포함)을 준비하고 setViewControllers를 사용하여 뷰 스택이되도록 설정할 수 있습니다. 이를 통해 VC를 변경할 수있는 완전한 자유를 누리면서 Apple의 예상 모델 내에서 작업하고 모든 이벤트 등을 올바르게 실행하는 모든 이점을 얻을 수 있습니다.

앱을 시작할 때마다 수행하는 작업은 다음과 같습니다.

  • 창 기반 앱에서 시작
  • 창의 rootViewController로 UINavigationController 추가
  • 내 첫 번째 UIViewController를 탐색 컨트롤러의 rootViewController로 원하는 것을 추가하십시오.

(창 기반에서 시작하는 것은 개인적인 취향 일뿐입니다. 직접 구성하는 것을 좋아하므로 어떻게 구성되는지 정확히 알 수 있습니다.보기 기반 템플릿에서는 잘 작동합니다.)

모든 이벤트는 올바르게 실행되며 기본적으로 삶은 좋습니다. 그런 다음 앱의 중요한 부분을 작성하는 데 모든 시간을 할애하고 뷰 계층 구조를 수동으로 해킹하는 데 신경 쓰지 않아도됩니다.


여러 개의 뷰 컨트롤러를 활성화해도 문제가 없습니다. UIViewController에는 계층 구조를 구성 할 수있는 메서드가 있습니다 (예 : [addChildViewController :]).
리처드

1
네, 지금은 그렇습니다. 2011 년에는 그렇지 않았습니다. 대답은 당시에 정확했지만 지금은 아닙니다.
Nigel Flack
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.