dismissModalViewController 및 데이터 다시 전달


84

두 개의 뷰 컨트롤러, firstViewControllersecondViewController가 있습니다. 이 코드를 사용하여 secondViewController로 전환합니다 (문자열도 전달하고 있습니다).

secondViewController *second = [[secondViewController alloc] initWithNibName:nil bundle:nil];

second.myString = @"This text is passed from firstViewController!";

second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

[self presentModalViewController:second animated:YES];

[second release];

그런 다음 secondViewController에서이 코드를 사용하여 firstViewController로 다시 전환합니다.

[self dismissModalViewControllerAnimated:YES];

이 모든 것이 잘 작동합니다. 내 질문은 firstViewController에 데이터를 어떻게 전달합니까? secondViewController에서 firstViewController로 다른 문자열을 전달하고 싶습니다.

답변:


142

위임 프로토콜을 사용해야합니다 ... 방법은 다음과 같습니다.

secondViewController의 헤더 파일에서 프로토콜을 선언하십시오. 다음과 같이 표시되어야합니다.

#import <UIKit/UIKit.h>

@protocol SecondDelegate <NSObject>
-(void)secondViewControllerDismissed:(NSString *)stringForFirst
@end


@interface SecondViewController : UIViewController
{
    id myDelegate;  
}

@property (nonatomic, assign) id<SecondDelegate>    myDelegate;

구현 (SecondViewController.m) 파일에서 myDelegate를 합성하는 것을 잊지 마십시오.

@synthesize myDelegate;

FirstViewController의 헤더 파일에서 다음을 수행하여 SecondDelegate 프로토콜을 구독하십시오.

#import "SecondViewController.h"

@interface FirstViewController:UIViewController <SecondDelegate>

이제 FirstViewController에서 SecondViewController를 인스턴스화 할 때 다음을 수행해야합니다.

// If you're using a view controller built with Interface Builder.
SecondViewController *second = [[SecondViewController alloc] initWithNibName:"SecondViewController" bundle:[NSBundle mainBundle]];
// If you're using a view controller built programmatically.
SecondViewController *second = [SecondViewController new]; // Convenience initializer that uses alloc] init]
second.myString = @"This text is passed from firstViewController!";
second.myDelegate = self;
second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second animated:YES];
[second release];

마지막으로 첫 번째 뷰 컨트롤러 (FirstViewController.m)의 구현 파일에서 secondViewControllerDismissed에 대한 SecondDelegate의 메서드를 구현합니다.

- (void)secondViewControllerDismissed:(NSString *)stringForFirst
{
    NSString *thisIsTheDesiredString = stringForFirst; //And there you have it.....
}

이제 두 번째 뷰 컨트롤러를 닫으려고 할 때 첫 번째 뷰 컨트롤러에서 구현 된 메서드를 호출하려고합니다. 이 부분은 간단합니다. 두 번째 뷰 컨트롤러에서 해제 코드 앞에 코드를 추가하면됩니다.

if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:)])
{
    [self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!"];
}
[self dismissModalViewControllerAnimated:YES];

위임 프로토콜은 매우, 매우, 매우 유용합니다. 그들에 익숙해지면 좋을 것입니다 :)

NSNotifications는이를 수행하는 또 다른 방법이지만 모범 사례로서 여러 viewController 또는 개체간에 통신하려는 경우 사용하는 것을 선호합니다. NSNotifications 사용에 대해 궁금한 경우 이전에 게시 한 답변은 다음과 같습니다 . appdelegate의 스레드에서 여러 뷰 컨트롤러에 걸쳐 이벤트 발생

편집하다:

여러 인수를 전달하려는 경우 닫기 전 코드는 다음과 같습니다.

if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:argument2:argument3:)])
{
    [self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!" argument2:someObject argument3:anotherObject];
}
[self dismissModalViewControllerAnimated:YES];

즉, firstViewController 내부의 SecondDelegate 메서드 구현이 다음과 같이 보일 것입니다.

- (void) secondViewControllerDismissed:(NSString*)stringForFirst argument2:(NSObject*)inObject1 argument3:(NSObject*)inObject2
{
    NSString thisIsTheDesiredString = stringForFirst;
    NSObject desiredObject1 = inObject1;
    //....and so on
}

iOS 용 Apple의 View Controller Programming Guide에 따르면 secondViewController는 제시된 뷰 컨트롤러가 아니라 제시하는 뷰 컨트롤러에서 해제되어야합니다.
Michael

UITableView의 델리게이트를 설정하지 않은 것 같습니다. 가지고있는 코드와 함께이 질문을 게시하고 다시 동그라미를 치시겠습니까? 도와 드릴 수있을 것 같습니다.
Sid

1
@Michael 문서에 따르면 dismiss on self를 호출하면 해당 호출이 표시되는 뷰 컨트롤러로 전달됩니다. 또한 self를 호출하는 것은 대상이되는 iOS 버전 (5 이전)에 따라 presentingViewController와 parentViewController를 전환하는 것에 대해 걱정할 필요가 없기 때문에 더 깔끔합니다.
Sid

1
@Resty 동의합니다. 블록은 놀랍도록 유용합니다. 나는 어떤 시점에서 블록을 지원하기 위해이 답변을 변경할 것을 고려하고있었습니다. 그러나이 경우 모달에 전달할 수있는 개체를 좀 더 자유롭게 조작 할 수 있기 때문에 지금은 대리자 대답을 표시했습니다. 나는 단지 게으르고 곧 블록을 사용하기 위해이 답변을 업데이트 할 것입니다 :)
Sid

