26

I know this question has been asked and answered many times over here. But I am dealing with this thing for the first time and still not able to get the perfect implementation of it in my mind. Here's the code I have the delegate method I implement to pass data from SecondViewController to FirstViewController.

FirstViewController.h

#import "SecondViewController.h"

@interface FirstViewController : UITableViewController<sampleDelegate> 
@end

FirstViewController.m

@interface FirstViewController ()

// Array in which I want to store the data I get back from SecondViewController.
@property (nonatomic, copy) NSArray *sampleData;
@end

@implementation FirstViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
   SecondViewController *controller = [[SecondViewController alloc] init];          
   [self.navigationController pushViewController:controller animated:YES];
}
@end

SecondViewController.h

@protocol sampleDelegate <NSObject>
- (NSArray*)sendDataBackToFirstController;
@end

@interface SecondViewController : UITableViewController
@property (nonatomic, strong) id <sampleDelegate> sampleDelegateObject;
@end

SecondViewController.m

@interface SecondViewController ()
@property (strong, nonatomic) NSArray *dataInSecondViewController;
@end

@implementation SecondViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.dataInSecondViewController = [NSArray arrayWithObjects:@"Object1", @"Object2", nil];
}

- (NSArray*)sendDataBackToFirstController
{
    return self.dataInSecondViewController;
}
@end

Am I doing it correctly? All I want it to send the data in self.dataInSecondViewController to FirstViewController and store it over there in the NSArray property sampleData of FirstViewController.

Somehow I am not able to access sendDataBackToFirstController in FirstViewController. What other things I am missing implementing to access sendDataBackToFirstController there?

Mark Parnell
  • 9,175
  • 9
  • 31
  • 36
tech_human
  • 6,592
  • 16
  • 65
  • 107
  • 1
    You need to set the first vc as delegate of second vc. So the delegate method of second vc needs to be implemented in first vc. Then invoke the method from second vc when the event is triggered. From your scenario its unclear if you want to have a datasource or delegate. If you use second vc as a datasource for first vc, it is the first vc which requests data. But you just want to return the value back to first vc when some event happens in second vc then its kind of delegate. Then you would need to change the return type to void and pass the data as argument. – Anupdas Dec 17 '13 at 04:08
  • Correct. I tried doing controller.delegate = self in didSelectRow... of my First vc. But somehow controller is not able to find the delegate object. Does my code seem to be correct so far? – tech_human Dec 17 '13 at 04:09
  • Please follow answers of @gdavis and art – Anupdas Dec 17 '13 at 04:12
  • @NANNAV - Not sure how is this question a duplicate. I did mention in the very initial starting of my question that it has been answered already, but the question is specific to my implementation. The answer there didn't help me much with implementing my code thats why I started another question. – tech_human Dec 17 '13 at 04:47
  • there is one more option other than protocols and delegates that is blocks simple and easy to implement.... – Leena Dec 17 '13 at 05:42

3 Answers3

15

Not quite right. First you need to assign the delegate property in the first view controller so the second view controller knows which object to send messages to.

FirstViewController.m

controller.delegate = self;

Second, you have the sending and receiving of your delegate method backwards. You have it setup in a way where the FirstViewController is expected to call sendDataBackToFirstController on the second controller. In a delegate pattern, the SecondViewController is the one that sends the message and optionally sends data with that method. So, you should change your delegate declaration to something like this:

@protocol sampleDelegate <NSObject>
- (void)secondControllerFinishedWithItems:(NSArray* )newData;
@end

Then, when your SecondViewController finishes its tasks and needs to notify its delegate, it should do something like this:

// ... do a bunch of tasks ...
// notify delegate
if ([self.delegate respondsToSelector:@selector(secondControllerFinishedWithItems:)]) {
    [self.delegate secondControllerFinishedWithItems:arrayOfNewData];
}

I added an extra if statement here to check to make sure the delegate will respond to the method we want to send it before actually sending it. If we had optional methods in our protocol and did not have this, the app would crash.

Hope this helps!

gdavis
  • 2,556
  • 1
  • 20
  • 25
  • Your and @art's explanation helped me a lot in understanding the entire flow of the protocol and delegates. I followed your and art's code to implement the delegates and I got what I wanted. I changed the delegate property to weak instead of strong to prevent the retain cycle. – tech_human Dec 17 '13 at 04:51
4

Please follow this

FirstViewController.h

   #import "SecondViewController.h"

   @interface FirstViewController : UITableViewController<sampleDelegate> 
   @end

FirstViewController.m

  @interface FirstViewController ()

  // Array in which I want to store the data I get back from SecondViewController.
  @property (nonatomic, copy) NSArray *sampleData;
  @end

 @implementation FirstViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
   SecondViewController *controller = [[SecondViewController alloc] init]; 
   controller.sampleDelegateObject=self;      
  [self.navigationController pushViewController:controller animated:YES];

 }

  //implementation of delegate method
  - (NSArray*)sendDataBackToFirstController
{
  return self.dataInSecondViewController;
}
 @end

SecondViewController.h

 @protocol sampleDelegate <NSObject>
- (NSArray*)sendDataBackToFirstController;
@end

@interface SecondViewController : UITableViewController
@property (nonatomic, strong) id <sampleDelegate> sampleDelegateObject;
@end
SecondViewController.m

 @interface SecondViewController ()
 @property (strong, nonatomic) NSArray *dataInSecondViewController;
 @end

 @implementation SecondViewController

 - (void)viewDidLoad
{
  [super viewDidLoad];
  self.dataInSecondViewController = [NSArray arrayWithObjects:@"Object1", @"Object2", nil];
   //calling the delegate method
  [sampleDelegateObject sendDataBackToFirstController];
}


  @end
Albin Joseph
  • 1,133
  • 15
  • 27
1

First change @property (nonatomic, strong) id <sampleDelegate> sampleDelegateObject; to @property (nonatomic, weak) id <sampleDelegate> sampleDelegateObject; to prevent retain cycle search google with that word for explanation.

Second your protocol should be

@protocol sampleDelegate <NSObject>
- (void)sendDataBackToFirstController:(NSArray*)dataToSendBack;
@end

and when you want to send data back you call [self.sampleDelegateObject sendDataBackToFirstControoler:yourData]; first view controller must implement those method in protocol.

sarunw
  • 8,036
  • 11
  • 48
  • 84