Pass data back to previous viewcontroller

2019-01-02 14:52发布

I am trying to pass data BACK TO previous viewController.

Does anyone know how to pass data back from ViewController B to ViewController A? So I want a string to go 'from' BIDAddTypeOfDealViewController to BIDDCCreateViewController. A user edits viewController B and I want that edited data back in ViewController A where I then use it.

I am using the 'passing data back' section of this answer. How mine differs: Point 3 and 6 just mentions when views are popped so I have put that code in viewWillDisappear. I think that is correct? Also on Point 6 I did not initialise with nib as that is old. I'm using storyboards. And I did not add that last line as I do not believe I would have to push it. Pressing a button on my storyboard already takes me forward.

I think the problem may arise in BIDDCCreateViewController, I have the method but I cannot run it. To run a method it should go [self method]. I am unable to do that. Well that is just what I am guessing.

It compiles and runs fine just nothing is logged, so I don't know if it works.

UPDATE: I am unable to get the 'sendDataToA' method to execute.

#import <UIKit/UIKit.h>
#import "BIDAddTypeOfDealViewController.h"

 @interface BIDDCCreateViewController : UIViewController
 @property (strong, nonatomic) NSString *placeId;
- (IBAction)gotoBViewController:(id)sender;
@end


#import "BIDDCCreateViewController.h"
#import "BIDAddTypeOfDealViewController.h"

@implementation BIDDCCreateViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSLog(@"SUCCESSFULLY PASSED PLACE ID: %@", self.placeId);
}

-(void)sendDataToA:(NSString *)myStringData
{

    NSLog(@"Inside sendDataToA");
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Your string Data Showing" message:myStringData delegate:self cancelButtonTitle:@"Ok " otherButtonTitles:nil];
    [alert show];
}

- (IBAction)gotoBViewController:(id)sender {
    NSLog(@"pressed");
    BIDAddTypeOfDealViewController *bidAddType = [[BIDAddTypeOfDealViewController alloc]init];
    bidAddType.delegate = self;

}
@end


@protocol senddataProtocol <NSObject>
-(void)sendDataToA:(NSString *)myStringData;
@end

#import <UIKit/UIKit.h>
@interface BIDAddTypeOfDealViewController : UIViewController <UITextFieldDelegate>//Using this delegate for data a user inputs
@property(nonatomic,assign)id delegate;
//other textfield outlets not relevant
- (IBAction)chooseDiscountDeal:(id)sender;
@end

#import "BIDAddTypeOfDealViewController.h"

@interface BIDAddTypeOfDealViewController ()

@end

@implementation BIDAddTypeOfDealViewController
@synthesize delegate;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
}

-(void)viewWillDisappear:(BOOL)animated
{
    [delegate sendDataToA:@"Apple"];
}
@end

8条回答
闭嘴吧你
2楼-- · 2019-01-02 15:46

There is protocol there is closure. With closure, we need to avoid memory leaks by using weak self (or unowned self). With protocol, there would be one per viewController that you want to "monitor", end up with dozens of delegate to implement. Here I've another simple solutions in Swift:

Inside a new file or existing one (for example: UIViewController+Extensions.swift), create this protocol:

protocol ViewControllerBackDelegate: class {
    func back(from viewController: UIViewController)
}

Inside LEVEL-2 viewController, where you want a callback when Back is pressed from:

class LevelTwoViewController: UIViewController {
    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: ViewControllerBackDelegate? = nil

    override func willMove(toParentViewController parent: UIViewController?) {
        super.willMove(toParentViewController: parent)
        if (parent == nil) {
            delegate?.back(from: self)
        }
    }
}

Since delegate is optional, you may add this code to a base class of your view controllers. I would add to where it needs to be.

In your LEVEL-1 viewController, assume you calling LEVEL-2 via a segue in Storyboard:

class LevelOneViewController: UIViewController {
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "Go to Level 2") {
            if let vc = segue.destination as? LevelTwoViewController {
                vc.selectedItems = self.selectedItems // passing data-in
                vc.delegate = self
            }
        }
        // repeat `if` for another sub-level view controller
    }
}

extension LevelOneViewController: ViewControllerBackDelegate {    
    func back(from viewController: UIViewController) {
        if let vc = viewController as? LevelTwoViewController {
            self.selectedItems = vc.selectedItems
            // call update if necessary
        }
        // repeat `if` for another sub-level view controller
    }
}
  • only one protocol is required.
  • only one extension per first-level viewController.
  • no modifications to sub-level viewController if more/less data need to return
  • handle data-out just like data-in in prepare(for:sender:)
查看更多
路过你的时光
3楼-- · 2019-01-02 15:47

Edit: Use @Erhan's solution above. Not this one. This is not a good solution.

This will help. Write this in your ViewControllerB.

    // Get array of current navigation stack
    NSArray *arrayViewControllers = [self.navigationController viewControllers];

    // Get previous viewController object from it
    YOUR_VIEW_CONTROLLER_NAME *objViewController = (YOUR_VIEW_CONTROLLER_NAME *)[arrayViewControllers objectAtIndex:arrayViewControllers.count-2];

    // For safety this check is needed. whether it the class that you want or not.
    if ([objViewController isKindOfClass:[YOUR_VIEW_CONTROLLER_NAME class]])
    {
        // Access properties of YOUR_VIEW_CONTROLLER_NAME here
        objViewController.yourProperty = YOUR_VALUE;
    }
查看更多
登录 后发表回答