VC2라는 뷰 컨트롤러 클래스의 인스턴스가 있다고 가정 해 보겠습니다. VC2에는 자동으로 해제되는 “취소”버튼이 있습니다. 하지만 “취소”버튼이 트리거되면 콜백을 감지하거나 수신 할 수 없습니다. VC2는 블랙 박스입니다.
뷰 컨트롤러 (VC1이라고 함)는 presentViewController:animated:completion:
메서드를 사용하여 VC2를 표시 합니다.
VC2가 해제되었을 때 VC1이 감지해야하는 옵션은 무엇입니까?
편집 : @rory mckinnel의 의견과 @NicolasMiari의 답변에서 다음을 시도했습니다.
VC2에서 :
-(void)cancelButton:(id)sender
{
[self dismissViewControllerAnimated:YES completion:^{
}];
// [super dismissViewControllerAnimated:YES completion:^{
//
// }];
}
VC1에서 :
//-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
- (void)dismissViewControllerAnimated:(BOOL)flag
completion:(void (^ _Nullable)(void))completion
{
NSLog(@"%s ", __PRETTY_FUNCTION__);
[super dismissViewControllerAnimated:flag completion:completion];
// [self dismissViewControllerAnimated:YES completion:^{
//
// }];
}
그러나 dismissViewControllerAnimated
VC1에서 호출되지 않았습니다.
답변
문서에 따르면 발표하는 컨트롤러는 실제 해제를 담당합니다. 제시된 컨트롤러가 스스로 닫히면 발표자에게이를 수행하도록 요청합니다. 따라서 VC1 컨트롤러에서 dismissViewControllerAnimated를 재정의하면 VC2에서 취소를 누를 때 호출 될 것이라고 믿습니다. 해제를 감지 한 다음 실제 해제를 수행 할 슈퍼 클래스 버전을 호출합니다.
토론에서 알 수 있듯이 이것은 작동하지 않는 것 같습니다. 오히려 대신 호출하는 기본 메커니즘에 의존하는 것보다 dismissViewControllerAnimated:completion
VC2 자체 통화 dismissViewControllerAnimated:completion
에 self.presentingViewController
VC2한다. 그러면 재정의가 직접 호출됩니다.
더 나은 접근 방식은 VC2가 모달 컨트롤러가 완료 될 때 호출되는 블록을 제공하도록하는 것입니다.
따라서 VC2에서 이름과 함께 블록 속성을 제공하십시오 onDoneBlock
.
VC1에서는 다음과 같이 발표합니다.
-
VC1에서 VC2를 만듭니다.
-
VC2에 대한 완료 핸들러를 다음과 같이 설정하십시오.
VC2.onDoneBlock={[VC2 dismissViewControllerAnimated:YES completion:nil]};
-
[self presentViewController : VC2 animated : YES 완료 : nil]을 사용하여 VC2 컨트롤러를 정상적으로 표시합니다.
-
VC2에서 취소 대상 작업 호출에서
self.onDoneBlock();
결과는 VC2가 누구에게나 그것이 완료되었음을 알려줍니다. onDoneBlock
모달이 완료되었는지, 취소되었는지, 성공했는지 등을 나타내는 인수를 갖도록를 확장 할 수 있습니다 .
답변
이 목적으로 사용할 수있는 UIViewController
라는 특수 부울 속성 isBeingDismissed
이 있습니다.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isBeingDismissed {
// TODO: Do your stuff here.
}
}
답변
블록 속성 사용
VC2에서 선언
var onDoneBlock : ((Bool) -> Void)?
VC1에서 설정
VC2.onDoneBlock = { result in
// Do something
}
해고하려고 할 때 VC2를 호출하십시오.
onDoneBlock!(true)
답변
프레젠테이션 및 프레젠테이션보기 컨트롤러는 모두 프레젠테이션보기 컨트롤러 dismissViewController:animated:
를 해제하기 위해 호출 할 수 있습니다 .
전자의 옵션은 디자인 적으로 “올바른”옵션입니다. 동일한 “부모”뷰 컨트롤러가 모달 ( “하위”) 뷰 컨트롤러를 표시하고 해제하는 역할을합니다.
그러나 후자가 더 편리합니다. 일반적으로 “닫기”버튼이 제시된 뷰 컨트롤러의 뷰에 연결되고 뷰 컨트롤러가 작업 대상으로 설정되어 있습니다.
이전 접근 방식을 채택하는 경우, 해제가 발생하는 프레젠테이션 뷰 컨트롤러의 코드 줄을 이미 알고 있습니다. 바로 뒤에 코드를 실행 dismissViewControllerAnimated:completion:
하거나 완료 블록 내에서 코드를 실행합니다 .
후자의 접근 방식을 채택하는 경우 (제공된 뷰 컨트롤러가 자동으로 해제 됨), dismissViewControllerAnimated:completion:
제시된 뷰 컨트롤러에서 호출 하면 UIKit이 제시하는 뷰 컨트롤러에서 해당 메서드를 차례로 호출하게됩니다.
토론
프리젠 테이션 뷰 컨트롤러는 자신이 제시 한 뷰 컨트롤러를 해제 할 책임이 있습니다. 제시된 뷰 컨트롤러 자체에서이 메서드를 호출하면 UIKit은 제시 뷰 컨트롤러에게 해제를 처리하도록 요청합니다.
( 출처 : UIViewController Class Reference )
따라서 이러한 이벤트를 가로 채기 위해 프레젠테이션 뷰 컨트롤러 에서 해당 메서드를 재정의 할 수 있습니다 .
override func dismiss(animated flag: Bool,
completion: (() -> Void)?) {
super.dismiss(animated: flag, completion: completion)
// Your custom code here...
}
답변
extension Foo: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
//call whatever you want
}
}
vc.presentationController?.delegate = foo
답변
unwind segue를 사용하여이 작업을 수행 할 수 있으며 dismissModalViewController를 사용할 필요가 없습니다. VC1에서 unwind segue 방법을 정의하십시오.
unwind segue를 만드는 방법에 대한이 링크, https://stackoverflow.com/a/15839298/5647055를 참조하십시오 .
unwind segue가 설정되었다고 가정하면 “Cancel”버튼에 대해 정의 된 작업 방법에서 다음과 같이 segue를 수행 할 수 있습니다.
[self performSegueWithIdentifier:@"YourUnwindSegueName" sender:nil];
이제 VC2에서 “취소”버튼을 누를 때마다 해제되고 VC1이 나타납니다. 또한 VC1에서 정의한 unwind 메서드를 호출합니다. 이제 제시된 뷰 컨트롤러가 언제 닫혔는지 알 수 있습니다.
답변
다음을 사용하여 코디네이터에게 뷰 컨트롤러가 “완료”되었음을 알립니다. 이것은 AVPlayerViewController
tvOS 애플리케이션 의 하위 클래스에서 사용되며 playerVC 해제 전환이 완료된 후에 호출됩니다.
class PlayerViewController: AVPlayerViewController {
var onDismissal: (() -> Void)?
override func beginAppearanceTransition(_ isAppearing: Bool, animated: Bool) {
super.beginAppearanceTransition(isAppearing, animated: animated)
transitionCoordinator?.animate(alongsideTransition: nil,
completion: { [weak self] _ in
if !isAppearing {
self?.onDismissal?()
}
})
}
}