How to pass data between view controller in objective-c? - ios

The select item is a slider. When I click the slider It will pass the data to Second VC (WebViewController). but how to pass data from first view controller to second view controller in objective-c? Sorry, This is my first time coding objective C.
First VC .m file
#import "WebViewController.h"
- (void)viewDidLoad {
[super viewDidLoad];
arraySliderProducts = [[NSMutableArray alloc]init];
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
UIViewController *controller = nil;
switch (indexPath.row)
{
case 0:
{
WebViewController *WebViewController = [[WebViewController alloc] init];
//error: No visible #interface for "WebViewController" declares the selector 'alloc'
WebViewController.data = arraySliderProducts[indexPath.row][#"title"]; //pass this link value
//error: Property 'data' not found on object of type 'WebViewController'
[self.navigationController pushViewController: WebViewController animated:YES];
}..
Second VC .m file
#interface WebViewController ()
#property (nonatomic, retain) NSString *data;
Second VC .h file
#import <UIKit/UIKit.h>
#interface WebViewController : UIViewController
{
AppDelegate *appDelegate;
NSString *data;
}
#end

Two points to note:
1: This is not the way to initiate a view controller to show/present in your app.
2: You should declare your NSString *data in your SecondVC's .h file.
Now point 1 solutions is to change your code with below in your didSelectItemAtIndexPath: function
switch (indexPath.row)
{
case 0:
{
// By Default storyboard name is "Main". Change it if you you have different name in your project
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
// Now instantiate your view controller with its identifier on this storyboard object.
// Note: don't forget to set viewControllers' identifier
WebViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier: #"WebViewController"];
// Now Pass your value
WebViewController.data = arraySliderProducts[indexPath.row][#"title"];
//Finally push this object on your navigation stack
[self.navigationController pushViewController: WebViewController animated:YES];
}...
}

try as
//Your class and obj name is same so You are getting this type of error
WebViewController *VC = [[WebViewController alloc] init];
//OR
WebViewController *VC= [self.storyboard instantiateViewControllerWithIdentifier:#"WebViewController"];
VC.data = arraySliderProducts[indexPath.row][#"title"];
[self.navigationController pushViewController: VC animated:YES];

Related

Pass NSString value to another ViewController in Objective C

I am trying to pass NSString value to another ViewController. But I get null instead of the value. Here is my code.
FirstViewController.m:
NSString cellID = #"66";
SecondViewController *apiViewController = [[SecondViewController alloc] init];
apiViewController.strMessage=cellID;
[self.navigationController pushViewController:apiViewController animated:YES];
SecondViewController.h:
#interface SecondViewController : UIViewController{
NSString *strMessage;
}
#property(nonatomic,retain) NSString *strMessage;
#end
SecondViewController.m:
#implementation SecondViewController
#synthesize strMessage;
NSLog(#"%#", strMessage);
#end
I did import. I assigned variable before pushing. But it anyway returns null. How can I do this? Any tips, ideas. Thank you.
Try assigning the property before you push the view controller.
NSString cellID = #"66";
LineChartViewController *apiViewController = [[LineChartViewController alloc] init];
apiViewController.strMessage=cellID;
[self.navigationController pushViewController:apiViewController animated:YES];
Furthermore, you need to call the NSLog from within a function in your implementation. The viewDidLoad function, for example, as this is a UIViewController that is being pushed on a UINavigationController stack.
try this code
SecondViewController *apiViewController = [[SecondViewController alloc] init];
apiViewController.strMessage=cellID;
[self.navigationController pushViewController:apiViewController animated:YES];
Try this
SecondViewController *apiViewController = [[SecondViewController alloc] init];
apiViewController.strMessage=cellID;
[self.navigationController pushViewController:apiViewController animated:YES];
And Print
NSLog(#"%#", self.strMessage);

Destination value is null when sending value using "performSegueWithIdentifier"

I have three navigation buttons in a view controller, two of which I process locally and one which launches an edit view controller. I have created a segue from the body of the first UITableView to the Navigation Controller of the destination view controller (the edit view controller).
The button works fine (i.e. launches the edit view) but it doesn't receive the string I send to it. Could someone please help. I have tried all of the suggestions given to other related questions but cannot seem to fix this. Following is the related code.
Source controller.h:
#import <UIKit/UIKit.h>
#import "EQHorseAddViewController.h"
#import "EQDatabase.h"
#interface EQHorseDetailViewController : UITableViewController
#property (strong, nonatomic) EQHorseAddViewController *addViewController;
Source controller.m:
#import "EQHorseDetailViewController.h"
#interface EQHorseDetailViewController ()
#end
#implementation EQHorseDetailViewController
#synthesize addViewController;
-(void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *deleteItem= [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemTrash
target:self
action:#selector(deleteHorse:)];
UIBarButtonItem *editItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self
action:#selector(editHorse:)];
NSArray *actionButtonItems = [[NSArray alloc] initWithObjects:deleteItem, editItem,
nil];
self.navigationItem.rightBarButtonItems = actionButtonItems;
}
-(void)editHorse:(id)sender
{
NSLog(#"EditingHorse");
self.addViewController= [[EQHorseAddViewController alloc] init];
addViewController.resultSegue = #"Edit Horse Details";
[self performSegueWithIdentifier:#"EditHorseDetails" sender: self];
}
Destination View Controller.h:
#import <UIKit/UIKit.h>
#import "EQHorseDetailsInfo.h"
#import "EQDatabase.h"
#class EQHorseAddViewController;
#protocol EQHorseAddViewControllerDelegate <NSObject>
- (void) eqHorseAddViewControllerDidCancel:(EQHorseAddViewController *)controller;
- (void)eqHorseAddViewControllerDidSave: (EQHorseAddViewController *)controller;
#end
#interface EQHorseAddViewController : UITableViewController
<EQHorseAddViewControllerDelegate>
#property (strong, nonatomic) EQHorseAddViewController *addViewController;
#property (nonatomic, weak) id <EQHorseAddViewControllerDelegate> delegate;
#property (strong,nonatomic) NSString *resultSegue;
Destination View Controller.m
#import "EQHorseAddViewController.h"
#import "EQDatabase.h"
#import "EQHorseDetailsInfo.h"
#interface EQHorseAddViewController ()
#end
#implementation EQHorseAddViewController
#synthesize resultSegue;
- (void)viewDidLoad
{
NSLog(#"resultSegue %#",resultSegue);
}
Thanking you in advance.
It looks like you're referring to the code in editHorse:, which allocates an EQHorseAddViewController and sets a property on it. The problem with that code is that the view controller it allocates bears no relation to the vc destination of the segue. That method simply creates a vc and then instantly discards it.
Remove the allocation and instead implement prepareForSegue:. The segue object passed to that method will have a property called destinationViewController. That's the view controller that's about to be pushed onto the navigation. That's the one on which you should set the resultSegue property.
-(void)editHorse:(id)sender
{
NSLog(#"EditingHorse");
[self performSegueWithIdentifier:#"EditHorseDetails" sender: self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"EditHorseDetails"]) {
EQHorseAddViewController *vc = segue.destinationViewController;
vc.resultSegue = #"Edit Horse Details";
}
}
You need to define the new controller as follows:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
EQHorseAddViewController *ivc = [storyboard instantiateViewControllerWithIdentifier:#"EditHorseDetails"];
ivc.resultSegue = #"Edit Horse Details";
Perhaps you'll need this method too
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"EditHorseDetails"]) {
// Get destination view
EQHorseAddViewController *vc = [segue destinationViewController];
vc.resultSegue = #"Edit Horse Details";
}
}
-(void)editHorse:(id)sender
{
NSLog(#"EditingHorse");
resultSegue = #"Edit Horse Details";
[self performSegueWithIdentifier:#"EditHorseDetails" sender: self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UINavigationController *navigationController = segue.destinationViewController;
EQHorseAddViewController *addViewController = [navigationController viewControllers]
[0];
// Get destination view
NSLog(#"ResultSegue in Prepare - %#",resultSegue);
addViewController.resultSegue = #"Edit Horse Details";
}

Property nil when using delegate to pass data back to VC

I've got a view in a xib file that I load to my viewController - its a temp view and thus isn't on screen all the time. However the temp view and the main view, use the same view controller class as they both are doing the same job.
Now, in the xib view I load up a second viewControoler - lets call it viewControllerB - which is a UITableView with 197 cells. Once a cell is selected, the view is dismissed and the value of the cell is returned to viewControllerA.
viewControllerB is on the storyboard.
Here is the code I have used:
viewControllerB (The VC I need data back from)
Delegate Protocol:
#protocol CountrySelectedDelegate <NSObject>
-(void)selectedCountry: (id)countryReturned;
#end
#property (strong, nonatomic) id <CountrySelectedDelegate> myDelegate;
Then in the .m file:
Set the delegate:
ViewControllerA *viewA = [[ViewControllerA alloc]init];
self.myDelegate = viewA;
Then I call the delegate in the same file;
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[self myDelegate] selectedCountry:indexPath.row];
[self dismissViewControllerAnimated:YES completion:nil];
}
Now in viewControllerA:
pragma mark - CountrySelected Delegate
-(void)selectedCountry:(id)countryReturned
{
self.testInt = countryReturned;
}
Now this method does get called by the delegate. Looking in the console: countryReturned is the correct value. Once this method has finished, self.testInt is also the correct value.
Then, in my viewWillAppear method, I simply check the value again to see if its still the same with a NSLog print.
the value is always nil in the viewWillAppear method (Or anywhere else I check it) - I have tried with NSMutableString and NSString - always nil.
Why are my properties / instance variables getting set to nil?
Update:
This is how I show viewControllerB
- (IBAction)countrySelect:(UIButton *)sender
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
UITableViewController *vc = [sb instantiateViewControllerWithIdentifier:#"CountrySelection"];
vc.modalTransitionStyle = UINavigationControllerOperationPop;
[self presentViewController:vc animated:YES completion:NULL];
}
On ViewB do the below I guess you have already done
#protocol CountrySelectedDelegate <NSObject>
-(void)selectedCountry: (NSInteger)countryReturned;
#end
#property (week, nonatomic) id <CountrySelectedDelegate> myDelegate;
and in didSelectRowAtIndexPath
if ([[self myDelegate] respondsToSelector:#selector(selectedCountry:)])
{
[[self myDelegate] selectedCountry:indexPath.row];
}
On ViewA
Conform the protocol
#interface ViewA : UIViewController < CountrySelectedDelegate >
create the call ViewB
ViewB *viewBObjc=[[ViewB alloc] init];
[viewBObjc setMyDelegate:self];
[[self navigationController] presentViewController:ViewB animated:YES completion:Nil];
implement the delegate on ViewA
-(void)selectedCountry: (NSInteger)countryReturned
{
NSLog(#"Country Id is :%d", countryReturned);
}
Try this,
Set delegate by
//in ViewControllerB
self.myDelegate = [self parentViewController];
or
- (IBAction)countrySelect:(UIButton *)sender
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
ViewControllerB *vc = (ViewControllerB *)[sb instantiateViewControllerWithIdentifier:#"CountrySelection"];
vc.modalTransitionStyle = UINavigationControllerOperationPop;
vc. myDelegate = self;
[self presentViewController:vc animated:YES completion:NULL];
}

Set property of another UIViewController

In my DetailViewController.h I've declared the property * type as seen below:
#interface DetailViewController : UIViewController
#property (strong, nonatomic) NSString *type;
#end
Then I got a ListViewController which is a UIViewController containing a TableView.
The ListViewController.h looks like this:
#interface ListViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#end
In my ListViewController.m I want to change the value of * type a soon I switch the View (view switching is working fine).
I'm doing this by adding the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UINavigationController * navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailController"];
DetailViewController * detailController = [[DetailViewController alloc] init];
detailController.type = #"video";
NSLog(#"Type: %#", detailController.type);
[self.navigationController pushViewController:navigationController animated:YES];
}
When I put a breakpoint at the second line in this block/function I get detailController with in it * type.
When I NSLog this a few lines later it return "(null)".
The View is changed but but the type is not set.
I can't figure out what I'm doing wrong?
Someone who has a solution for this or can point me to something we're this is explained?
Because I tried searching for the answer but I couldn't find anything equivalent to my problem, or I used the wrong search terms..
in your didSelectRowAtIndexPath: method change the following lines`
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController * detailController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailController"];;
detailController.type = #"video";
NSLog(#"Type: %#", detailController.type);
[self.navigationController pushViewController: detailController animated:YES];
}`
in your storyboard select DetailViewController and give storyboard id as "DetailController". Make sure your ListViewController is embed in UINavigationController, you can do that by selecting ListViewController and go to editor->Embed in->Navigation Controller. Follow these steps and your problem will be solved.
OR you can give segue from your ListViewController to DetailViewController and use
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *path = [self.tableView indexPathForSelectedRow]; //create tableview outlet
[segue.destinationViewController setType:#"video"];
}
What is this for?
UINavigationController * navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailController"];
Why are you pushing a navigation controller inside a navigation controller?
[self.navigationController pushViewController:navigationController animated:YES];
detailController was not used or displayed.
Try this instead:
[self.navigationController pushViewController:detailController animated:YES];
Look at the last line - you are telling the nav controller to push itself!
It should be like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController * detailController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailController"];
detailController.type = #"video";
NSLog(#"Type: %#", detailController.type);
[self.navigationController pushViewController:detailController animated:YES];
}
Is the navigation controller and the alloc-init method both instantiates the save view controller??
If yes, try this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController * detailController = [[DetailViewController alloc] init];
detailController.type = #"video";
NSLog(#"Type: %#", detailController.type);
[self.navigationController pushViewController:detailController animated:YES];
}

Pass data between view controllers WITHOUT segues

I'm using storyboard and I have a view that loads dynamic buttons. On click of this button, I need to load the second view controller and also pass data. I cannot use segue as its dynamic button.
I use following code to load the second view controller
UIStoryboard* sb1 = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone"
bundle:nil];
UIViewController* vc1 = [sb1 instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:vc1 animated:YES];
In the 2nd view controller, I need to access about 5 fields from the 1st view controller. How do I pass the data?
You can create a Segue not bounded to a button by ctrl+drag from the first controller to the second one (don't forget to give this segue and identifier).
Next In the IBAction of the button (set via Interface Builder or via addTarget:self action:forControlEvents: ) you can call the [self performSegueWithIdentifier:#"YourSegueIdentifier" sender:button];
You can pass the data to the second controller, as usual, in - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Try something like that:
Class A
// CLASS_A.h
#import <UIKit/UIKit.h>
#interface CLASS_A : UIViewController {
...
}
- (IBAction)Btn_PushPressed:(id)sender;
...
#end
// CLASS_A.m
#import "CLASS_A.h"
#import "CLASS_B.h"
#implementation CLASS_A
- (IBAction)Btn_PushPressed:(id)sender
{
UIStoryboard* sb1 = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone"
bundle:nil];
CLASS_B* vc1 = [sb1 instantiateViewControllerWithIdentifier:#"SecondViewController"];
vc1.delegate = self;
[self.navigationController pushViewController:vc1 animated:TRUE];
}
....
#end
Class B
// CLASS_B.h
#import <UIKit/UIKit.h>
#class CLASS_A;
#interface CLASS_B : UIViewController {
...
}
#property (weak, nonatomic) CLASS_A *delegate;
....
#end
// CLASS_B.m
#import "CLASS_B.h"
#import "CLASS_A.h"
#implementation CLASS_B
....
#end
This is how to do it in Swift 2.0. Instead of using prepareForSegue,
Swift 3.0
let someViewConroller = self.storyboard?.instantiateViewController(withIdentifier: "SomeViewController") as! SomeViewController
someViewConroller.someObject = self.someObject!
self.navigationController?.pushViewController(someViewConroller, animated: true)
Swift 2.0
let someViewConroller = self.storyboard?.instantiateViewControllerWithIdentifier("SomeViewController") as! SomeViewController
someViewConroller.someObject = self.someObject!
self.navigationController?.pushViewController(someViewConroller, animated: true)
Swift 3
let destinationView = self.storyboard?.instantiateViewController(withIdentifier: "ID") as! ViewController2
destinationView.Value2 = Value1
self.present(destinationView, animated: true, completion: nil)
You can simply use
NSUserDefaults
to store the data and retrieve in what ever page you need
In view controller A
[[NSUserDefaults standardUserDefaults] setObject:aData forKey:#"DATA"];
[[NSUserDefaults standardUserDefaults] synchronize];
In destination Controller
NSData * aData = [[NSUserDefaults standardUserDefaults] valueForKey:#"DATA"];
firstly you can use segue even you have dynamic buttons, just add target method to UIButtons and push view controller using segue in that method. in the second view controller, take few properties and assign values to those properties before you push second view controller. like:
UIStoryboard* sb1 = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone"
bundle:nil];
UIViewController* vc2 = [sb1 instantiateViewControllerWithIdentifier:#"SecondViewController"];
[vc2 setName:#"name"];
[self.navigationController pushViewController:vc2 animated:YES];
before that you need to assign property to a NSString *name in SecondViewController
You can define a protocol: PassValueDelegate,and in the first viewController you can implement this protocol.
UIStoryboard* sb1 = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
UIViewController* vc1 = [sb1 instantiateViewControllerWithIdentifier:#"SecondViewController"];
//set the delegate for the second view controller,so you can access the values in the first controller
vc1.delegate = self;
[self.navigationController pushViewController:vc1 animated:YES];

Resources