Hello future friends who is gonna help me big time on this project,
I have these Books parsed from XML file (adopted from this post I found). First view (RootViewController) has a list of book titles in a UITable. When user clicks on one of the books, instead of viewing the books detail (BooksDetailViewController) in a second UITable, I would like the Title, Author and Summary to be in a custom view laid out in Interface Builder with UILabels and UITextView.
IBOutlet UILabel *bookTitle;
IBOutlet UILabel *bookAuthor;
IBOutlet UITextView *bookSummary;
I believe my problem has to do with RootViewController.m "didSelectRowAtIndexPath". If I understand the example I had adapted properly (which I am not confident about), it passed the Book array into each row of the new table on my BooksDetailViewController.
Book *aBook = [appDelegate.books objectAtIndex:indexPath.row];
I have tried a few things to recreate didSelectRowAtIndexPath, but I am not having much luck. Below I have the example code commented out and with my own terrible guessed code /sigh.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// if(bdvController == nil)
// bdvController = [[BookDetailViewController alloc] initWithNibName:#"BookDetailView" bundle:[NSBundle mainBundle]];
// Book *aBook = [appDelegate.books objectAtIndex:indexPath.row];
// bdvController.aBook = aBook;
// [self.navigationController pushViewController:bdvController animated:YES];
NewBookDetailViewController *detailViewController = [[NewBookDetailViewController alloc] initWithNibName:#"NewBookDetailViewController" bundle:nil];
Book *aBook = appDelegate.books;
//detailViewController.aBook.title = bookTitle.text;
//detailViewController.aBook.author = bookAuthor.text;
//detailViewController.aBook.summary = bookSummary.text;
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
Do I actually connect the parsed data aBook.title to bookTitle (UILabel) in didSelectRowAtIndexPath of RootViewController?
or
Do I connect them in viewDidLoad in NewBookDetailViewController.m?
bookTitle.text = aBook.title;
bookAuthor.text = aBook.author;
bookSummary.text = aBook.summary;
What is the proper way to write the didSelectRowAtIndexPath in RootViewController for a custom view instead of a table view?
Please take it easy on me.
Clo
The purpose of NewBookDetailViewController is to display information about a single book, yes? So NewBookDetailViewController will need a way of being told which book it's supposed to display.
An easy way of doing this would be to add a property to this class to hold a reference to the Book it's supposed to display. You would not want to pass the entire array of books to the detail view controller. How is it supposed to know which single book to display?
Here' how my implementation would look:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Book *selectedBook = [appDelegate.books objectAtIndex:indexPath.row];
NewBookDetailViewController* viewController = [[NewBookDetailViewControlleralloc] initWithNibName:#"NewBookDetailViewController"];
viewController.book = selectedBook; // "book" is a property you'd add to NewBookDetailViewController
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
}
Here's how you add the book property to NewDetailViewController:
The .h file:
#class Book;
#interface NewDetailViewController : UIViewController {
// other instance variables
Book *_book;
}
#property (nonatomic, retain) Book *book;
#end
The .m file:
#import "NewDetailViewController.h"
#import "Book.h" // assuming the "Book" class is defined in Book.h
#implementation NewDetailViewController
#synthesize book = _book;
- (void)dealloc {
[_book release];
[super dealloc];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// set up your controls to display the book information
}
// other method implementations
#end
Related
I have been trying to figure this out for a while and not coming up with a solution. I have a view controller with a table and the first cell of the table is allocated for a button called "Add Friends". When clicked, it takes you to another view controller with a list of contacts in a table. When you click on a person, it goes back to the other view controller and adds the selected person. This is what I have so far.
ContactsViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
FirstViewController *newVC = [self.storyboard instantiateViewControllerWithIdentifier:#"newVCSegue"];
newVC.peopleArray = [[NSMutableArray alloc] init];
Person *user = [contactsList objectAtIndex:indexPath.row];
NSArray *userKeys = [NSArray arrayWithObjects:#"FirstName", #"LastName", nil];
NSArray *userObjects = [NSArray arrayWithObjects:user.firstName, user.lastName, nil];
NSDictionary *userDictionary = [NSDictionary dictionaryWithObjects:userObjects forKeys:userKeys];
[newVC.peopleArray addObject:userDictionary];
[self.navigationController pushViewController:newVC animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
FirstViewController.h
#property (strong, nonatomic) NSMutableArray *peopleArray;
FirstViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
if (indexPath.row == 0) {
contactName.text = #"Add Person";
imgView.image = [UIImage imageNamed:#"plus-icon.png"];
} else {
NSString *firstName = [[peopleArray objectAtIndex:(indexPath.row)-1] objectForKey:#"firstName"];
NSString *lastName = [[peopleArray objectAtIndex:(indexPath.row)-1] objectForKey:#"lastName"];
contactName.text = [NSString stringWithFormat:#"%# %#", firstName, lastName];
}
return cell;
}
This lets me add one friend so far and if I decided to add another to the list, it replaces the first friend added.
What's basically happening is every time you select a new contact, you're recreating the array in the first view controller, hence it is replacing things. You ideally want to try and avoid getting the FirstViewController using the storyboard like that as well, it's pretty bad practice and may well lead to various problems later.
What I'd suggest in this situation is creating a protocol (look at the delegate pattern). This way, what you'd have is :
Use taps "Add Contact"
Contacts list appears, and FirstViewController is set as the delegate
User taps contact to add them
ContactsViewController informs the delegate of the user that was selected
FirstViewController adds the user, and dismissed the view controller
This is generally the approach you'd take, and it's pretty simple to implement. Start with the protocol
#protocol ContactsDelegate
-(void) contactsViewController:(ContactsViewController *)vc didSelectContact:(Person *)person;
#end
Then, make your FirstViewController implement this protocol. To do this, in your header file, in the angle brackets after the name (< >) add ContactsDelegate
In the implementation of FirstViewController, add the new method of the contacts delegate.
In your ContactsViewController.h file, add
#property (nonatomic, assign) NSObject<ContactsDelegate> *delegate;
Then when you display your contacts view controller, set the delegate
userVc.delegate = self;
[self presentModalViewController:userVc];
Then, in the user view controllers didSelectRowAtIndexPath:, simply inform the delegate that you've selected that person
[delegate contactsViewController:self didSelectContact:[contactsList objectAtIndex:indexPath.row]];
And lastly, in your FirstViewController, in the delegate method you added, we need to ADD the user to the list, not re-create the list
[peopleArray addObject:person];
And that should do what you're after :)
From what I understand, you are instantiating a new FirstViewController every time you select a contact in the ContactsViewController. Instead, you should reference the original FirstViewController (perhaps save it before transitioning to ContactsViewController), and use this reference to add the contact to the original array [original.people addObject:userDict]. As long as you make sure to reload the table, this should work.
Sorry this is probably a newbie question to alot of you but I've been going round in circles for the last few hours.
I have a table and when the row is pressed pops to second view.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
BlogDetailViewController *blogDetailViewController = [[BlogDetailViewController alloc] initWithNibName:#"BlogDetailViewController" bundle:nil];
blogDetailViewController.title = [idArray objectAtIndex:indexPath.row];
blogDetailViewController.newsArticle = [content objectAtIndex:indexPath.row];
[self.navigationController pushViewController:blogDetailViewController animated:YES];
}
Then on my next view I have a text box which i want to display the contents of [content objectAtIndex:indexPath.row];.
So far i have added this into the secoundview.h
#interface BlogDetailViewController : UIViewController{
NSDictionary *newArticle;
IBOutlet UITextView *descTextView;
}
#property (nonatomic, copy) NSDictionary *newsArticle;
I have also #synthesize newsArticle; on the secoundview.m, and linked up the IBOutlet.
So far i have
- (void)viewDidLoad
{
[super viewDidLoad];
descTextView.text = [content];
// Do any additional setup after loading the view from its nib.
}
Hope that explains things I can upload the zip if this does not make sense.
Thanks
I'm a bit puzzled with the question as it's not super clear, but I think what you're doing is passing data from the table view to another view, but the next view isn't displaying the data? The simplest thing to do in that case is add into viewWillAppear code that puts the content (newArticle?) into the descTextView.
descTextView.text = [NSString stringWithFormat:newsArticle]; this displayed the string inside the textview
I'm new to Objective-C, I like it,
I'm developping a free application for the local firefighters.
The app does nothing really hard, but I have a big problem with the main menu:
I have already created a table content all the section of my application, I am trying to implement the drill down method by means I can access to other ViewControllers, but I really don't know how to do it, I googled a lot but I've only found fragmentary documentation referenced to old versions of Xcode.
I'm using version 4.5.2 and the storyboard.
Here is the menu.h
#import <UIKit/UIKit.h>
#interface Menu : UITableViewController
#property (nonatomic, retain) NSMutableArray *listaMenu; //questo sarà il mio array contentente le varie opzioni della tabella
#end
And the menu.m
#import "Menu.h"
#import "News.h"
#interface Menu ()
#end
#implementation Menu
#synthesize listaMenu; //creo i metodi getter e setter
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Menu";
//Elementi da visualizzare nella tabella
listaMenu = [[NSMutableArray alloc] initWithObjects: #"News", #"Memebri", #"Calendario", #"Interventi", #"Galleria", #"Mezzi", #"Reclutamento", nil];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (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
{
//funzione in cui va inserito il numero di righe da visualizzare
return [listaMenu count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
cell =[tableView dequeueReusableCellWithIdentifier:#"PlistCell"];
if(cell == nil){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"PlistCell"];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
cell.textLabel.text = [listaMenu objectAtIndex:indexPath.row];
return cell;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath //Rende gli oggetti NON editabili
{
// Return NO if you do not want the specified item to be editable.
//return YES;
return NO;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
}
#end
I hope my problem is well explained.
Thank you very much!
You need to read up about UISegue - this is the object that handles transitions from one UIViewController to another controller. In Interface Builder you can Ctrl-Drag to create a Segue between, say a UIButton and the desired UIViewController. This is the simplest usage of segues.
If you need to pass data to the destination UIViewController then you'll need to implement the - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender method. Within this method you can get the segue.destinationViewController and then send it whatever data you need. N.B. The destination view controller's view has not loaded yet, so if you're trying to customise UIViews directly, then they won't exist. You can fudge it by doing [segue.destinationViewController view] to get going, although it would be better to configure non-UI properties and have the view controller itself do any necessary customisation in viewDidLoad.
/*****UPDATED** ***/r.com/YH3cm.png
I am trying to figure out in the above image, how will we know if the user has selected Date or Track.
/UPDATED/
The data I am receving is through a select query and I create an array to store the list. It is dynamic and not necessary limited to two fields, it can have 10 fields also. How will I know which row is selected and how will I push the data on to the next view.
Like in didSelectRowAtIndexPath, how should I push the date or track field on the next view?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (dvController == nil)
dvController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
Teat *obj = [appDelegate.coffeeArray objectAtIndex:indexPath.row];
dvController.obj = obj;
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:dvController animated:YES];
}
It's still not very clear what you're trying to do. If you want to push a certain view controller depending on what the content of the cell is, but there is no definite arrangement of the rows, I would use the row index to access the array that is the source of your data. Some very loose code:
WhateverObject* selectedObject= (WhateverObject*)[tableDataSourceArray objectAtIndex:indexPath.row];
if( [selectedObject hasAnAttributeYouCareAbout] )
{
MyViewController* theCorrectController= whicheverViewControllerYouWant;
theCorrectController.anAttribute= aValue;
[self.navigationController pushViewController:theCorrectController animated:YES];
}
And here's how you can define your UIViewController subclass MyViewController with specific attributes. In the .h file:
#interface MyViewController : UIViewController {
int anAttribute;
}
#property int anAttribute
#end
In the .m file:
#implementation MyViewController
#synthesize anAttribute;
#end
You can have as many attributes as you want of whatever type, and then you can set them with aViewController.anAttribute as above.
Create objects - dateInfoViewController and trackInfoViewController and then...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = [indexPath row];
if (row==0)
{
if (self.dateInfoViewController == nil)
{
DateInfoViewController *temp = [[DateInfoViewController alloc] init];
self.dateInfoViewController = temp;
[temp release];
}
else {
dateInfoViewController.title= [ NSString stringWithFormat:#"%#", [sessionInfoDetailsArray objectAtIndex:row]];
YourAppDelegate *delegate = [[UIApplication sharedApplication]delegate];
[delegate.sessionNavigationController pushViewController:dateInfoViewController animated:YES];
}
}
if (row==1)
{
if (self.vetInfoViewController == nil)
{
TrackInfoViewController *temp = [[TrackInfoViewController alloc] init];
self.trackInfoViewController = temp;
[temp release];
}
else {
trackInfoViewController.title= [ NSString stringWithFormat:#"%#", [sessionInfoDetailsArray objectAtIndex:row]];
YourAppDelegate *delegate = [[UIApplication sharedApplication]delegate];
[delegate.sessionNavigationController pushViewController:trackInfoViewController animated:YES];
}
}
I fear it's not perfectly clear what do you want to do... if you need to push a different view depending on the selected row you may simply do something like
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0)
//push view 1
else
//push view 2
}
UPDATE: calling indexPath.row you get the index of the selected row. I guess is up to you to decide what to do depending on what row is selected. To pass this information to the next view you may simply think of a #property field to set, a method to call or a custom init method for the view controller you are pushing. What is the problem with the code you posted?
i tried to understand the uitable view and implemented it and able to populate data into row from a nsArray.I have make a NextViewController consisting of a dynamic lable which will receive inpur/text from the SimpleTable class.For ex,
in simple table view class i have rows with content as(see code please):
**My SimpleViewController.m**
#import "SimpleTableViewController.h"
#import "NextViewController.h"
#implementation SimpleTableViewController
- (void)viewDidLoad {
arryData = [[NSArray alloc] initWithObjects:#"iPhone",#"iPod",#"MacBook",#"MacBook Pro",nil];
self.title = #"Simple Table Exmaple";/**/NOT ABLE TO SET TITLE.WHY?????Please guide how to use NSlog here**
[super viewDidLoad];
}
***//And on selection of any row i want to navigate to next view controller class***
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NextViewController *nextController = [[NextViewController alloc] initWithNibName:#"NextViewController" bundle:nil];
[self.navigationController pushViewController:nextController animated:YES];
[nextController changeProductText:[arryData objectAtIndex:indexPath.row]];
}
#end
**My NextViewController.h**
#interface NextViewController : UIViewController {
IBOutlet UILabel *lblProductTxt;
}
- (IBAction) changeProductText:(NSString *)str;
#end
**my NextViewController.m**
//posted only important part of code where i feel may be an issue
- (IBAction) changeProductText:(NSString *)str{
lblProductTxt.text = str;
} #end
I have check IB properly and the connections are proper.Please help me.Not getting where i am wrong?
Make sure self.navigationController has a valid value. Add this before the pushViewController call:
NSLog(#" self.navigationController 0x%x", self.navigationController);