In my application I have oneUITableViewController (Uctovatrida0TableViewController) and two otherUIViewContoller (DetailViewController and examples).
Now I have a problem because I do not know how to identify index (from indexPath.row) in my firstUIViewController to then correctly referred to another UIViewController.
The code in my Uctovatrida0TableViewController.m (works well):
-(void) showDetailsForIndexPath:(NSIndexPath*)indexPath
{
[self.searchBar resignFirstResponder];
DetailViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailsViewController"];
Ucty* ucet;
if(isFiltered)
{
ucet = [_filteredTableData objectAtIndex:indexPath.row];
}
else
{
ucet = [self.alldataArray objectAtIndex:indexPath.row];
}
vc.uctyItem = ucet;
[self.navigationController pushViewController:vc animated:true];
}
Code in my class DetailViewConroller where I need indexPath from Uctovatrida0TableViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"Priklad"])
{
Priklad *vc = [segue destinationViewController];
Ucty* ucet;
//of course this does not work
ucet = [self.alldataArray objectAtIndex:NSIndexPath.row];
vc.uctyItem = ucet;
[self.navigationController pushViewController:vc animated:true];
}
}
Code in my class Priklad.m:
- (void)setDetailItem:(id)newDetailItem
{
if (self.uctyItem != newDetailItem)
{
self.uctyItem = newDetailItem;
[self configureView];
}
}
- (void)configureView
{
if (self.uctyItem ) {
self.prikladLabel.text = self.uctyItem.priklad;
self.uctykprikladu.text = self.uctyItem.uctykprikladu;
}
}
From your code, it seems DetailViewConroller has a property uctyItem. So in your DetaiViewController's prepareForSegue:sender: method, you can just call vc.uctyItem = self.uctyItem;.
Add a property to DetailViewConroller that you can set before pushing to it.
#property (assign, nonatomic) int index;
If you want to get selected cell indexPath then there is a method for that is : selectedIndexPath = [tableView indexPathForSelectedRow];
Related
I have two views in my app.in first view there is a label and I want to update it's value in my second view controller(this shows as a popup view). and after second view controller dismissed, the changed value should be in the label(as lebel.text). I used NSUserDefault.
in my second view controller I assign value like this :
- (IBAction)updatetheDatepicker:(id)sender
{
NSDate *flightDeparturedate = self.flightDepartureDatepicker.date;
NSDateFormatter *flightdepatureFormatter = [[NSDateFormatter alloc] init];
[flightdepatureFormatter setDateFormat:#"d/MM/y"];
NSString *flightDeparturedateDisplay = [flightdepatureFormatter stringFromDate:flightDeparturedate];
NSLog(#"selected departure date :%#", flightDeparturedateDisplay);
[[NSUserDefaults standardUserDefaults] setObject:flightDeparturedateDisplay forKey:#"flightDepartureDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
and in my firstviewcontroller when second view dismiss, I want to update the label in my first view.how can I do that.
self.depdate.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"];
NOTE: second view appears as a UIPopoverpresentationController
this is how I popup my second view controller from first view controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString *identifier = segue.identifier;
if([identifier isEqualToString:#"popover"])
{
UIViewController *destinationController = segue.destinationViewController;
UIPopoverPresentationController *popController = destinationController.popoverPresentationController;
if(popController)
{
popController.delegate = self;
}
}
if([identifier isEqualToString:#"popoverone"])
{
UIViewController *destinationController = segue.destinationViewController;
UIPopoverPresentationController *popController = destinationController.popoverPresentationController;
if(popController)
{
popController.delegate = self;
}
}
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
return UIModalPresentationNone;;
}
hope your help with this.
NOTE : Here i did not use any segue. i initiated view controller
FirstViewController.h
#interface FirstViewController : UIViewController<UIPopoverPresentationControllerDelegate>
#property(nonatomic,strong)IBOutlet UILabel *depdate;
#end
FirstViewController.m
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self updateDateLable];
}
- (IBAction)btnClicked:(id)sender
{
//[self performSegueWithIdentifier:#"openDatePicker" sender:self];
UIButton *btnInfo=(UIButton *)sender;
DatePickerPopUpViewController* popOverFileProperty = [[self storyboard] instantiateViewControllerWithIdentifier:#"DatePickerPopUpViewController"];
popOverFileProperty.modalPresentationStyle = UIModalPresentationPopover;
popOverFileProperty.popoverPresentationController.sourceView = btnInfo;
popOverFileProperty.popoverPresentationController.delegate=self;
[self presentViewController:popOverFileProperty animated:YES completion:nil];
}
-(void)updateDateLable
{
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"] != nil) {
self.depdate.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"];
}
else
{
//date is not set yet , set other text as you wish
self.depdate.text=#"Date not selected";
}
}
// Called on the delegate when the user has taken action to dismiss the popover. This is not called when the popover is dimissed programatically.
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController
{
[self updateDateLable];
}
If you want to use Segue :
- (IBAction)btnClicked:(id)sender
{
[self performSegueWithIdentifier:#"openDatePicker" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"openDatePicker"])
{
DatePickerPopUpViewController* popOverFileProperty = [segue destinationViewController];
popOverFileProperty.modalPresentationStyle = UIModalPresentationPopover;
popOverFileProperty.popoverPresentationController.delegate=self;
}
}
Try to call your update value here from NSUserDefaults.
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"] != nil||![[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"]] isEqualToString:#"(null)"]||![[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"]] isEqualToString:#""]) {
self.lbl.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"];
}
else
self.lbl.text=#"NO Date..";
}
So I'm completely stumped here. I'm using xcode 5 and I have a table view with 2 segues. I tried to set the segues originally with two different prototype cells, but that didn't work. So I now have both segues set at the UITableViewController. It seems like whichever segue I created last is the one it goes to. I'm not getting any errors and when I step through the code, it fires on the correct line to execute the segue.
This seems to execute perfectly every time but it just doesn't go to the correct view.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if([currentTableViewType isEqualToString:#"feedbackOnly"]){
// hits this line correctly
[self performSegueWithIdentifier:#"ShowSendFeedback" sender:indexPath];
} else {
// hits this line correctly
[self performSegueWithIdentifier:#"ShowTicketDetails" sender:indexPath];
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(NSIndexPath *)selectedIndexPath {
if ([[segue identifier] isEqualToString:#"ShowTicketDetails"])
{
TicketDetailsViewController *tdv = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
long row = [myIndexPath row];
Ticket * currentTicket = [ticketsArray objectAtIndex:row];
tdv.tPriority = currentTicket.ticketPriority;
tdv.tId = currentTicket.ticketId;
tdv.tStatus = currentTicket.ticketStatus;
}
if ([[segue identifier] isEqualToString:#"ShowSendFeedback"]){
FeedbackViewController *fvc = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
long row = [myIndexPath row];
Ticket * currentTicket = [ticketsArray objectAtIndex:row];
fvc.tPriority = currentTicket.ticketPriority;
fvc.tId = currentTicket.ticketId;
fvc.tStatus = currentTicket.ticketStatus;
}
}
To be thorough, I've included my entire controller that has the issue.
#import "TicketsViewController.h"
#interface TicketsViewController ()
#end
#implementation TicketsViewController
#synthesize json, ticketsArray, ticketsTableView, currentTableViewType;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Tickets";
AppDataClass *appData=[AppDataClass getInstance];
currentTableViewType = appData.tableViewType;
[self retrieveData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return ticketsArray.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if([currentTableViewType isEqualToString:#"feedbackOnly"]){
return #"Requires Feedback";
} else {
return #"Issues";
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
Ticket * currentTicket = [ticketsArray objectAtIndex:indexPath.row];
cell.textLabel.text = currentTicket.ticketName;
cell.detailTextLabel.text = currentTicket.ticketAddress;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if([currentTicket.ticketPriority.lowercaseString isEqualToString:#"high"]) {
cell.imageView.image = [UIImage imageNamed:#"alert.png"];
if([indexPath row] % 2) [cell setBackgroundColor:[UIColor lightGrayColor]];
}
return cell;
}
#pragma mark - Methods
- (void)retrieveData
{
// NSURL * url = [NSURL URLWithString:getDataURL];
// NSData * data = [NSData dataWithContentsOfURL:url];
AppDataClass *appData=[AppDataClass getInstance];
NSString *args = #"userid=%#&authid=%#";
NSString *values=[NSString stringWithFormat:args, appData.userId, appData.authId];
json = [appData getPostData:appData.URL_LIST_TICKETS:values];
ticketsArray = [[NSMutableArray alloc] init];
// segeue names
// allTickets
// feedbackOnly
for(int i=0; i<json.count; i++){
NSString * tId = [[json objectAtIndex:i] objectForKey:#"id"];
NSString * tName = [[json objectAtIndex:i] objectForKey:#"name"];
NSString * tPriority = [[json objectAtIndex:i] objectForKey:#"priority"];
Ticket * myTicket = [[Ticket alloc] initWithTicketId:tId andTicketName:tName andTicketPriority:tPriority];
[ticketsArray addObject:myTicket];
}
[self.ticketsTableView reloadData];
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if([currentTableViewType isEqualToString:#"feedbackOnly"]){
[self performSegueWithIdentifier:#"ShowSendFeedback" sender:indexPath];
} else {
[self performSegueWithIdentifier:#"ShowTicketDetails" sender:indexPath];
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(NSIndexPath *)selectedIndexPath {
if ([[segue identifier] isEqualToString:#"ShowTicketDetails"])
{
TicketDetailsViewController *tdv = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
long row = [myIndexPath row];
Ticket * currentTicket = [ticketsArray objectAtIndex:row];
tdv.tPriority = currentTicket.ticketPriority;
tdv.tId = currentTicket.ticketId;
tdv.tStatus = currentTicket.ticketStatus;
}
if ([[segue identifier] isEqualToString:#"ShowSendFeedback"]){
FeedbackViewController *fvc = [segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView indexPathForSelectedRow];
long row = [myIndexPath row];
Ticket * currentTicket = [ticketsArray objectAtIndex:row];
fvc.tPriority = currentTicket.ticketPriority;
fvc.tId = currentTicket.ticketId;
fvc.tStatus = currentTicket.ticketStatus;
}
}
#end
Ok... so it seems to be a bug in XCode. I had originally copied the 2nd ViewController that I was trying to segue to and changed the class of it as well as some of the view components. I figured StoryBoard would be smart enough to reassign this view as its own. I was wrong. XCode didn't seem to like that. Starting from scratch with a new ViewController seems to fix everything and the segues are working correctly now. The exact same code works.
So if anyone is having this issue, make sure you didn't copy and paste a ViewController that you are trying to segue to. This will save you hours of headaches :-)
It probably had a reference to the same ViewController which is why whatever the last segue I setup was the only one working.
I use segues for both push on cell and detail disclosure button.
I can't tap on indices, because detail disclosure button "intercepts" touch instead.
Code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
if ([segue.identifier isEqualToString:#"Dossier Segue"]) {
Person *person = [[self fetchedResultsController] objectAtIndexPath:indexPath];
DSRevealViewController *vc = (DSRevealViewController *)segue.destinationViewController;
vc.person = person;
vc.transitioningDelegate = self;
}
else if ([segue.identifier isEqualToString:#"Info"]) {
Person *person = [[self fetchedResultsController] objectAtIndexPath:indexPath];
NSAssert(person, #"Person is nil");
PersonInfoViewController *vc = (PersonInfoViewController *)segue.destinationViewController;
vc.person = person;
}
}
P.S. I checked my other app where I use table view delegate methods instead of segues, and it works well.
I have a detail view controller that is hooked up to a table view cell. I have a data model. It is an NSObject and has a NSMutableArray will all my properties I need in them.
I hooked up a label to an #property and named it questionLabel. For some reason, when I push over to the detail view, it does not display the question I put in the data model for the NSMutableArray.
At first I thought the segue was not working, but when I tried to change the navigation bar title, it worked when I passed my data from my NSMutableArray.
Anyone know what I am doing wrong with my label?
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"pushDetail"])
{
// Create an instance of our DetailViewController
DetailQuestionViewController *DQV = [[DetailQuestionViewController alloc] init];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
// Setting DQV to the destinationViewController of the seque
DQV = [segue destinationViewController];
Question *selectedQuestion = [self.myQuestionList questionAtIndex:path.row];
DQV.questionLabel.text = [selectedQuestion questionName];
DQV.navigationItem.title = [selectedQuestion questionRowName];
}
}
UPDATE (For: adambinsz)
Table view
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"pushDetail"])
{
// Create an instance of our DetailViewController
DetailQuestionViewController *DQV = [[DetailQuestionViewController alloc] init];
// Setting DQV to the destinationViewController of the seque
DQV = [segue destinationViewController];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
Question *selectedQuestion = [self.myQuestionList questionAtIndex:path.row];
DQV.detailItem = selectedQuestion;
}
}
detailView
- (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) {
Question *theQuestion = (Question *)self.detailItem;
self.questionLabel.text = theQuestion.questionName;
NSLog(#"The Question's questionName is %#", theQuestion.questionName);
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
The reason I think it may not be working, is because the if statement for self.detailItem is not checking it correctly.
The method gets called just not the detailItem.
Your label probably hasn't been created yet when you try to set its text. I would create a selectedQuestion instance variable on DetailQuestionViewController and set it when you create the view controller. Something like this:
// Create an instance of our DetailViewController
DetailQuestionViewController *DQV = [[DetailQuestionViewController alloc] init];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
// Setting DQV to the destinationViewController of the seque
DQV = [segue destinationViewController];
DQV.selectedQuestion = [self.myQuestionList questionAtIndex:path.row];
And in DetailQuestionViewController's viewDidLoad method, set your label's text by using:
self.questionLabel.text = [selectedQuestion questionName];
self.navigationItem.title = [selectedQuestion questionRowName];
I have an Xcode Universal Storyboard project that is properly displaying data for the iPhone but does not display data for the iPad. I had initialized the data array using the code below.
It is working properly in the iPhone but does not display data in the iPad and gets the error:
-[DetailViewController setDataController:]: unrecognized selector sent to instance
This is the AppDelegate.m
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
MasterViewController *masterViewController = (MasterViewController *)[navigationController topViewController];
DataController *controller = [[DataController alloc] init];
masterViewController.dataController = controller;
splitViewController.delegate = (id)navigationController.topViewController;
} else {
// Create the data controller and pass it to the master view controller.
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
MasterViewController *masterViewController = (MasterViewController *) [navigationController topViewController];
DataController *controller = [[DataController alloc] init];
masterViewController.dataController = controller;
}
The compiler is complaining about the DetailViewController here is that file.
#import "DetailViewController.h"
#import "Play.h"
#interface DetailViewController ()
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
#end
#implementation DetailViewController
#synthesize masterPopoverController = _masterPopoverController;
#synthesize play;
#pragma mark -
#pragma mark View lifecycle
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Scroll the table view to the top before it appears
[self.tableView reloadData];
[self.tableView setContentOffset:CGPointZero animated:YES];
//self.part = play.part;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#pragma mark - Split view
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UITableViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
barButtonItem.title = NSLocalizedString(#"Trading Rules That Work", #"Trading Rules That Work");
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
self.masterPopoverController = popoverController;
}
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UITableViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
// Called when the view is shown again in the split view, invalidating the button and popover controller.
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
self.masterPopoverController = nil;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// There are 2 sections, for rule, and media, in that order.
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//The number of rows varies by section.
NSInteger rows = 0;
switch (section) {
case 0:
// For part and date there is just one row.
rows = 1;
break;
case 1:
// For the media section, there are as many rows as there are media.
rows = [play.media count];
break;
default:
break;
}
return rows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.autoresizingMask = UIViewAutoresizingFlexibleHeight;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont boldSystemFontOfSize:11];
cell.textLabel.numberOfLines = 13;
}
NSString *cellText = nil;
switch (indexPath.section) {
case 0:
cellText = play.part;
break;
case 1:
cellText = [play.media objectAtIndex:indexPath.row];
break;
default:
break;
}
cell.textLabel.text = cellText;
return cell;
}
#pragma mark -
#pragma mark Section header titles
/*
HIG note: In this case, since the content of each section is obvious, there's probably no need to provide a title, but the code is useful for illustration.
*/
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *title = nil;
switch (section) {
case 0:
title = NSLocalizedString(#"Video Description", #"Part section title");
break;
case 1:
title = NSLocalizedString(#"Media", #"Main Media section title");
break;
default:
break;
}
return title;
}
#end
When you do
object.property = value;
in Objective-C code, that's a short cut for:
[object setProperty:value];
Since you don't appear to have a dataController property, there's no setDataController selector.
So either:
declare a dataController property in your DetailViewController's .h then synthesize it in your implementation, or
create a setter and manually assign it to an instance variable.
You are getting this error because in your iPad storyboard you do not have the class set properly for your navigation controller's rootViewController. Make sure the class for that viewController is set to DataController in the Identity Inspector. You probably have this set correctly in your iPhone version storyboard, which is why you don't get the error when running the iPhone version.