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

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

Related

segue data passing returns nil

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

how to delegate with an IBAction between two different UIViewController

I'm just trying to understand how delegate works and I'm in troubles.
I have two classes (both UIViewController) connected into the storyboard, the first one (ViewController.h/m) hold a TableView with cells and the second one (AddNameViewController.h/m) simply hold a TextField (where I want to write) and a button (Add Name)
as you surely understand I want the button pressed to send to the TableView what is written into the TextField, pretty simple.
And since I have two different Controllers and an Array containing the data holds by the tableview, I want to connect them with a delegate (just to learn it).
here is some code:
ViewController.h
#import "AddNameViewController.h"
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, AddNameViewControllerDelegate>
#property (strong, nonatomic) NSMutableArray *array;
#end
ViewController.m
#import "ViewController.h"
#import "AddNameViewController.h"
#inferface ViewController ()
#end
#implementation ViewController
#synthesize array;
-(void)addStringWithString:(NSString*)string
{
[self.array addObject:string];
NSLog(#"%#", array);
}
-(void)viewDidLoad
{
AddNameViewController *anvc = [[AddNameViewController alloc] init];
anvc.delegate = self;
array = [[NSMutableArray alloc] initWithObjects:#"first", #"second", nil];
NSLog(#"%#", array);
[super viewDidLoad];
}
-(NSInteger)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSindexPath*)indexPath
{
static NSString *simpleTableIdentifier = #"RecipeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [array objectAtIndex:indexPath.row];
return cell;
}
#end
AddNameViewController.h
#protocol AddNameViewControllerDelegate <NSObject>
-(void)addStringWithString:(NSString*)string;
#end
#interface AddNameViewController : UIViewController
#property (weak, nonatomic) id <AddNameViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UITextField *myTextField;
-(IBAction)add:(id)sender;
#end
finally the AddNameViewController.m
#import "ViewController.h"
#interface AddNameViewController ()
#end
#implementation AddNameViewController
#synthesize myTextField, delegate;
-(id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(IBAction)add:(id)sender
{
[self.delegate addStringWithString:self.myTextField.text];
// I've also tried with this but nothing --> [self.delegate addStringWithString:#"aa"];
}
#end
The array is initialized properly, no errors, no warnings, no crashes, simply seems like the method "addStringWithString" is not even called, because is not even NSLog anything.
obviously everything in connected in the storyboard, methods and outlets, thanks for your help.
in interface builder of AddNameViewController, did you connect the button event (Touch Up inside) into the action -(IBAction)add:(id)sender ?
also try this
-(IBAction)add:(id)sender
{
if([self.delegate respondsToSelector:#selector(addStringWithString:)]) {
[self.delegate addStringWithString:self.myTextField.text];
}
// I've also tried with this but nothing --> [self.delegate addStringWithString:#"aa"];
}

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.

No information is passed to the DetailView Objective-c

my problem - I want to pass information from the TableView in DetailView, but somewhere in the self.detailViewController.detailItem no value is passed.
that is:
self.detailViewController.detailItem =#"123";
NSString *sss = self.detailViewController.detailItem;
NSLog(#"%#", sss);
In NSLog output (null)
Here is my source code:
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController <UISplitViewControllerDelegate>
#property id detailItem;
#property id TitleOfDetail;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
- (void)configureView;
#end
#implementation DetailViewController
#pragma mark - Managing the detail item
-(void)setTitleOfDetail:(id)newTitleOfDetail {
NSLog(#"123");
if (_TitleOfDetail != newTitleOfDetail) {
_TitleOfDetail = newTitleOfDetail;
// Update the view.
[self configureView];
}
}
-(void)setDetailItem:(id)newDetailItem
{
NSLog(#"123");
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
self.title = self.TitleOfDetail;
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
NSLog(#"1%#", self.TitleOfDetail);
NSLog(#"2%#", [self.detailItem description]);
if (self.TitleOfDetail) {
self.title = self.TitleOfDetail;
}
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
…
myclass.h
#class DetailViewController;
#interface myclass : UITableViewController
#property DetailViewController *detailViewController;
#end
myclass.m
#import "choiseAvtoController.h"
#import "DetailViewController.h"
#interface myclass ()
#end
#implementation myclass
#synthesize detailViewController;
…
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.detailViewController.detailItem =#"123";
NSString *sss = self.detailViewController.detailItem;
NSLog(#"%#", sss);
}
In what may be the problem and how to fix it?
P.S. Sorry for my english, I'm just learning))
Since you are using a storyboard, you should be opening the detail controller on a segue.
Look up the segue identifier (say, it's OpenDetail) in the story board, then add the following code to your initial controller:
-(void)prepareForSegue:(UIStoryboardPopoverSegue*)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"OpenDetail"]) {
DetailViewController *dest = segue.destinationViewController;
dest.detailItem =#"123";
}
}

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.