Pass NSNumber back through segue - ios

I have used prepareForSegue successfully, which I have managed to pass variables though. I am trying to now pass a NSNumber through the reverse of the segue but prepareForSegue is not getting called. To get back to my previous VC I am using:
[self.navigationController popViewControllerAnimated:YES];
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowImages"]) {
DiaryViewController *photoNumber = [segue destinationViewController];
photoNumber.deleteObject = self.rowTodelete;
}
Is there something I can add to make the prepareForSegue to work in reverse. Or would I need to access my NSNumber from the different class somehow?

If you set up an unwind segue, you can get the UIViewController that is causing the unwind.
Check out this answer here about Unwind Segues.
Once you actually set up the unwind segue structure, here's some sample unwind segue code:
- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue {
UIViewController* sourceViewController = unwindSegue.sourceViewController;
if ([sourceViewController isKindOfClass:[DiaryViewController class]] {
DiaryViewController *photoNumber = (DiaryViewController *)sourceViewController;
NSNumber *deleteObject = photoNumber.deleteObject;
}
}

You could also use the Delegate-Pattern for it.
Just set the current Controller as the Delegate of the destination controller and create a protocol that defines which method the delegate should be implement.
Then you can pass any parameters you want back to the source Viewcontroller if your destination controller gets dismissed.
// Source Controller (which is also the delegate of the destination-controller)
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SomeController * a = segue.destinationController;
a.delegate = self;
}
// Delegate Method
-(void)viewControllerGotDismissed:(NSNumber*)test{
NSlog(#"TEST:%#",test);
}
// Destination Controller
#protocol SomeProtocol
-(void)viewControllerGotDismissed:(NSNumber*)test;
#end
// Destination Controller
-(void)viewWillDisappear {
// ....
[self.delegate viewControllerGotDismissed:#1337]; // Pass the value to the source Controller
}
#end

Another method that could work for you is assigning a completion block to run when the presented view is dismissed. For example, if A presents B with a segue, then set a completion block when you initially segue to B. When B is about to be dismissed, run the completion block.
In ViewControllerB.h
#property (nonatomic, strong) void (^onDismiss)(UIViewController *sender, NSNumber *aNumber);
In ViewControllerB.m
// execute the block right before A is presented again
- (void)viewWillDisappear:(BOOL)animated {
self.onDismiss(self, aNumberToPassBack); // Run the block
}
In ViewControllerA.h
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"SegueToB"]) {
ViewControllerB *vcb = [segue destinationViewController];
vcb.onDismiss = ^(UIViewController *sender, NSNumber *aNumber) {
self.aNumber = aNumber;
// ... update your views if needed
};
}
}

Related

IOS prepareForSegue pass a data successfully but viewdidload clear it?

In UIViewController A I performSegue to UIViewControllerB.And in the prepaerForSegue function of A, I use set function set a strong variable 's value of B. However, when the B's viewDidLoad() called, the value is nil.
Anybody help me and tell me why?
my code is:
UIViewController A:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
CXPWDViewController *cxpwdViewController=[[CXPWDViewController alloc] init];
//I can't use the segue.desinationViewController, cause it is a present modally , the desinationViewController is navigationViewController.
[cxpwdViewController setAction:#"EnterPasscode"];//here the cxpwdViewController .action is #"EnterPasscode"
}
UIViewController B:
-(void) viewDidLoad()
{
[super viewDidLoad];// here the cxpwdViewController .action is nil; Why?
}
If you are presenting an UINavigationViewController, then the rootViewController controller should be your CXPWDViewController. So that you can typeacast the same. Since you are creating an anaother viewcontroller instance you are not getting the value.Try this code.
UIViewController A:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue destinationViewController] isKindOfClass:[UINavigationViewController class]])
{
UINavigationViewController* destinationNavController =(NavigationViewController*)[segue destinationViewController];
CXPWDViewController *cxpwdViewController=(CXPWDViewController*)[destinationNavController.viewControllers firstObject];
if([cxpwdViewController isKindOfClass:[CXPWDViewController class]])
{
[cxpwdViewController setAction:#"EnterPasscode"];
}
}
}
CXPWDViewController *cxpwdViewController=[[CXPWDViewController alloc] init];
//I can't use the segue.desinationViewController
I don't know why you think you can't use the segue destination view controller. But in any case you certainly can't do what you want to do this way. You are creating a completely different CXPWDViewController - and then destroying it an instant later. You won't get far that way!

Loading another view in the same viewController clears non UI properties

