Development/아이폰
[Objective-C] 철탑만 몰랐던 iOS #5 - (InterfaceBuilder 만으로 화면결과 Delegating - UnwindingSegue Action )
江多林
2014. 6. 3. 14:27
InterfaceBuilder 만으로 화면결과 Delegating - UnwindingSegue Action
개요
- iOS6 이상에서 UIStoryBoard를 사용하는 경우에
상세에서 상위 화면으로 메시지를 전달하는 명쾌한 방법
관련 예제
UnwindSegue Example : https://developer.apple.com/library/ios/samplecode/UnwindSegue/Introduction/Intro.html
VC 의 관련 메소드
/* canPerformUnwind - unwindSegueAction 의 제공여부 확인*/
– canPerformUnwindSegueAction:fromViewController:withSender:
/* viewControlerFor - unwindSegueAction 을 처리할 VC 를 얻는 메소드 */
– viewControllerForUnwindSegueAction:fromViewController:withSender:
/* segueFor - unwindSegueAction 를 perform 할 때 사용할 segue 를 생성하는 메소드 */
– segueForUnwindingToViewController:fromViewController:identifier:
|
동작 로그
// - View Controller Hierachy -
Controller Hierarchy
<UIApplication: 0xc903750> { ControlResponder, <UIWindow: 0x13f4a260> }
| <KSBSplashViewController: 0x13f4bab0> { ControlResponder, <KSBLoginRootViewController: 0xc911d70> }
| | <KSBLoginRootViewController: 0xc911d70> { ControlResponder, <UINavigationController: 0x13fa5400> }
| | | <UINavigationController: 0x13fa5400> { ControlResponder, <UILayoutContainerView: 0xdb7bc00> }
| | | | <KSBLoginWebViewController: 0x13f53950> { ControlResponder, <UIView: 0x13fe9110> } // - ViewController Hierachy 에서 unwindSegue Handle 가능한 VC 찾기
-[KSBLoginWebViewController canPerformUnwindSegueAction:fromViewController:withSender:] has called with {
action = "returnActionForSegue:sender:";
fromVC = "<KSBLoginWebViewController: 0x13f53950>";
sender = "<UIBarButtonItem: 0x13fb3f00>";
superReturnCanPerform = 0;
}
-[KSBLoginRootViewController canPerformUnwindSegueAction:fromViewController:withSender:] has called with {
action = "returnActionForSegue:sender:";
fromVC = "<KSBLoginWebViewController: 0x13f53950>";
sender = "<UIBarButtonItem: 0x13fb3f00>";
superReturnCanPerform = 1;
} // Action 전송을 위한 Segue 생성
-[KSBLoginRootViewController segueForUnwindingToViewController:fromViewController:identifier:] has called with {
fromVC = "<KSBLoginWebViewController: 0x13f53950>";
identifier = "<null>";
superReturnSegue = {
destinationViewController = "<KSBLoginRootViewController: 0xc911d70>";
identifier = "<null>";
performHandler = "<__NSMallocBlock__: 0xdba99d0>";
sourceViewController = "<KSBLoginWebViewController: 0x13f53950>";
};
toVC = "<KSBLoginRootViewController: 0xc911d70>";
}
// prepareForSegue 실행 on Source with sender(Event Firing Control) -[KSBLoginWebViewController prepareForSegue:sender:] has called with segue:<UIStoryboardSegue:0xdbd2b00>{
destinationViewController = "<KSBLoginRootViewController: 0xc911d70>";
identifier = "<null>";
performHandler = "<__NSMallocBlock__: 0xdba99d0>";
sourceViewController = "<KSBLoginWebViewController: 0x13f53950>";
} sender:<UIBarButtonItem:0x13fb3f00>{
target = "<UIStoryboardUnwindSegueTemplate: 0x13f5d5b0>";
}
// actionForSegue 실행 on Target with sender:(Target ViewController) -[KSBLoginRootViewController returnActionForSegue:sender:] has called.
segue:<UIStoryboardSegue:0xdbd2b00>{
destinationViewController = "<KSBLoginRootViewController: 0xc911d70>";
identifier = "<null>";
performHandler = "<__NSMallocBlock__: 0xdba99d0>";
sourceViewController = "<KSBLoginWebViewController: 0x13f53950>";
} sender:<KSBLoginRootViewController:0xc911d70>{
"*class* UIViewController" = {
"*class* UIResponder" = {
"__content" = "<KSBLoginRootViewController: 0xc911d70>";
"_responderForEditing" = "<KSBLoginRootViewController: 0xc911d70>";
"_textSelectingContainer" = "<KSBLoginRootViewController: 0xc911d70>";
};
"_modalSourceViewController" = "<KSBSplashViewController: 0x13f4bab0>";
"_parentModalViewController" = "<KSBSplashViewController: 0x13f4bab0>";
"_presentedStatusBarViewController" = "<UINavigationController: 0x13fa5400>";
childModalViewController = "<UINavigationController: 0x13fa5400>";
"ka_presentedViewController" = "<UINavigationController: 0x13fa5400>";
modalViewController = "<UINavigationController: 0x13fa5400>";
nibName = "BBF-ZV-3Lw-view-N2m-qU-VNs";
parentModalViewController = "<KSBSplashViewController: 0x13f4bab0>";
presentedViewController = "<UINavigationController: 0x13fa5400>";
presentingViewController = "<KSBSplashViewController: 0x13f4bab0>";
storyboard = "<UIStoryboard: 0x13f45040>";
storyboardSegueTemplates = (
"<UIStoryboardModalSegueTemplate: 0xc914f70>",
"<UIStoryboardModalSegueTemplate: 0xc906cc0>"
);
};
}
// perform Segue (View Life Cycle Delegate) -[KSBLoginWebViewController viewWillDisappear:] has called
-[KSBLoginRootViewController viewWillAppear:] has called
-[KSBLoginRootViewController viewDidAppear:] has called
-[KSBLoginWebViewController viewDidDisappear:] has called
|
* 추가사항
- ContainerVC 에 속한 VC 의 경우에 ContainerVC 에서 구현되지 않은 경우에
ContainerVC 의 Parent 에게 전달된다. (responder Chain 과 같이 canPerformUnwind 메소드로 지원여부 확인)
- Unwinding Segue 는 -[targetVC segueForUnwindingToViewController:fromViewController:identifier:]에서 생성되며,
- 생성된 Unwinding Segue는 SourceVC 에서 실행되게 된다.
- 이 과정은 ViewLifeCycle 과 무관하게 그 이전에 실행되는 것으로 보인다.
- ViewController 의 동작의 결과를 다른 ViewController 로 전달하는 것은 매우 귀찮은 일이었다.
- 일반적으로 delegate 를 만들어서 결과를 알려주고, 결과를 받은 쪽에서 ViewController 를 내려주는 방식으로 코딩해왔다.
- iOS6 에서 등장한 UnwindingSegue 를 활용하면, delegate 사용보다 훨씬 직관적이고 단순하게 결과를 받을 수 있다.
* responder chain 을 이해하고 있다면, 개념파악에 도움이 된다.
- ViewController Hierachy 의 상위 VC 에서 -(IBAction)xxxActionForSegue:sender: 메소드를 구현하고,
InterfaceBuilder 에서 'Exit' 링크로 연결하면 해당 Segue 기동시에 ActionForSegue: 가 호출된다.
복잡해보이지만, 실제로는 코딩은 한 줄과, IB 에서 action을 하나 연결한 것이 전부.
- (IBAction)returnActionForSegue:(UIStoryboardSegue *)segue
{
NSLog(@"%s has called. segue:%@", __PRETTY_FUNCTION__, [segue KCCPD_propertiesDescription]);
}
|