segue data passing returns nil - objective-c

I need to pass a NSString to my other ViewController but it keeps returning nil.
//prepareForSegue is called from didSelectRowAtIndexPath
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"chat"]) {
NSString *userName = (NSString *) [toUsersArray objectAtIndex:[self.chatsTableView indexPathForSelectedRow].row];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ChatViewController *chatViewController = [storyboard instantiateViewControllerWithIdentifier:#"ChatViewController"];
//[chatViewController setChatWithUser:userName]; EVEN TRIED:
chatViewController.chatWithUser = username;
}
}
Here is where I declare the NSString:
#interface ChatViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, MessageDelegate> {
UITextField *messageField;
NSString *chatWithUser;
UITableView *chatTableView;
NSMutableArray *messagesArray;
}
#property (nonatomic,retain) IBOutlet UITextField *messageField;
#property (nonatomic,retain) NSString *chatWithUser;
#property (nonatomic,retain) IBOutlet UITableView *chatTableView;
- (IBAction) sendMessage;
#end
and here its still nil:
#synthesize chatWithUser;
- (void)viewDidLoad {
[super viewDidLoad];
//DO STUFF WITH chatWithUser; ADDED BREAKPOINT AND chatWithUser = nil;
//ALSO TRIED viewWillAppear;
}
What is the right way to pass data between these two View Controllers? My variables stay nil.

The problem is that you're instantiating a new ChatViewController, that's not the one that the segue is going to. You should get that controller from the segue's destinationViewController property.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"chat"]) {
NSString *userName = (NSString *) [toUsersArray objectAtIndex:[self.chatsTableView indexPathForSelectedRow].row];
ChatViewController *chatViewController = segue.destinationViewController;
chatViewController.chatWithUser = username;
}
}

// Get reference to the destination view controller
ChatViewController *ChatViewController = [segue destinationViewController];

Related

Objective-c: passing data from UITable to ViewController with prepareForSegue

this is my very first app and, basically, this part consists in passing data from a UItableView to a second View Controll. I managed to learn how to pass data from a simple NSarray (also in a UITable), but my goal is to pass values from a NSDictionary. Everything is set up, but I can't figure out how to write the PrepareForSegue method properly. The app runs, but the label on the "DetailView" stays empty. What I got so far:
#implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
_citySpots = #{#"Bars" : #[#"Hurricane", #"Black Swan", #"Texas"],
#"Clubs" : #[#"Electric Wizard", #"Offspring", #"The Tunnel"],
#"Restaurants" : #[#"Nando's", #"1/2 Burguer", #"Satellite"],
};
_sectionTitles = [[_citySpots allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
}
PrepareForSegue Method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"spotsDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
DetailViewController *destViewController = segue.destinationViewController;
NSString *sectionTitle = [_sectionTitles objectAtIndex:indexPath.section];
NSArray *citySpots = [_citySpots objectForKey:sectionTitle];
destViewController.receiver = [citySpots objectAtIndex:indexPath.row];
}
}
And the receiver(header):
#import <UIKit/UIKit.h>
#import "TableViewController.h"
#interface DetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *receiver;
#property (nonatomic, strong) NSString *spot;
#end
Main:
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
- (void)viewDidLoad {
[super viewDidLoad];
_receiver.text =_spot;
}
Can someone help me out? Thanks
Try to use setters:
[destViewController setReceiver:[citySpots objectAtIndex:indexPath.row]];
[destViewController setSpot:[citySpots objectAtIndex:indexPath.row]];

NSMutableArray is not mutable anymore after passing it to another viewController