I have a UIViewController controlling several different views in Xcode. I want to set a label on the incoming view using information from the current view. I know labels and other UI elements get reset when the view is loaded, but my non UI #property is being set to nil as well.
Here is my property:
#property (strong, nonatomic) NSString* username;
Here is the code that sets it:
//NSLog(#"%#",dict);
if ([dict[#"login"] intValue]){
[self performSegueWithIdentifier:#"JoinSuccess" sender:sender];
self.username = dict[#"user"];
Here is the code that tries to use it:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", self.username);
self.welcomeLabel.text = [NSString stringWithFormat:#"Welcome, %#",self.username];
}
I've tried setting username both before and after performSegueWithIdentifier, but in either case when I try to reference it in viewDidLoad the value is nil. Any idea as to why it's reseting my #property? My guess is maybe it's creating a new instance of my viewController. If that's the case, how can I pass the needed variable?
As you said the viewController will be created again when ever you call performSegueWithIdentifier. You could set the value in the new instance. You can do this in
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
YourViewController *vc = [segue destinationViewController];
vc.username = dict[#"user"];
}
you have to add another method to pass value from one view controller to another view controller .
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
nextViewcontroller *nextViewcontrollerObjt = [segue
destinationViewController];
// apply setter to set value of next view
nextViewcontrollerobject.title = nextViewControllerTitleString;
nextViewcontrollerobject.variable_1= currentView_variable1;
nextViewcontrollerobject.variable_2 =currentView_variable2;
}

Pass info to viewcontroller on storyboard

I'm new using storyboards and I'm facing this situation: A uinavigationcontroller contains a view controller (root controller) which contains ten buttons linked each one of then through storyboard to the same view controller.
The behavior of the second view controller depends on the button tapped in the first view controller, but how can identify which button is tapped (like tag value) and pass this info to second view controller?
Thank you.
To add on Daniel's answer:
First, add a public property onto your secondVC that is accessible from your first VC:
#interface SecondViewController : UIViewController
#property (nonatomic) int buttonTagClicked;
#end
You need to set tags up on your UIButtons. This is either done in storyboard or programmatically in your code. I would create a generic IBAction that each button is linked to. You can extract the tag off the button through the sender parameter later.
- (IBAction)buttonClicked:(id)sender
{
[self performSegueWithIdentifier:#"pushSegue" sender:sender];
}
That is linked up to
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"pushSegue"]) {
SecondViewController *destinationVC = (SecondViewController *)[segue destinationViewController];
UIButton *selectedButton = (UIButton *)sender;
destinationVC.buttonTagClicked = selectedButton.tag;
}
}
You can set a segueIdentifier for each connection. Then in your ViewController you could trigger an action based on the identifier you set.
e.g.:
If you select your connection in storyboard you can name it:
And in your ViewController you can trigger an action based on the identifier like this:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segue1"]) {
UIViewController *destinationVC = [segue destinationViewController];
destinationVC.property = ...;
}
}

Segue to a UITableViewController with custom init

I have a simple push segue that goes from one UITableViewController to another. At the time of initing the other UITableViewController, I want to pass an id that will be used to perform an sqlite query and populate the table. I could use a public property and reload the table in a custom setter, but the design seems better if it is done on initing. After searching around for quite a while I haven't been able to find any clear examples. I have a seen a mentions of initWithCoder and initWithFrame but they haven't been clear enough to connect it to what I am trying to do.
Here is what the segue looks like from the first table:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowFlashcards"]) {
//pass variable to custom init somewhere around here?
FlashcardsTableViewController *flashcardsTableViewController = [segue destinationViewController];
}
}
Here is what the custom init looks like:
#property (nonatomic, strong) NSNumber *listId;
#property (nonatomic, strong) NSArray *flashcards;
- (id)initWithListId:(NSNumber *)listId {
self = [super init];
if (self ) {
self.listId = listId;
Database *db = [[Database alloc] init];
self.flashcards = [db getWordsFromList:[listId integerValue]];
}
return self;
}
You are over-thinking this, and coming to some wrong conclusions.
Adding a property to the destination VC (view controller) and setting it in prepareForSegue is exactly what you want to do.
You can't use a custom init in this situation. Invoking the segue allocates and initializes the destination VC (actually, I believe it is created using the initWithCoder method.) The destination VC's view won't have been loaded yet when prepareForSegue is called, so you can set properties and they will be set up by the time the destination VC's viewDidLoad method gets called.
#AJHacker's answer shows how to give the destination VC a pointer to the source VC, which is useful when the destination needs to be able to send data back.
You would need to add a property that contains a reference of the first view into the second view. For example:
#interface AutoRenewDrop
#property(weak, nonatomic) AddR *callerView;
#end
And then in the 'done' method of the second view you can just update the variables in the caller view like so:
-(IBAction)done:(UIStoryboardSegue *)segue {
[self.navigationController popViewControllerAnimated:YES];
callerView.renewDate.text = transferData;
}
Of course when you initiate the second view you will have to set the reference, like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Check Mark Segue"])
{
NSLog(#"Transfering Data");
AutoRenewDrop *controller = segue.destinationViewController;
controller.transferData = self.renewDate.text;
controller.callerView = self; //Here, you are passing the reference to this View
}
}
Hope that helps

Passing parameter using Storyboard

I want to create a game which is basically ask your buddy to put a word. And you will guess what word has been entered. For that reason, I have to pass guesword from FirstViewController to SecondViewController.
First View Controller
- (IBAction)doneBtn:(id)sender {
self.guessWord = [enterTF.text lowercaseString];
NSLog (#"Guessword s %#", guessWord);
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
NSLog (#"%#", [segue identifier]);
if ([[segue identifier] isEqualToString:#"F2S"])
{
// Get reference to the destination view controller
SecondViewController *gvc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
gvc.guessWord =self.guessWord;
}
}
Second View Controller
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#",guessWord);
}
In the SecondViewController guessword output "null". Why am I getting null?
In the second view controller, declare your variable in the .h file, say a string type:
#property (nonatomic, strong) NSString *someText;
Synthesize it in the .m file:
#synthesize someText;
In the first view controller's segue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
NSLog (#"%#", [segue identifier]);
if ([[segue identifier] isEqualToString:#"F2S"])
{
// Get reference to the destination view controller
SecondViewController *gvc = [segue destinationViewController];
gvc.someText = **YOUR TEXT HERE** ; //this should set the value in the second view controller
}
}
If the passed value is not a string, change accordingly.
Here is the sequence of events happening in your code:
The segue object is created. Source and destination view controllers are set on the segue, causing the second view controller to be loaded.
-viewDidLoad: is called on the second view controller.
-prepareForSegue: is called on the first view controller.
-viewWillAppear: and -viewDidAppear: are called on the second view controller.
-viewDidLoad: is called before guessWord is configured in -prepareForSegue:. Try -viewWillAppear: or -viewDidAppear: instead when logging guessWord.

Resources