I'm having an issue with my app.
I have 3 View controllers, let's name them Oil, App and Prop . Those 3 View Controllers are embed in Navigation controllers. And in those View Controllers I got 3 table view.
So from Up to Bottom and Left to Right :
Prop View Controller -> Prop Detail View Controller
Oil View Controller -> Oil Detail View Controller-> Web View Controller
App View Controller-> App Detail View Controller
So in the middle (Oil) Everything works fine, I click on a cell, and the Oil Detail View Controller is displayed, with the information I passed through my Segue.
OilViewController.m :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *sectionTitle = [aromaSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionAroma = [tableData objectForKey:sectionTitle];
aromaNom = [sectionAroma objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"Detail" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"Detail"]) {
OilDetailViewController *test = segue.destinationViewController;
test.aromaName = aromaNom;
test.botaniqueName.text = botaniqueName;
}
}
And I'm also performing Segue between Oil Detail View Controller and Web View Controller like this :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"webView"]) {
NSLog(#"Segue is catched");
WebViewViewController *webView = segue.destinationViewController;
webView.aromaUrl = _aromaName;
}
}
I click on the orange button and it displays the webview.
But now if I do the SAME thing in Prop or App it doesn't work properly.
For example in Prop Detail VC I got a Label that displays the Property selected, but it displays me the View Controller with the label containing the old selected property before displaying me the right property selected in the label. So I have 2 Prop Detail View displayed AND embed in my Navigation Controller.
I made a video of the simulator : http://videobam.com/VwgLx
The code in PropViewController.m :
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *sectionTitle = [aromaPropSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionProp = [propData objectForKey:sectionTitle];
propName = [sectionProp objectAtIndex:indexPath.row];
NSLog(#"prop name = %#", propName);
[self performSegueWithIdentifier:#"PropDetail" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"PropDetail"]) {
PropDetailViewController *propView = segue.destinationViewController;
propView.propStr = propName;
NSLog(#"PREPARE FOR SEGUE PROP VIEW CONTROLLER");
}
}
And in PropDetailViewController.m :
- (void)viewDidLoad {
[super viewDidLoad];
self.propLabel.text = _propStr;
NSLog(#"VIEW DID LOAD PROP DETAIL");
// Do any additional setup after loading the view.
}
Finally the logs :
Thanks in advance for your help, I'm stuck with this, and nobody in my team knows iOs .. So i'm alone with this !
So I finally managed to find a proper solution .. I still don't know why it works on Oil and causes problems on other views but still; here is the solution :
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *sectionTitle = [aromaPropSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionProp = [propData objectForKey:sectionTitle];
propName = [sectionProp objectAtIndex:indexPath.row];
NSLog(#"prop name = %#", propName);
[self performSegueWithIdentifier:#"PropDetail" sender:self];
}
Delete the method above. And do everything you do in this method in the prepareForSegue method instead :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"PropDetail"]) {
PropDetailViewController *propView = segue.destinationViewController;
NSIndexPath *indexPath = [self.propTableView indexPathForSelectedRow];
NSString *sectionTitle = [aromaPropSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionApp = [propData objectForKey:sectionTitle];
NSString *name = [sectionApp objectAtIndex:indexPath.row];
propView.propStr = name;
}
}
Now it works fine ! But it's not logic that it works in a place, and doesn't in an other ..
Related
I'm trying to make a simple iOS app by following this (https://www.appcoda.com/use-storyboards-to-build-navigation-controller-and-table-view/) tutorial but when I try to click on the listed items, I don't get redirected to the detail view and just stay on the same page. I'm fairly new to using both Xcode (I'm using Xcode 7) and objective-C so I have no idea what I'm doing. Any kind of help will be very appreciable.
In your case the storyboard ID is RecipeBookViewController
You have to set Storyboard ID for that View controller as explained below.
GO In Xcode utilities pan click on Identity Inspector and set
Storyboard ID = RecipeBookViewController
For more clarification see the Image, and add RecipeBookViewController against Storyboard ID
Follow this code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self performSegueWithIdentifier:#"Your Segue Name" sender:self];
}
pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([segue.identifier isEqualToString:#"Your Segue Name"]) {
DetailViewController *vc= (DetailViewController *)segue.destinationViewController;
NSIndexPath *indexPath = [tableview indexPathForSelectedRow];
vc.(DetailViewController Object)= [(Your tableView Array name) objectAtIndex:indexPath.row];
}
}
In appCoda, they used segue to push so you might be not added this code in your project,
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"segue_Key"]) {
DetailViewController *nextVC = [segue destinationViewController];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"segue_Key" sender:self];
}
If you facing issue in segue then remove the segue connection from storyboard and use below code ,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *obj = (DetailViewController *) [self.storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"]; // Identifier must match with the storyboard VC ID, else project git crashed.
[self.navigationController pushViewController:obj animated:YES];
}
If you already done this, then let me know.
If you don't want to use a segue you should create your destination controller by code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
destinationcontroller *loading = (destinationcontroller *)[self.storyboard instantiateViewControllerWithIdentifier:#"destinationcontroller"];
[self.navigationController pushViewController:loading animated:YES];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog((#"This is didSelectRowAtIndexPAth"));
DetailViewController *detailViewController = [[DetailViewController alloc] init];
detailViewController.myDictionary = [self.placeArray objectAtIndex:[indexPath row]];
/* The below NSlog is showing the content , its not null still in next viewcontroller same variable showing null content*/
NSLog(#"My Dictionary: This is a MasterView%#",detailViewController.myDictionary);
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
It is because the presented instance of your DetailViewController is different than the instance you are creating manually. You should either present that new ViewController yourself (modally or by push), or implement the prepareForSegue method and set the dictionary there.
Edit:
The 2 solutions:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailViewController = [[DetailViewController alloc] init];
detailViewController.myDictionary = [self.placeArray objectAtIndex:[indexPath row]];
// If it is a modal
[self presentViewController:detailViewController animated:YES];
}
OR
#implementation MyClass {
NSIndexPath *selectedCellIndexPath;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog((#"This is didSelectRowAtIndexPAth"));
selectedCellIndexPath = indexPath;
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showDetail"]) {
DetailViewController *detailViewController = (DetailViewController *)segue.destinationViewController;
detailViewController.myDictionary = [self.placeArray objectAtIndex:selectedCellIndexPath.row];
}
}
try this
Decalre one NSInteger varable Globaly assign that varble to indexpath.row
#interface DashbordViewController ()
{
NSInteger SelectedRownum;
}
#end
#implementation DashbordViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SelectedRownum=indexPath.row
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"])
{
NSLog((#"This is didSelectRowAtIndexPAth%#",SelectedRownum));
DetailViewController *detailViewController = [segue destinationViewController];
detailViewController.myDictionary = [self.placeArray objectAtIndex:SelectedRownum];
}
}
In DetailViewController check if the myDictionary is a property declared as weak or strong..
try this . . .
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog((#"This is didSelectRowAtIndexPAth"));
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:#"myStoryBoardName" bundle:nil];
self.detailsViewController = [mystoryboard instantiateViewControllerWithIdentifier:#"detailviewcontroller"]
/* The below NSlog is showing the content , its not null still in next viewcontroller same variable showing null content*/
NSLog(#"My Dictionary: This is a MasterView%#",detailViewController.myDictionary);
[self performSegueWithIdentifier:#"showDetail" sender:self];
}
you have to set identifier of your detailViewController in storyBoard .
You need to assign the dictionary in prepareForSegue: method.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DetailViewController *viewController = = (DetailViewController *)[segue destinationViewController];
detailViewController.myDictionary = //YOUR Dictionary here;
}
This way the same dictionary can be obtained in viewDidLoad: of DetailViewController.
Note: Make sure you allocate the dictionary.
Hope it helps.
Since I can't see implementation of your controller (being subclass of UIViewController or not), I cannot say a lot, but keep in mind that initWithNibName:bundle: is the designated initializer for UIViewController and not init.
So, this is the first problem. In any case, check the instance before setting a property. It is very likely that instance is nil.
EDIT:
It is also very likely, they you are instantiating new View Controller from existing. In this case, you can add new view controller as child controller or present new controller from existing. In both cases properties of existing are reachable from new through properties: parentViewController and presentingViewController, which makes the story opposite: you take property value from existing controller into new controller.
You are creating new view controller in didSelectRowAtIndexPath, and at the end you are calling prepareForSegue method... which will create new Instance, So you have to set your data which you want to send in new view controller in prepareForSegue method like this.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//
if ([[segue identifier] isEqualToString:#"name_of_ur_segue"])
{
// Get reference to the destination view controller
DetailViewController *detailViewController = [segue destinationViewController];
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
// Pass any data here ...
detailViewController.myDictionary = [self.placeArray objectAtIndex:[indexPath row]];
}
}
Edit:
As you are accessing data in ViewDidLoad method and in iOS 7 data passed like this is not accessible in ViewDidLoad method. As view controller presentation logic is bit changed now. Now we can pass data in initMethod if we want to access this in viewDidLoad.
Or access this in viewWillAppear or viewDidApepar.
If you want to call this code only once in viewDidAppear or ViewWillApepar just set a boolean flag, which can tell if you want to access this or not.
I have a table view controller that displays all fetchresults for an entity. when a row is selected, I want that row to pass its information to a detail view controller. problem is I get stuck on how to only show the entity selected and not all of them before I segue.I thought with just what I had in didSelectAtIndexPath it should be changing the textfield's text in the next view controller, but it doesnt. Am I missing something? here is what I have so far.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Athlete *athlete = (Athlete *)[athleteArray objectAtIndex:indexPath.row];
AthleteDetail *athleteDetail= [self.storyboard instantiateViewControllerWithIdentifier:#"showAthlete"];
athleteDetail.firstDetailTextField.text = athlete.first;
[self.navigationController pushViewController:athleteDetail animated:YES];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showAthlete"]){
//prepare
}
}
UITableView has - (NSIndexPath *)indexPathForSelectedRow method. Use it to get index of selected row.
You'll have sth like:
NSIndexPath *index = [self.yourTableView indexPathForSelectedRow];
NSUInteger currentRow = [index row];
YourDataObject * d = // take out data from your model using currentRow
YourDetailViewController *vc = [segue destinationViewController];
// pass your data to detailViewController
[vc setData:d];
I have developed an application using a TableView connected to a SQLite database with a search bar and everything works well.
I have a detail view controller that shows me infos about a clicked row. How can I pass a variable from AuthorVC.m to Details.m?
Partial code :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"prepareForSegue: %#", segue.identifier);
if ([segue.identifier isEqualToString:#"Details"])
// segue.identifier value here
{
Details *dv = segue.destinationViewController;
dv.labelText.text = author.title;
// author.title = dv.labelText.text ;
// your value to pass
[segue.destinationViewController setLabelText:author.title];
}
}
Do this:
Create property of variable in myDetails to pass data
Suppose i have NSString *strAuthoTitle in myDetails
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//Depending upon cell index pass your data differently
myDetails *objmyDetails = [myDetails alloc] initWithNib:#"myDetails" bundle:nil] //alloc your controller for navigation
objmyDetails.strAuthoTitle = [yourArrayofAuthorTile objectAtIndex:indexPath.row];
//Simarly other data can be passed
}
As u not mentioned that u were using storyboard so for that u need to create a segue between AuthorVC to Details controlers and use that segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//NSLog(#"prepareForSegue: %#", segue.identifier);
if ([segue.identifier isEqualToString:#"DetailsPass"]) // segue.identifier value here
{
objmyDetails = segue.destinationViewController;
objmyDetails.strText =lblText.text; // your value to pass
//[segue.destinationViewController setStrText:lblText.text];
}
}
lets say you have 2 properties in your detailedVC strName and strDescription...
than before pushing the detailedVC in the stack, you could simple do something like:
detailedVCObject.strName = #"whatever";
detailedVCObject.strDescription = #"whatever";
hope it would help...
With story board
How pass data in seque ios5 storyboard uitableview to detail view
http://kurrytran.blogspot.in/2011/10/ios-5-storyboard-and.html
Without story board
For this you have to access varible in class one let see below example for example on click of table row you have to navigate on another view say root view. So for this define a variable in root view and access this view when you create object in didselect method of table.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
RootViewController *rvController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:[NSBundle mainBundle]];
//Increment the Current View
rvController.CurrentLevel += 1;
//Set the title;
rvController.CurrentTitle = [dictionary objectForKey:#"Title"];
//Push the new table view on the stack
[self.navigationController pushViewController:rvController animated:YES];
[rv release]
}
I am trying to use Table Views and navigation controllers. This is the code I would use if I was using NIB files. This piece of code would work fine if I was using NIB files, but I decided to try storyboard -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (_webViewController == nil) {
self.webViewController = [[[WebViewController alloc] initWithNibName:#"WebViewController" bundle:[NSBundle mainBundle]] autorelease];
}
RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];
_webViewController.entry = entry;
[self.navigationController pushViewController:_webViewController animated:YES];
}
I have created another scene in storyboard and have everything set up out there. When a user clicks a cell in this Table View they will be taken to that scene. This is what I wrote for the code but it is not right and I'm hopelessly stuck :( -
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"articleView"]){
UINavigationController *navigationController = segue.destinationViewController;
WebViewController *controller = (WebViewController *)navigationController.topViewController;
controller.webView = self;
}
Answer - Answers 2 and 3 are both right
I had a very similar problem 2 days ago, with the user selecting the disclosure accessory on a row and wanting to invoke a segue. What worked for me:
In storyboard, create segue "articleView" from the entire tableView controller (not the cell) to the next viewController.
Add the following method to your tableViewController:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"articleView" sender:[self.tableView cellForRowAtIndexPath:indexPath]];
}
Just for you I also tested with tableView:didSelectRowAtIndexPath: and it works.
Enjoy,
Damien
If your table view is already embedded in a navigation controller (looks that way, from your first code snippet) then the destination view controller of your segue will be a WebViewController, not a navigation controller.
You can therefore have your prepareForSegue method pass the item directly across :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"articleView"])
{
WebViewController *controller = (WebViewController *)segue.destinationViewController;
RSSEntry *entry = [_allEntries objectAtIndex:[self.tableView indexPathForSelectedRow].row];
controller.entry = entry;
}
}
You may find this excellent two-part tutorial helpful
http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-1