I'm using NavigationController and in the MasterViewController I have a NSMutableArray called _emails, when I prepareForSegue I do this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SelectContactViewController *vc = [segue destinationViewController];
vc.delegate = self;
vc.emails = _emails;
}
in SelectContactViewController _emails is correctly filled with datas from MasterViewController _emails property, But it is no more Mutable! I can't add/remove object. Here is definition of _emails in SelectContactsViewController:
#import "MasterViewController.h"
#protocol MyViewDelegate;
#interface SelectContactViewController : UITableViewController {
id<MyViewDelegate> delegate;
}
#property (strong, nonatomic) NSMutableArray* emails;
and definition of _emails in MasterViewController:
#interface MasterViewController () {
NSMutableArray *_emails;
}
How can I pass a MutableArray to another view and still be a MutableArray??
Just change the below lines
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SelectContactViewController *vc = [segue destinationViewController];
vc.delegate = self;
vc.emails = _emails;
}
To the below lines
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SelectContactViewController *vc = [segue destinationViewController];
vc.delegate = self;
vc.emails = [_emails mutableCopy];
}

Call method from another view, I think?

I have a simple utility app, with a MainViewController.m & h and a FlipsideViewController.m & h. Within my storyboard I have a button on MainViewController. I want to be able to click the button and run a method in FlipsideViewController.m is this possible? this is my first app and I am a total novice. all comments / suggestion welcome.
enter code here
i have this in my FlipsideViewController.m this is what i want to call when i click the button.
- (void)SaveFPQData
{
NSLog(#"Data Saved");
}
and this is what i have in MainViewController.m
- (IBAction)saveButton:(id)sender
{
}
This is the code I have so far;
MainViewController.h
#import "FlipsideViewController.h"
#import "sqlite3.h"
#import "FPQCheck.h"
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate>
#property (weak, nonatomic) IBOutlet UITextField *nameField;
#property (weak, nonatomic) IBOutlet UITextField *checkField;
#property (weak, nonatomic) IBOutlet UITextField *commentsField;
#property (weak, nonatomic) FlipsideViewController *flipsidecontroller;
- (IBAction)saveButton:(id)sender;
- (IBAction)showHistoryButton:(id)sender;
#end
MainViewController.m
#import "MainViewController.h"
#import "FlipsideViewController.h"
#import "sqlite3.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (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.
}
#pragma mark - Flipside View
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showAlternate"]) {
[[segue destinationViewController] setDelegate:self];
}
}
- (IBAction)saveButton:(id)sender
{
[self.flipsidecontroller SaveFPQData];
//[[NSNotificationCenter defaultCenter] postNotificationName:#"SaveFPQData" object:nil];
}
- (IBAction)showHistoryButton:(id)sender
{
}
#end
FlipSideViewController.h
#import <UIKit/UIKit.h>
#import "FPQCheck.h"
#class FlipsideViewController;
#protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface FlipsideViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *myTableView;
#property (weak, nonatomic) id <FlipsideViewControllerDelegate> delegate;
-(void)SaveFPQData;
- (IBAction)done:(id)sender;
- (IBAction)deleteEntry:(id)sender;
#end
FlipSideViewController.m
#import "FlipsideViewController.h"
#import "MainViewController.h"
#interface FlipsideViewController ()
{
NSMutableArray *arrayOfCheck;
sqlite3 *fpqDB;
NSString *dbPathString;
}
#end
#implementation FlipsideViewController
- (void)viewDidLoad
{
/*
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(SaveFPQData)
name:#"SaveFPQData"
object:nil];
*/
[super viewDidLoad];
arrayOfCheck = [[NSMutableArray alloc]init];
[self creatOrOpenDB];
[[self myTableView]setDelegate:self];
[[self myTableView]setDataSource:self];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)SaveFPQData
{
NSLog(#"Data Saved");
}
-(void)creatOrOpenDB
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *docPath = [path objectAtIndex:0];
dbPathString = [docPath stringByAppendingPathComponent:#"FPQ.db"];
char *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:dbPathString]) {
const char *dbPath = [dbPathString UTF8String];
//create db
if (sqlite3_open(dbPath, &fpqDB)==SQLITE_OK) {
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS FPQ (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, CHECK INTEGER, COMMENTS TEXT)";
sqlite3_exec(fpqDB, sql_stmt, NULL, NULL, &error);
sqlite3_close(fpqDB);
}
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Actions
- (IBAction)done:(id)sender
{
[self.delegate flipsideViewControllerDidFinish:self];}
- (IBAction)deleteEntry:(id)sender {
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrayOfCheck count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
FPQCheck *fpqCheck = [arrayOfCheck objectAtIndex:indexPath.row];
NSString *nameANDcheck = [NSString stringWithFormat:#"%#%d", fpqCheck.name, fpqCheck.check];
cell.textLabel.text = nameANDcheck;
cell.detailTextLabel.text = fpqCheck.comments;
return cell;
}
#end
You have mainly two ways:
add a property (eg. self.flipSideController) to your MainViewController to store a reference to the FlipsideViewController; then call SaveFPQData though it (eg. [self.flipSideController SaveFPQData]; or
use notification center to post a notification from saveButton: that triggers SaveFPQData; this would go like this:
//-- in flipsidecontroller `viewDidLoad`:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(SaveFPQData)
name:#"SaveFPQData"
object:nil];
//-- in saveButton:
[[NSNotificationCenter defaultCenter] postNotificationName:#"SaveFPQData" object:nil];
The second method is the simplest to implement, IMO, and it allows for the loosest coupling, at the expense of some clock cycles.
EDIT:
It is not entirely clear to me what you are trying to do (specifically, I don't understand fully how you can push the button in MainViewController once you FlipsideViewController is displayed; on the other hand, if you do not segue to the FlipsideViewController, then it is not there, so you cannot send a message to it), anyway you could try and initialise your self.flipsideViewController property in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showAlternate"]) {
UIViewController* controller = [segue destinationViewController];
[controller setDelegate:self];
if ([controller isKindOfClass:[FlipsideViewController class]])
self.flipsideViewController = (id)controller;
}
}
after doing that, your MainViewController will be able to send the saveFPQ message to the FlipsideViewController.
If you mean you would like to send the saveFPQ message before segue-ing to the FlipsideViewController, you should make the saveButton segue to it and the call the saveFPQ method.
What I suspect is you need some kind of "model" object accessible both from the main view and the flipside view controller.
Hope this helps.

webview after checking user input

I'm a xcode noob, but here's what I'm looking for followed by what I've done. I've created a login and with that login usernameField I'm trying verify the user and open a only a web page specific to that person. The login is working here's all my code
//LoginViewController.h
#import <UIKit/UIKit.h>
#interface LoginViewController : UIViewController
{
IBOutlet UITextField *usernameField;
IBOutlet UITextField *passwordField;
IBOutlet UIButton *loginButton;
IBOutlet UIActivityIndicatorView *loginIndicator;
}
#property(nonatomic, strong) UITextField *usernameField;
#property(nonatomic, strong) UITextField *passwordField;
#property(nonatomic, strong) UIButton *loginButton;
#property(nonatomic, strong) UIActivityIndicatorView *loginIndicator;
-(IBAction) login: (id) sender;
#end
//LoginViewController.m
#import "LoginViewController.h"
#implementation LoginViewController
#synthesize usernameField, passwordField, loginButton, loginIndicator;
-(IBAction) login: (id) sender
{
if ([usernameField.text isEqualToString: #"userOne"] && [passwordField.text
isEqualToString: #"passwordOne"])
{
printf("Success")
//here is where I would like to pass usernameField.text to WebViews
}
else if (([usernameField.text isEqualToString: #"userTwo"] && [passwordField.text
isEqualToString: #"passwordTwo"])
{
printf("Success")
//here is where I would like to pass usernameField.text to WebViews
}
else
{
printf("Login Failed")
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Login Failed"
message:#"Wrong username and password" delegate:self
cancelButtonTitle:#"Done"
otherButtonTitles:nil];
[alert show];
}
loginIndicator.hidden=False;
[loginIndicator startAnimating];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"fromLogin"])
{
WebViews *wvc = [segue destinationViewController];
wvc.usernamerField = self.usernameField.text;
}
}
#end
//WebViews.h
#interface WebViews : UIViewController
{
IBOutlet UIWebView *webView;
NSString *usernameField;
}
#property (nonatomic, strong) NSString*usernameField;
#end
//WebViews.m
#import "WebViews.h"
#interface WebViews ()//To be honest I'm not sure what this is for
#end
#implementation WebViews
#synthesize usernameField;
-(void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"username is = %#", self.usernameField);
if([T.usernameField.text isEqualToString: #"userOne"])
{
[webView loadRequest: [NSURLRequest requestWithURL: [NSURL
URLWithString:#"http://www.google.com"]]];
}
else if([T.usernameField.text isEqualToString: #"userTwo"])
{
[webView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString:#"http://www.yahoo.com"]]];
}
else
{
[webView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString:#"http://www.wikipedia.com"]]];
}
#end
Any help is greatly appreciated
Your problem is that you are never assigning anything to T so it is nil in your method.
In the code for your LoginViewController you need to pass the username to the WebViewController. You can do this by implementing the prepareForSegue method.
Here is an example, taken from How to pass prepareForSegue: an object
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
WebViewController *wvc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
wvc.username = self.usernameField.text;
}
}

delegate gets null when performWithSegue

Im trying to send some info from a modal view to a delgate. But it seems like my delegate doesnt follow through, it gets null. It looks like this in IB http://i.imgur.com/7oaxb.png.
But it works if i remove the navigationController that is right before the modal view and use the buttons in the View.
please help, ive tried for like 5 hours... :/
Heres the modalViewController code:
#import
#import "Link.h"
#protocol modalViewDelegate <NSObject>
-(void)closeview;
-(void)saveLink:(Link *)link;
#end
#interface modelViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *titel;
#property (weak, nonatomic) IBOutlet UITextField *url;
#property (nonatomic, weak) id <modalViewDelegate> delegate;
- (IBAction)exitModal:(id)sender;
- (IBAction)saveLink:(id)sender;
#end
and .m:
#import "modelViewController.h"
#interface modelViewController ()
#end
#implementation modelViewController
#synthesize titel;
#synthesize url, delegate;
- (IBAction)exitModal:(id)sender {
//[self.delegate closeview];
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)saveLink:(id)sender {
if (titel.text.length > 0 && url.text.length > 0) {
NSString *urlen = [NSString stringWithFormat:#"%#", url.text];
Link *linken = [[Link alloc] initWithURL:[NSURL URLWithString:urlen]];
linken.title = titel.text;
NSLog(#"%#", delegate); **//returns null when pressing button** it returns null if i put it in viewDidLoad to..
[self.delegate saveLink:linken];
[self dismissModalViewControllerAnimated:YES];
} else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:#"warning" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alertView show];
}
}
#end
the MasterViewController .h (that pushes the modalview:
#import <UIKit/UIKit.h>
#import "modelViewController.h"
#class DetailViewController;
#interface MasterViewController : UITableViewController <modalViewDelegate>
....
and .m
#import "MasterViewController.h"
#import "DetailViewController.h"
#implementation MasterViewController
#synthesize detailViewController = _detailViewController;
#synthesize links;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"linkPush"]) {
// Skicka länken till detaljvyn
DetailViewController *detailVC = segue.destinationViewController;
detailVC.link = [self.links objectAtIndex:self.tableView.indexPathForSelectedRow.row];
NSLog(#"%#", detailVC);
}
//this is the modalview "pusher"
if ([segue.identifier isEqualToString:#"newLink"]) {
modelViewController *mvc = segue.destinationViewController;
mvc.delegate = self;
NSLog(#"%#", mvc.delegate);
}
}
- (void)closeview {
[self dismissModalViewControllerAnimated:YES];
//[self.tabBarController dismissModalViewControllerAnimated:YES];
}
-(void)saveLink:(Link *)link{
NSLog(#"hello");
[links insertObject:link atIndex:links.count]; //updates a Tableview and works fine if delegate is called
[self.tableView reloadData];
//[self dismissModalViewControllerAnimated:YES];
}
If your destination view controller is wrapped into a navigation controller, you have to refer to it differently in prepareForSegue:
UINavigationController *nav = segue.destinationViewController;
DetailViewController *dvc = [nav.viewControllers objectAtIndex:0];
Now setting the properties, including the delegate, should work.