getting NSException while passing data from one viewController to another viewController - ios

I am passing a data from one viewController to another viewController. But it is throwing NSException.
Here is my code.
viewcontroller.m
NSString *empid1 = [dataDict objectForKey:#"EmployeeId"];
NSLog(#"empid %#",empid1); //it prints 161.
DashBoardViewController *dash = [[DashBoardViewController alloc]initWithNibName:#"DashBoardViewController" bundle:nil];
dash.empid = empid1;
DashBoardViewController.h
#property (strong, nonatomic) NSString * empid;
DashBoardViewController.m
NSString *strURL=[NSString stringWithFormat:#"http://192.168.1.1:8002/api/Case/GetCaseByEmployeeID/?empId=%#",_empid];
It throws data is nil.NSException.Any help will be appreciated.

plz use this you are using storyboard
pass your value like this
[self performSegueWithIdentifier:#"DashBoardViewController" sender:[dataDict objectForKey:#"EmployeeId"]];
use this method when you use performSegueWithIdentifier
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([segue.identifier isEqualToString:#"DashBoardViewController"])
{
DashBoardViewController *dash= segue.destinationViewController;
dash.empid =(NSString *)sender;
}
}

YOURCONTROLLER *chatdetail=[[YOURCONTROLLER alloc] initWithNibName:#"YOURCONTROLLER_IDENTIFIER" bundle:nil];
chatdetail.strTitle = "YOUR VALUE"
[self.navigationController pushViewController:chatdetail animated:YES];
Next Controller
#property (weak, nonatomic) NSString *strTitle;
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#",self.strTitle);
}

Reason
It is happening because the DashboardViewController Which you are instantiating and setting the property empid is different from the DashboardViewController instance on which segue is performed. You are instantiating it with the following code
DashBoardViewController *dash = [[DashBoardViewController alloc]initWithNibName:#"DashBoardViewController" bundle:nil];
dash.empid = empid1;
But the DashBoardViewController which is being used by iOS is being created in prepareForSegue method and is different from dash created by you. For debugging purpose put some default value in empid property and then call performSegueWithIdentifier.It calls prepareForSegue method.ViewController on which segue will happen will be passed as destinationViewController as a parameter in this method whic will be of type UIViewController.Override this method.Downcast destinationViewController as DashBoardViewController.Log empid property.It will be having default value.Now log empid property of dash.It will be having correct value.So your instance is of no use here.
Solution
Set the empid property in prepareForSegue as answered by #balkaran singh or if you want to use your dash variable then embed a navigationController and push dash on it without calling performSegueWithIdentifier as suggested by #HImanshu Moradia in previous answers.

Related

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;
}

How can I use NSMutableArray in a detail ViewController?

I am stuck with a problem and can't find a decent solution. I am trying to add a name in parent ViewController and show them in a UITableView but to add a new name I go to a AddVC where I add a name via a UITextField and I want to add the name in the NSMutableArray from the parentVC.
Let me restate what I think you're asking: You have a ParentVC and you want to segue to a ChildVC that will present a UITextField to enter a name. Once the name is entered, you want to return the name back to the ParentVC. If this is correct then within your ChildVC prepareForSegue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// if you're using a nav controller (modal)
//UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
//ParentVC *destinationVC = (ParentVC *)navController.topViewController;
// if you're not using a nav controller (push)
ParentVC *destinationVC = (ParentVC *)segue.destinationViewController;
// assuming you have a public property in your ParentVC.h such as:
// #property (strong, nonatomic) NSString *theNewName;
destinationVC.theNewName = myAddNameTextField.text;
}
Take an NSMutableArray as a property in your AppDelegate . Always fetch the Array from AppDelegate. If you add something. Just add in this global mutable array. This way it won't matter where you add object in array and where from you fetch .

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

Get ViewController from Storyboard

I have two ViewControllers, which aren`t (directly) connected with a Segue. But I want to change a String in the second VC, which i get in the first one. My try was:
#import "secondViewController.h"
#interface firstViewController ()
#property NSString* originalString;
#end
#implementation firstViewController
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
secondViewController* svc = [secondViewController new];
svc.anotherString = self.originalString;
}
But it dosent work, because I've only created a instance of the second VC, so the value was not saved. Also I can`t use the Storyboard ID, because I use Xcode 5.
I have a menuVC from which you can get to the firstVC and the secondVC. And from the firstVC I can go back (with the navigationbackbarbutton) to the menu. so: menu->firstVC->menu. menu->secondVC->...->menu
My try with StoryboardID:
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
secondViewController* svc =[[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"secondVCSrorybradID"];
svc.anotherString = self.originalString;
}
you can pass the string to second view controller with this code.
secondViewController* svc =[self.storyboard instantiateViewControllerWithIdentifier:#"Your Second VC's Storyboad ID"];
svc.anotherString = self.originalString;
[self presentViewController:svc animated:YES completion:nil];
//you have to create anotherString property in second View Controller's .h File.
now you can get the string of originalString to second VC. Now you can get this value back second VC to first VC.
hope this helps you.
You should pass your data successively through your UIViewControllers navigation. If, for example, you have a navigation like FirstVC > SecondVC > ThirdVC :
In your FirstVC.m, use :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
((SecondVCClass*) segue.destinationViewController).secondVCString = _firstVCString;
}
With secondVCString being a #property in your second ViewController.
In your SecondVC.m, use :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
((ThirdVCClass*) segue.destinationViewController).thirdVCString = _secondVCString;
}
With of course thirdVCString being a #property in your third ViewController.
Edit:
As you updated your question, here is what I suggest :
In your MenuVC, add this :
#property (nonatomic, weak) NSString *importantString;
In your FirstVC and SecondVC, add this :
#property (nonatomic, weak) MenuVCClass *menu;
When you push to FirstVC or SecondVC, use prepareForSegue to set the destination's view controller menu property to your menu :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"FirstSegue"])
((FirstVC*) segue.destinationViewController).menu = self;
else if ([segue.identifier isEqualToString:#"SecondSegue"])
((SecondVC*) segue.destinationViewController).menu = self;
}
In FirstVC or SecondVC, you can change the NSString value from your menu using _menu.importantString = #"";
You should never use new to create a view controller.
If you're using storyboards but not using segues, you can still create a view controller from the storyboard and invoke it.
Use the method instantiateViewControllerWithIdentifier: to create an instance of the target view controller. The set the properties you want to set, and finally make a call to display it (present it modally, push it onto the navigation stack, or whatever is appropriate for your program.)

IOS Segue not able to set label directly

I am having two view controllers 'FirstViewController' and 'SecondViewController'. From first view controller it will take input from a text field ,process it and display accordingly in the second view. But I am having a problem while setting label value directly.
#interface SecondViewController : UIViewController
{
NSString *numPlate;
IBOutlet UILabel *output;
};
#property(strong,nonatomic) NSString *numPlate;
#property(strong,nonatomic) IBOutlet UILabel *output;
#end
The main file for FirstViewController.m with prepare for segue is as
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"Change"])
{
SecondViewController *svc = (SecondViewController *)[segue destinationViewController];
svc.numPlate = input.text;
NumberPlate *numPlate=[[NumberPlate alloc]init];
[numPlate setPlate:input.text];
NSInteger flag=[numPlate checkValidity];
if(flag==0)
{
svc.output.text =#"Invalid License";
}
else
if([numPlate getArea]==NULL||[numPlate getRegOffice]==NULL)
{
svc.output.text =#"Data not found";
}
else
{
svc.output.text =#"VALID License";
}
}
}
But when the action is performed its not working.The label is not changing.
When i used svc.numPlate instead of svc.output.text and in the SecondViewController viewDidLoad method and i used
- (void)viewDidLoad
{
[super viewDidLoad];
output.text=numPlate;
}
Everything is fine with this. Whats wrong in first method??
You will not be able to assign value directly to UILabel of second VC as view is not yet loaded into view hierarchy at this point.
So view cannot render the value assigned prior to it.
On the other hand, holding value in NSString and assigning same on viewDidLoad is working as now your view is in view hierarchy and loaded into memory.
At the time when you push SecondViewController, the SecondViewController's view hasn't been loaded yet, so you can't access its views. You need to create NSString properties in SecondViewController and pass a string to SecondViewController' NSString Object. Then in SecondViewController's viewDidLoad method, use those properties to populate the labels (which will have been loaded by the time viewDidLoad runs).
The initialisation of controller is different and presentation of its view is different process even if the viewController has been initialise its view will not because pushing the controller has not performed and controller dont know he need to load the view.. so we pass the data to controller and it load when view appears... like below code
#interface SecondViewController : UIViewController{
NSString *strMessage;
}
#property(nonatomic,retain) NSString *strMessage;
#end
SecondViewController.m
#synthesize strMessage;
- (void)viewDidLoad {
Nslog(#"%#",strMessage);
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"Change"])
{
SecondViewController *svc = (SecondViewController *)[segue destinationViewController];
NSString *message = [NSString stringWithFormat:#"Check out %#", nameLb.text];
svc.strMessage=message;
}

Resources