1
@ sid 감사합니다 형제 나를 위해 작동하지만 약간 수정해야합니다. 많은 것들이 변화했습니다. 그것을 편집하십시오
ChenSmile

40

여기서 벗어날 수는 있지만 매우 장황한 델리게이트 / 프로토콜 접근 방식보다 블록 구문을 선호하기 시작했습니다. vc1에서 vc2를 만들면 블록 인 vc1에서 설정할 수있는 vc2의 속성을 가지세요!

@property (nonatomic, copy) void (^somethingHappenedInVC2)(NSString *response);

그런 다음 vc2에서 vc1에 알리고 싶은 일이 발생하면 vc1에서 정의한 블록을 실행하십시오!

self.somethingHappenedInVC2(@"Hello!");

이를 통해 vc2에서 vc1로 데이터를 다시 보낼 수 있습니다. 마법처럼. IMO, 이것은 프로토콜보다 훨씬 쉽고 / 깨끗합니다. 블록은 굉장하며 가능한 한 많이 수용해야합니다.

편집-개선 된 예

사용자로부터 입력을 받기 위해 일시적으로 modalVC를 표시하려는 mainVC가 있다고 가정 해 보겠습니다. mainVC에서 해당 modalVC를 표시하려면 mainVC 내부에 할당 / 초기화해야합니다. 아주 기본적인 것들. 이 modalVC 객체를 만들 때 두 vc 객체간에 쉽게 통신 할 수 있도록 블록 속성을 설정할 수도 있습니다. 따라서 위의 예를 들어 modalVC의 .h 파일에 다음 속성을 입력 해 보겠습니다.

 @property (nonatomic, copy) void (^somethingHappenedInModalVC)(NSString *response);  

그런 다음 mainVC에서 새 modalVC 객체를 할당 / 초기화 한 후 다음과 같이 modalVC의 블록 속성을 설정합니다.

ModalVC *modalVC = [[ModalVC alloc] init];
modalVC.somethingHappenedInModalVC = ^(NSString *response) {
     NSLog(@"Something was selected in the modalVC, and this is what it was:%@", response);
}

그래서 우리는 블록 속성을 설정하고 그 블록이 실행될 때 일어나는 일을 정의하고 있습니다.

마지막으로, modalVC에서 문자열의 dataSource 배열로 지원되는 tableViewController를 가질 수 있습니다. 행 선택이 이루어지면 다음과 같이 할 수 있습니다.

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      NSString *selectedString = self.dataSource[indexPath.row];
      self.somethingHappenedInModalVC(selectedString);
 }

물론 modalVC에서 행을 선택할 때마다 NSLog 라인에서 콘솔 출력을 mainVC로 가져옵니다. 도움이 되었기를 바랍니다.


1
스토리 보드를 사용할 때 여전히 작동해야합니까? 지금은 나를 위해 작동하지 않습니다. lldb 오류로 종료됩니다. 주요 차이점. vc의 할당이 이제 인스턴스화 된 스토리 보드 흐름임을 알 수 있습니다. 편집 그리고 블록을 만들기 전에 발표했습니다. 결정된.
malaki1974 2014

2
나는 당신과 동의합니다 :) 나는 꽤 오래 전에 내 대답을 게시했습니다. 이제 사용량에 따라 블록 / 프로토콜 사용을 전환합니다. 이 스레드가 오늘날까지 꽤 활동적이므로 언젠가는 블록을 포함하도록 내 대답을 편집해야합니다.
Sid

1
이 답변은 가장 직관적 인 솔루션을 제공하기 때문에 받아 들여 져야합니다.
Sukitha Udugamasooriya

2
두 가지 적절한 답변 중 이것이 가장 좋은 답변입니다!
kygcoleman 2015-07-07

1
이것은 내가 선호하는 방법입니다. 신속하게 이것은 폐쇄로 수행됩니다. 프로토콜이나 "추악한"알림 상수를 지정할 필요가 없기 때문에 델리게이트 및 알림보다 훨씬 좋습니다. 클로저를 멋지게 유지하는 제시된 vc에서 변수의 이름을 만들면 예를 들어 매우 직관적 인 코드가 될 수 있습니다. Vc.didCancel, vc.didFinish ...이를 제공하는 vc의 prepareForSegue에서 설정할 수 있습니다 (세그를 사용하는 경우).
HixField 2016-04-26

4

흠, 알림 센터를 찾아 알림에 정보를 전달합니다. 여기에 사과가 있습니다. 다른 제안이없는 한 개인적으로이 접근 방식을 취합니다.


링크는 실제로 그것을 지나치게 복잡하게 만듭니다. 필요한 것은 관찰자 (첫 번째 뷰 컨트롤러)이고 두 번째에서 알림을 보내는 것뿐입니다. 알림에 선택기를 할당하고 알림을 통해 정보를 다시받을 수도 있습니다.
theiOSDude 2011-06-01

2

두 번째 뷰 컨트롤러에서 델리게이트 프로토콜을 정의하고 첫 번째를 두 번째의 델리게이트로 만듭니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.