이 줄 :
[self dismissViewControllerAnimated:YES completion:nil];
자신에게 메시지를 보내는 것이 아니라 실제로 제시하는 VC에게 메시지를 보내고 해제를 요청하는 것입니다. VC를 발표 할 때 발표하는 VC와 제시된 VC 간의 관계를 생성합니다. 따라서 발표하는 동안 발표중인 VC를 파괴해서는 안됩니다 (제시된 VC는 해당 해제 메시지를 다시 보낼 수 없습니다…). 실제로 그것을 고려하지 않기 때문에 앱을 혼란스러운 상태로 두는 것입니다.
이 방법을 권장 하는 내 대답 Dismissing a Presented View Controller 가 더 명확하게 작성되었습니다.
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
귀하의 경우 모든 제어가 mainVC
. 델리게이트를 사용하여 ViewController1에서 MainViewController로 올바른 메시지를 다시 보내야 mainVC가 VC1을 해제 한 다음 VC2를 표시 할 수 있습니다.
에서 VC2 VC1 @interface 위의 .h 파일에 프로토콜을 추가 :
@protocol ViewController1Protocol <NSObject>
- (void)dismissAndPresentVC2;
@end
@interface 섹션의 동일한 파일에서 아래로 내려 위임 포인터를 보유하는 속성을 선언합니다.
@property (nonatomic,weak) id <ViewController1Protocol> delegate;
VC1 .m 파일에서 닫기 버튼 메서드는 대리자 메서드를 호출해야합니다.
- (IBAction)buttonPressedFromVC1:(UIButton *)sender {
[self.delegate dissmissAndPresentVC2]
}
이제 mainVC에서 VC1을 만들 때 VC1의 델리게이트로 설정합니다.
- (IBAction)present1:(id)sender {
ViewController1* vc = [[ViewController1 alloc] initWithNibName:@"ViewController1" bundle:nil];
vc.delegate = self;
[self present:vc];
}
대리자 메서드를 구현합니다.
- (void)dismissAndPresent2 {
[self dismissViewControllerAnimated:NO completion:^{
[self present2:nil];
}];
}
present2:
VC2Pressed:
버튼 IBAction 메서드 와 동일한 메서드 일 수 있습니다 . 완료 블록에서 호출되어 VC1이 완전히 해제 될 때까지 VC2가 표시되지 않도록합니다.
이제 VC1-> VCMain-> VC2에서 이동 중이므로 전환 중 하나만 애니메이션으로 만들 수 있습니다.
최신 정보
당신의 의견에서 당신은 겉보기에 단순한 일을 달성하는 데 필요한 복잡성에 놀라움을 표현합니다. 이 위임 패턴은 Objective-C와 Cocoa의 대부분의 핵심이며,이 예제는 여러분이 얻을 수있는 가장 간단한 것에 대한 것이므로 여러분은 그것에 익숙해지기 위해 노력해야합니다.
애플의에서 보기 컨트롤러 프로그래밍 가이드 그들은이 이 말을 :
제시된보기 컨트롤러 닫기
제시된 뷰 컨트롤러를 닫을 때 선호되는 접근 방식은 제시하는 뷰 컨트롤러가이를 해제하도록하는 것입니다. 즉, 가능할 때마다 뷰 컨트롤러를 표시 한 동일한 뷰 컨트롤러가이를 해제 할 책임이 있습니다. 프리젠 테이션 뷰 컨트롤러에게 제시된 뷰 컨트롤러를 해제해야 함을 알리는 몇 가지 기술이 있지만, 선호하는 기법은 위임입니다. 자세한 내용은 "위임을 사용하여 다른 컨트롤러와 통신"을 참조하십시오.
당신이 달성하고자하는 것과 그것에 대해 어떻게 진행하고 있는지를 정말로 생각한다면, 모든 작업을 수행하기 위해 MainViewController를 메시징하는 것이 NavigationController를 사용하고 싶지 않다는 것을 감안할 때 유일한 논리적 방법이라는 것을 알게 될 것입니다. 당신이 경우에 할 NavController를 사용, 효과에 당신도없는 경우 명시 적으로 모든 작업을 수행 할 navController에, '위임'이다. 있을 필요가 일부 사용자의 VC 탐색에 무슨 일이 일어나고 있는지의 중심을 추적 객체, 당신은 필요 어떤 무슨 일이 있어도 그것으로 의사 소통의 방법을.
실제로 애플의 조언은 당신이 신뢰할 수있는, 조금 극단적가 ... 정상적인 경우에, 당신은 전용 위임 및 방법을 할 필요가 없습니다입니다 [self presentingViewController] dismissViewControllerAnimated:
- 때의 당신이 당신의 삭제 중 원격에 다른 영향을 미칠 것인지 귀하와 같은 경우에 당신이 돌봐야 할 물건.
여기 에 델리게이트의 번거 로움없이 작업 할 수 있다고 상상할 수있는 것이 있습니다 .
- (IBAction)dismiss:(id)sender {
[[self presentingViewController] dismissViewControllerAnimated:YES
completion:^{
[self.presentingViewController performSelector:@selector(presentVC2:)
withObject:nil];
}];
}
프리젠 테이션 컨트롤러에게 우리를 닫아달라고 요청한 후, 우리는 presentingViewController에서 VC2를 호출하는 메소드를 호출하는 완료 블록을 갖게됩니다. 대리인이 필요하지 않습니다. (블록의 큰 판매 포인트는 이러한 상황에서 대리인의 필요성을 줄인다는 것입니다). 그러나이 경우에는 방해가되는 몇 가지 사항이 있습니다.
- VC1 에서는 mainVC가 메서드를 구현한다는 사실 을 알지 못합니다
present2
. 디버깅하기 어려운 오류나 충돌이 발생할 수 있습니다. 대리인은이를 방지 할 수 있도록 도와줍니다.
- VC1이 해제되면 완료 블록을 실행할 수 없습니다 ... 아니면 그럴까요? self.presentingViewController는 더 이상 의미가 있습니까? 당신은 몰라요 (저도 요) ... 대리인과 함께라면, 당신은이 불확실성을 가지고 있지 않습니다.
- 이 메서드를 실행하려고하면 경고 나 오류없이 중단됩니다.
그러니 시간을내어 위임을 배우십시오!
update2
귀하의 의견에서 VC2의 닫기 버튼 처리기에서 이것을 사용하여 작동하도록 관리했습니다.
[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
이것은 확실히 훨씬 간단하지만 많은 문제를 남깁니다.
긴밀한 결합
viewController 구조를 함께 고정하고 있습니다. 예를 들어 mainVC 앞에 새 viewController를 삽입하면 필요한 동작이 중단됩니다 (이전 동작으로 이동). VC1에서는 VC2를 #import해야했습니다. 따라서 OOP / MVC 목표를 위반하는 상호 의존성이 상당히 많습니다.
델리게이트를 사용하면 VC1과 VC2 모두 mainVC에 대해 알 필요가 없거나 선행 항목이므로 모든 것을 느슨하게 결합하고 모듈화합니다.
메모리
VC1은 사라지지 않았으며 여전히 두 개의 포인터를 보유하고 있습니다.
- mainVC의
presentedViewController
속성
- VC2의
presentingViewController
속성
로깅을 통해 테스트 할 수 있으며 VC2에서이를 수행 할 수도 있습니다.
[self dismissViewControllerAnimated:YES completion:nil];
여전히 작동하지만 여전히 VC1로 돌아갑니다.
그것은 메모리 누수처럼 보입니다.
이에 대한 단서는 여기에 표시되는 경고에 있습니다.
[self presentViewController:vc2 animated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
VC2가 제시된 VC 인 제시 VC 를 해제 하려고 할 때 로직이 무너집니다 . 두 번째 메시지는 실제로 실행되지 않습니다. 아마도 몇 가지 일이 발생하지만 제거했다고 생각한 객체에 대한 두 개의 포인터가 남아 있습니다. ( 편집-나는 이것을 확인했고 그렇게 나쁘지 않습니다. mainVC로 돌아갈 때 두 개체가 모두 사라집니다 )
그것은 다소 장황한 표현입니다-제발, 대리인을 사용하십시오. 도움이된다면 여기에 패턴에 대한 또 다른 간단한 설명을 만들었습니다
. 컨트롤러를 생성자에게 전달하는 것이 항상 나쁜 습관입니까?
업데이트 3
정말로 대리인을 피하려면 이것이 최선의 방법이 될 수 있습니다.
VC1에서 :
[self presentViewController:VC2
animated:YES
completion:nil];
그러나 아무것도 무시 하지 마십시오. 우리가 확인했듯이 어쨌든 실제로는 일어나지 않습니다.
VC2에서 :
[self.presentingViewController.presentingViewController
dismissViewControllerAnimated:YES
completion:nil];
(알다시피) VC1 을 닫지 않았으므로 VC1 을 통해 MainVC 에 다시 연결할 수 있습니다 . MainVC는 VC1을 닫습니다. VC1이 사라졌기 때문에 VC2가 함께 제공되므로 깨끗한 상태로 MainVC로 돌아 왔습니다.
VC1은 VC2에 대해 알아야하고 VC2는 MainVC-> VC1을 통해 도착했음을 알아야하므로 여전히 고도로 결합되어 있지만 약간의 명시 적 위임없이 얻을 수있는 최선의 방법입니다.