I have a simple app which connects to a web server and the web server returns a JSON value.
I am trying to send the JSON value from ViewController1 to "linkController", however when I send the sender over to ViewController2 the sender value is null?
Here is my code:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"linkControllerSegue"]) {
linkController *lc = [segue destinationViewController];
lc.introString = sender;
}
}
This is part of my linkController.h file:
#interface linkController : UIViewController
{
// succes view outlets
IBOutlet UILabel *short_url;
IBOutlet UILabel *full_url;
UIDataDetectorTypes *json;
}
#property (weak, nonatomic) NSDictionary *introString;
And my linkController.m file:
#synthesize introString;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#", introString);
}
The segue is being called through the code:
[self performSegueWithIdentifier:#"linkControllerSegue" sender:nil];
The NSLog in the viewDidLoad method returns: (null).
Is there anything I am doing wrong?
Many Thanks,
Peter
Try:
lc.introString = short_url.text;
instead of:
lc.introString = sender;
Related
I have a UIViewController several segues deep that when the use is finished, should unwind and take them back to the DashboardViewController.
I created the unwindToDashboard method in the Dashboard and hooked a button up to the Exit in my FinishViewController. So that when its clicked will fire the unwind action.
That works fine.
But I need to pass back data to the Dashboard from the FinishViewController.
So I created a delegate ProcessDataDelegate for the FinishViewController and made the Dashboard conform to it.
However, the delegate method in the Dashboard is NOT called.
Can anyone tell me what I have done wrong?
DashboardViewController.m
#import "FinishViewController.h"
#interface DashboardViewController () <ProcessDataDelegate>{
FinishViewController *fm;
}
#end
#implementation DashboardViewController
- (void)viewDidLoad {
[super viewDidLoad];
if(!fm){
fm = [[FinishViewController alloc] init];
}
fm.delegate = self;
}
- (IBAction)unwindToDashboard:(UIStoryboardSegue *)unwindSegue {
//empty
}
#pragma mark PROTOCOL METHODS
-(void) didFinishWithResults:(NSDictionary*) dictionary{
NSLog(#"Dashboard method called didFinishWithResults");
}
#end
FinishViewController.h
#class FinishViewController;
#protocol ProcessDataDelegate <NSObject>
#required
- (void) didFinishWithResults: (NSDictionary*)dictionary;
#end
#interface FinishViewController : UIViewController
#property (nonatomic, weak) id <ProcessDataDelegate> delegate;
#end
FinishViewController.m
#interface FinishViewController ()
#end
#implementation FinishViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"fired via the button to the exit--- Segue: %#", [segue identifier]);
[delegate didFinishWithResults:nil ];
}
#end
You need pass your delegate in prepareForSegue method of your DashboardViewController, there get the destinationViewController and cast to FinishViewController if the identifier is equal to your expected segue identifier
Something like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"fired via the button to the exit--- Segue: %#", [segue identifier]);
if([[segue identifier] isEqualToString:#"YourSegueIdentifier"])
{
((FinishViewController*)[segue destinationViewController]).delegate = self
}
}
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SecondViewController *svc=[segue destinationViewController];
if ([segue.identifier isEqualToString:#"show"]) {
svc.scrool=#"dict";
}
}
- (IBAction)buttonAction:(id)sender {
dict= #{#"firstname":#"firstname.textfield.text", #"lastname":#"lastname.textfield.text", #"fullname":#"fullname.textfield.text",#"gender":#"gender.textfield.text",#"country":#"country.textfield.text",#"state":#"state.textfield.text",#"phnumber":#"phnumber.textfield.text",#"email":#"email.textfield.text",#"zipcode":#"zipcode.textfield.text",#"landnumber":#"landnumber.textfield.text"};
}
can u please anyone give me answer for these need to send these dictionary to another view controller using segues
make this change:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SecondViewController *svc=[segue destinationViewController];
if ([segue.identifier isEqualToString:#"show"]) {
svc.scrool = dict;
}
}
In your code you are passing a string with the value of "dict", and not your dict variable.
Edit:
I also want to add that in this code:
dict= #{#"firstname":#"firstname.textfield.text", #"lastname":#"lastname.textfield.text", #"fullname":#"fullname.textfield.text",#"gender":#"gender.textfield.text",#"country":#"country.textfield.text",#"state":#"state.textfield.text",#"phnumber":#"phnumber.textfield.text",#"email":#"email.textfield.text",#"zipcode":#"zipcode.textfield.text",#"landnumber":#"landnumber.textfield.text"};
You are not actually pulling the values from your textfields. Given that you have all of these properties set correctly, you would need to use:
dict= #{#"firstname": firstname.textfield.text, #"lastname": lastname.textfield.text, #"fullname": fullname.textfield.text, #"gender": gender.textfield.text, #"country": country.textfield.text, #"state": state.textfield.text, #"phnumber": phnumber.textfield.text, #"email": email.textfield.text, #"zipcode": zipcode.textfield.text, #"landnumber": landnumber.textfield.text};
Also make sure you have the scrool property in your SecondViewController's .h file:
#property (strong, nonatomic) NSDictionary *scrool;
Wow it has been a while since I have written Obj-c code lol
Try this
- (IBAction) buttonAction:(id)sender
{
[self performSegueWithIdentifier:#"show" sender:sender];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SecondViewController *svc=[segue destinationViewController];
if ([segue.identifier isEqualToString:#"show"]) {
svc.scrool=#"dict";
svc.dict = #{#"firstname":#"firstname.textfield.text", #"lastname":#"lastname.textfield.text", #"fullname":#"fullname.textfield.text",#"gender":#"gender.textfield.text",#"country":#"country.textfield.text",#"state":#"state.textfield.text",#"phnumber":#"phnumber.textfield.text",#"email":#"email.textfield.text",#"zipcode":#"zipcode.textfield.text",#"landnumber":#"landnumber.textfield.text"};
}
}
First import another ViewController in current ViewController.
#import "secViewController.h"
Now set the data another view data when prepare for degue method is called.
ViewController.m file
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
secViewController *dest = [segue destinationViewController];
dest.data = #"test data";
}
Here declare NSString *data as globally in destination ViewController.
secViewController.h
#property NSString *data;
Which one Data receive that print in viewDidLoad() Method.
secViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#",self.data);
}
I know this question has been asked, but I have read the responses, adopted the fixes and still have an issue somewhere which I can't identify.
I have an IOS app which is similar in nature to email. It has an InboxVC which is a tableVC with a custom prototype cell which upon selection triggers a messageDetailVC.
The issue is that the messageDetailVC is triggered but the values are not being passed to it. I added log messages to evaluate the value in code before getting to Storyboard issues, and the variable being passed (messageID) has a NULL value.
Can someone tell me what I am missing or doing wrong? My code is:
InboxVC.m (snippet)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"%#: Message touched...", LOG_TAG);
messageDetail *mdvc = [[messageDetail alloc] init];
mdvc.messageID = #"123456789-1";
[self.navigationController pushViewController:mdvc animated:YES];
NSLog(#"%#: messageID value is = %#",LOG_TAG,mdvc.messageID);
//messageID has valid value here
}
messageDetail.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface messageDetail : UIViewController
{
NSString *messageID;
}
#property (strong, nonatomic) NSString *messageID;
#property (strong, nonatomic) IBOutlet UITextView *body;
messageDetail.m
#import <Foundation/Foundation.h>
#import "messageDetail.h"
static NSString * LOG_TAG = #"messageDetailController";
#implementation messageDetail
#synthesize messageID;
#synthesize body;
- (void)viewDidLoad {
[super viewDidLoad];
body.text = messageID;
//debug messages
NSLog(#"%#:Added messageID as Body text", LOG_TAG);
NSLog(#"%#:Value of body.text is = %#", LOG_TAG, body.text);
NSLog(#"%#:Value of messageID is = %#", LOG_TAG, messageID);
//messageID has null value here
}
- (void) viewWillAppear:(BOOL)animated {
[self.navigationController setNavigationBarHidden:NO];
}
MainStoryboard:
I have a messageDetail view tied to the messageDetail sub class of UIViewController. There is a segue with identifier "s_msgDetail" from the prototype cell's selection event to the messageDetailVC (show). As I said above the messageDetailVC appears, just not with the body.text being set to the value of "messageID".
You are setting the messageID on the wrong instance of your messageDetail view controller. Since you are using storyboards, the storyboard is already creating and presenting an instance of messageDetail for you. But, in tableView:didSelectRowAtIndexPath: you are creating a second one and presenting it. (I'm surprised you're not getting a bunch of runtime animation warnings when doing that.)
You should be setting messageID in prepareForSegue:sender: like this:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"s_msgDetail"]) {
messageDetail * vc = (messageDetail *) segue.destinationViewController;
NSIndexPath * indexPath = [self.tableView indexPathForSelectedRow];
vc.messageID = /* use indexPath to get data from messages collection */;
}
}
You have to use prepareForSegue to pass value to another view Controller
I have this Segue here:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
//NSDate *object = self.objects[indexPath.row];
NSString *strPOIndex = [self.tableData[indexPath.row] valueForKey:#"POIndex"];
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] topViewController];
[controller setDetailItem:strPOIndex];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
}
}
and what I am trying to do with it is pass strPOIndex to setDetailItem in my detail controller from my master controller.. but when I run this, I get an error:
-[LHPurchaseOrderMaster setDetailItem:]: unrecognized selector sent to instance 0x156cce80
I dont understand why this is happening, is it an issue with my storyboard? or my master controller or detail controller? Here is my Detail Controller:
.h:
#import <UIKit/UIKit.h>
#interface LHPurchaseOrderDetail : UIViewController
#property (strong, nonatomic) IBOutlet UINavigationBar *NavBar;
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
.m:
#import "LHPurchaseOrderDetail.h"
#interface LHPurchaseOrderDetail ()
#end
#implementation LHPurchaseOrderDetail
- (void)setDetailItem:(id)newDetailItem {
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView {
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self configureView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
Master Controller:
.h
#import <UIKit/UIKit.h>
#import "ShinobiDataSource.h"
#import "PopupGenerator.h"
#class LHPurchaseOrderDetail;
#interface LHPurchaseOrderMaster : UITableViewController<UIPopoverControllerDelegate, UIPickerViewDelegate>
#property (strong, nonatomic) IBOutlet UIButton *communityBtn;
#property (strong, nonatomic) IBOutlet UIButton *lotBtn;
#property (strong, nonatomic) IBOutlet UIButton *goBtn;
- (IBAction)communityBtnPressed:(id)sender;
- (IBAction)lotBtnPressed:(id)sender;
- (IBAction)goBtnPressed:(id)sender;
#property(nonatomic, retain) NSArray * tableData;
#property (strong, nonatomic) LHPurchaseOrderDetail *purchaseOrderController;
#end
Your error is this:
-[LHPurchaseOrderMaster setDetailItem:]: unrecognized selector sent to instance 0x156cce80
so it seems that somewhere in your LHPurchaseOrderMaster class you're trying to access and set the detailItem property as if it would be a part of LHPurchaseOrderMaster but because it doesn't exist there, you get an unrecognized selector error.
Edit
You should check for three things:
In Interface Builder check that the segue from LHPurchaseOrderMaster ViewController is to an UINavigationController that embeds the LHPurchaseOrderDetail ViewController as the first view controller in its stack.
Check the Class name returned by [segue destinationViewController]topViewController] like this:
id obj = [segue destinationViewController]topViewController];
NSLog(#"%#", NSStringFromClass([obj class]));
The class name should be LHPurchaseOrderDetail. If it's not, then you have a problem in your Storyboard where more than certainly you've connected the segue wrong.
Check your LHPurchaseOrderMaster class for any code that tries to access the "detailItem" property as if it would be part of this class.
It seems that the property you are trying to access is not accessible (wrong retrieved object).
Have you tried to use instead of
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] topViewController];
Something like
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] viewControllers][0];
I had sometimes the same your issue.
Set your detailItem not to NSString. Not to id. The problem is here,
self.detailDescriptionLabel.text = [self.detailItem description];
In configureView method change the code as follow,
- (void)configureView {
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = self.detailItem;
}
}
Don't forget to change this as well,
- (void)setDetailItem:(NSString *)newDetailItem {
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
I'm very new to iOS development and I know there have been questions like this asked, but I can't seem to pull out of those examples what I think I need.
I'm trying to teach this to myself by coding a very simple mortgage calculator. I have two views, MortgageCalculatorViewController where the user enters the loan value, term and interest; and the ResultsViewController where this information is redisplayed, with the monthly payment, in labels. My current issue is I can't seem to figure out how to relay the calculated monthly payment value to the ResultsViewController.
I named the segue showResultsSegue.
In MortgageCalculatorViewController:
#import "MortgageCalculatorViewController.h"
#import "ResultsViewController.h"
#interface MortgageCalculatorViewController ()
#end
#implementation MortgageCalculatorViewController
NSString *paymentText;
-(IBAction)calculateMonthlyPayment
{
float rate = (self.interestRate.text.floatValue / 12) / 100;
long term = self.termInYears.text.integerValue;
float principle = self.loanAmount.text.floatValue;
float termedRate = pow((1 + rate), term);
float payment;
payment = (principle * rate * termedRate) / (termedRate - 1);
paymentText = [NSString stringWithFormat:#"%f", payment];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showResultsSegue"]){
ResultsViewController *controller = (ResultsViewController *)segue.destinationViewController;
controller.paymentLabel.text = paymentText;
}
}
#end
And in ResultsViewController:
#interface ResultsViewController : UIViewController
#property (nonatomic) IBOutlet UILabel *loanAmountLabel;
#property (nonatomic) IBOutlet UILabel *termInYearsLabel;
#property (nonatomic) IBOutlet UILabel *interestRateLabel;
#property (nonatomic) IBOutlet UILabel *paymentLabel;
-(IBAction)close;
#end
I've guided this approach on the information I found in Passing Data between View Controllers, but I'm still seeing no change after the segue.
Any help would be appreciated. Thanks.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showResultsSegue"]){
ResultsViewController *controller = (ResultsViewController *)segue.destinationViewController;
controller.paymentLabel.text = paymentText;
}
}
When preparing for a segue, the view has probably not been loaded, so paymentLabel is nil. Instead, declare a paymentText property on ResultsViewController and assign that value to paymentLabel in viewDidLoad.
New prepareForSegue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showResultsSegue"]){
ResultsViewController *controller = (ResultsViewController *)segue.destinationViewController;
controller.paymentText = paymentText;
}
}
Implementation for ResultsViewController:
#interface ResultsViewController : UIViewController
#property(copy, nonatomic) NSString *paymentText;
#end
#implementation ResultsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.paymentLabel.text = self.paymentText;
}
#end
It's likely that your ResultsViewController has not initialized it's view elements, including the paymentLabel yet. Try explicitly calling view before setting the label text like so:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showResultsSegue"]){
ResultsViewController *controller = (ResultsViewController *)segue.destinationViewController;
[controller view];
controller.paymentLabel.text = paymentText;
}
}
Calling view will cause the view controller to load it's view elements, hence letting you set the label's text properly.
By far the easiest why to do this without using delegates, singletons or as mentioned above using the prepareForSegue, is using NSUserDefaults.
Save string:
[[NSUserDefaults standardUserDefaults] setObject:paymentText forKey:#"payment"];
[[NSUserDefaults standardUserDefaults]synchronize];
Read string:
NSString *readPaymentString = [[NSUserDefaults standardUserDefaults] stringForKey:#"payment"];
What you basically need to do here is to use the save code I provided in one view and the read code in the second view, simple.
I hope it makes sense.