2

Basically, I am now intend to use delegate to pass values between view controllers.

The flow of the view controllers is A -> B -> C

When the user does some action in the "C" view controller, how to pass the value back to the first view controller, which is "A"?

In my own code, the delegate method is never triggerred and "self.delegate" is always "null". I am not sure why and how to solve this problem.

Below is the code of the First VC and Third VC:

#import "ViewController.h"
#import "ThirdViewController.h"

@interface ViewController ()<PassValueProtocal>
@property (weak, nonatomic) IBOutlet UILabel *myLabel;

@end

@implementation ViewController
{
    ThirdViewController *thirdVC;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void) passValueBack:(NSString *)value
{
    NSLog(@"HAHAH");
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (IBAction)segueToSecondVC:(UIButton *)sender
{
    thirdVC = [ThirdViewController sharedManager];
    thirdVC.delegate = self;
}

@end

#import "ThirdViewController.h"

@interface ThirdViewController ()
@property (weak, nonatomic) IBOutlet UITextField *myTextField;

@end

@implementation ThirdViewController

+ (id) sharedManager
{
    NSLog(@"myDelegate sharedManager");
    static ThirdViewController *sharedManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ sharedManager = [[self alloc] init]; });
    return sharedManager;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)passValueAction:(UIButton *)sender
{
    NSLog(@"%@", self.delegate);
    if ([self.delegate respondsToSelector:@selector(passValueBack:)])
    {
        [self.delegate passValueBack:self.myTextField.text];
    }
}
Mike Zhu
  • 107
  • 1
  • 1
  • 10

2 Answers2

0

The above code doesn't show where you're setting the delegate in your UIViewController. That's probably why it's nil and also why your delegate method is never fired. Set the delegate property after you initialize the UIViewController but before you push it like so:

// Inside your third viewcontroller class:
@interface ThirdViewController ()
@property (weak, nonatomic) id delegate; // make sure the delegate is set to weak
@end


// Maybe in your AppDelegate, before you push the third view controller
ThirdViewController *thirdVC = [[ThirdViewController alloc] init];
thirdVC.delegate = self;
// Now push the VC. The below assumes a UINavigationController but that detail isn't important.
[self.navigationController pushViewController:thirdVC animated:YES];
JaredH
  • 2,338
  • 1
  • 30
  • 40
  • But I don't want to push directly to the thirdVC, I just wanna the user to change some actions in the thirdVC and after that when the user goes back to the firstVC, he may see the changes triggered by the thirdVC – Mike Zhu Jul 28 '15 at 05:40
  • Right but you were saying that the delegate is always nil. That's because you're not setting it before you create the VC. – JaredH Jul 28 '15 at 05:42
  • Oh~~~I just forgot to copy the .h file of the thirdVC, I set it at the .h file of the third VC: – Mike Zhu Jul 28 '15 at 05:50
0

Yes it's possible to do. In order to pass data back from C -> A, you need to chain delegates

This is how storyboard looks: https://i.stack.imgur.com/BqPuY.png

Pay attention segue identifier in storyboard

FirstViewController:

import UIKit

class FirstViewController: UIViewController, SecondViewControllerDelegate {

    @IBAction func buttonPressed(sender: AnyObject) {
        performSegueWithIdentifier("goToSecondView", sender: self)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if(segue.identifier == "goToSecondView"){
            let secondVC: SecondViewController = segue.destinationViewController as! SecondViewController

            secondVC.delegate = self
        }
    }

    func speakSecond(name: String) {
        print("Data from Third view is: \(name)")
    }
}

SecondViewController:

import UIKit

protocol SecondViewControllerDelegate{
    func speakSecond(name: String)
}


class SecondViewController: UIViewController, ThirdViewControllerDelegate {

    var delegate: SecondViewControllerDelegate?

    @IBAction func buttonPressed(sender: AnyObject) {
        performSegueWithIdentifier("goToThirdView", sender: self)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if(segue.identifier == "goToThirdView"){
            let thirdVC: ThirdViewController = segue.destinationViewController as! ThirdViewController
            thirdVC.delegate = self
        }
    }

    func speakThird(name: String) {
        delegate?.speakSecond(name)
    }
}

ThirdViewController:

import UIKit

protocol ThirdViewControllerDelegate{
    func speakThird(name: String)
}

class ThirdViewController: UIViewController {

    var delegate: ThirdViewControllerDelegate?

    @IBOutlet var textField: UITextField!

    @IBAction func buttonPressed(sender: AnyObject) {
        let text = textField.text
        delegate?.speakThird(text)
        self.navigationController?.popToRootViewControllerAnimated(true)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}
berik
  • 1
  • 3