I would like to manipulate table cells in my UITableView as it comes back from its detail view, to remind the user what row they last selected. The UITableView was created in IB and there currently isn't a #property or custom class for the UITableView or any other handle. Clearly, it exists when, the user is coming back from the detail view and viewWillAppear is called but I don't see any handle in the debugger for my UITableView.
Any way to simply get a handle to the IB tableView object?
// - The Containing ViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSIndexPath *selected = [self.tableView indexPathForSelectedRow];
if(selected){
//Do something stylish with the last-selected row
NSLog(#"Last row selected was: %#",selected);
}
}
I solved this by creating a class member of NSIndexPath * and set it inside didSelectRowAtIndexPath. Then, when viewWillAppear executes, when the user navigates back fram the table view detail, I have the last-selected row so I can easily highlight it or treat it any way I want:
//The Containing View Controller
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(self.lastSelectedRow){
[self.tableView selectRowAtIndexPath:self.lastSelectedRow animated:YES scrollPosition:UITableViewScrollPositionNone];
}
}
Related
I have a subclass of UITableViewController.
By default, it creates a UITableView when it is initialized. To that tableview I have set a header that I created in Interface Builder in the screen that is controlled by the controller. The header has two buttons:
one to enter editing mode for the tableview (called "Edit")
one to add a random item to the tableview (called "New").
I linked an IBOutlet property called headerView to the header from Interface Builder and I set it to be the header of the UITableView created at initialization in the viewDidLoad method.
The problem is that when I press the "New" button (which adds a new row with a new item to the tableview) the header of the tableview falls down to the bottom of the tableview.
Any idea why? How can I make it stick to the top?
This is the viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"UITableViewCell"];
[self.tableView setTableHeaderView:self.headerView];
}
This is the method that gets executed when the "New" button is pressed:
- (IBAction)addNewItem:(id)sender {
Item *newItem = [[ItemStore sharedStore] createItem];
NSInteger lastRow = [[[ItemStore sharedStore] allItems] indexOfObject:newItem];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
Thanks.
Possibly you've set up the layout for table header view in a wrong way. Was there any layout constraint on it?
By the way, this project on GitHub is a very simple example to demonstrate how simply it is to achieve what you want in the storyboard. It will produce the result like below:
Please use this project to compare with your current configuration.
I hope this helps in one way or another.
I change the value of 2 UILabels in my "viewDidLoad" method, but I need the view to refresh after that in order to display the values. As it currently stands, the UILabels display the value of the previously selected cell. I need to do the refresh right after I change the labels' values. The "setNeedsDisplay" method is not doing the job.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_nameLabel.text = _selectedLocation.name;
_addressLabel.text = _selectedLocation.address;
[self.view setNeedsDisplay];
}
Based on your comments, I think you are trying to do something like:
- (void)updateLabelTexts {
_nameLabel.text = _selectedLocation.name;
_addressLabel.text = _selectedLocation.address;
}
and wherever you are changing the _selectedLocation values:
//Just an example
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
_selectedLocation = _yourLocationsArray[indexPath.row];
//now you call your update method
[self updateLabelTexts];
}
The point is that you have to call [self updateLabelTexts]; just after you update the values.
A very stupid bug. Turns out when I made the segue to transition into the next view, I actually dragged it from a physical cell on to the destination controller. However, I should've simply connected the sending uiview controller to the destination viewcontroller with the segue, and then manually handled the transition. That fixed it, so there's no need to "refresh or reload" the UIView as I was trying to do.
So I have a DetailViewController which displays the details of row/cell from table view. Now I would like to add an option of DELETE on this controller. I added a Bar Button Item(trash) on it. How will I be able to delete the current row/data and remove it also from the TableViewController?
TableViewController
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WishlistItem *wish = [self.wishlistItem objectAtIndex:indexPath.row];
DetailViewController *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"dvcID"];
dvc.wishItemStr = wish.wishlistItem;
dvc.dateItemStr = wish.targetDate;
dvc.descItemStr = wish.descWishItem;
[self.navigationController pushViewController:dvc animated:YES];
}
When you create the detailed view controller you must be initializing it with some data relevant to the row. So you can extent that initializer method (or add a new method if you like) which takes a block.
When the table view controller creates and loads the detailed view controller it initializes it with some block code that will delete the relevant row.
Example: (note I haven't compiled this).
Add this to the DetailViewController:
#property (copy, nonatomic) void (^deleteRowBlock)(void);
- (void) onDeletion:(void (^)(void)) deletionBlock;
The implementation of onDeletion is
- (void) onDeletion:(void (^)(void)) deletionBlock
{
self.deleteRowBlock = deletionBlock;
}
When the button is pressed in the DetailViewController call the block like this:
self.deleteRowBlock();
Then in didSelectRowAtIndexPath: add this:
[dvc onDeletion:^{
code to delete the row and update your data model
}];
Then when the button is pressed the "code to delete the row and update your data model" will get executed.
Or alternatively if you don't like blocks (but you should learn to like them) define a protocol with a method such as onDelete:(NSIndexPath*) row. The table view is a delegate of the detailed view and implements the protocol method, which you invoke when the button is pressed.
The detailed view would need to know its row number. Alternatively remove the NSIndexPath as the parameter to onDelete and have the tableView cache the row number of the currently presented detail view controller and when onDelete is called it deletes the row for the cached row number.
But it is preferable to use blocks
well, this is another solution,
1) pass self.wishListItem to DetailViewController, here is example
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"dvcID"];
...
[dvc setWishListItem:self.wishListItem];
...
[self.navigationController pushViewController:dvc animated:YES];
}
2) in TableViewController implement viewWillAppear method like this
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView reloadData];
}
3) in DetailViewController you have a delete button, right ? here is your button's action method
- (void)onDelete {
// your deleting stuff ...
[self.wishListItem removeObjectAtIndex:self.currentItemIndex]; // this line updates shared data
}
So TableViewController reloads it's data and keeps cells up to date once you get back (by touching back button, for example)
if you still have questions feel free to comment.
I have a viewcontroller.xib which contains View, buttons,toolbarbutton, text box and a tableview. When I load the initial screen comes without table view which is fine. Now when I click on a toolbarbutton say, viewtable, I want the view to move to tableview. I have filled my tableview data with some default objects like this:
- (void)viewDidLoad
{
tableData = [[NSArray alloc] initWithObjects:#"object1",#"object2",#"object3",#"object4", nil];
[super viewDidLoad];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"My Cell"];
if(cell==nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"My Cell"];
}
cell.textLabel.text=[tableData objectAtIndex:indexPath.row];
return cell;
}
So when I click on toolbar view button it should show tableview with toolbar button which also has a back button so when I click on that it should hide the table view and show the initial view. Is it possible to do all this in single xib? I can achieve the result if I create another xib and simply transfer control over to that xib but I wanted to know if its possible do this without creating a second xib file. And also for navigation I can use navigation controller but I want to check and see if its possible to use toolbar to transfer the control. Thanks.
First check if your table view is inside your view, if not put it inside and set delegate of datasource to file owner, then in your view table method write this code
-(void)viewTable
{
self.tableView.hidden = NO;
self.viewToolbar.hidden=YES;
}
On your back button code in toolbar write
-(void)goback
{
self.tableView.hidden = YES;
self.viewToolbar.hidden=NO;
}
If you don't need animation then you can do the following
Get a handle of tableView in your interface like this:
#property(nonatomic,assign)IBOutlet UITableView *tableView;
Hide your table view in initially ( like in viewDidLoad method )
-(void)viewDidLoad
{
[super viewDidLoad];
self.tableView.hidden = YES;
}
Then in the method called by your toolbar's button do the following
-(void)on_click_toolbar_button
{
self.tableView.hidden = !self.tableView.hidden;
//This will keep toggling the table view from hidden to shown & vice-versa.
}
you could use the hidden property to achieve that. Put these in the appropriate ibaction methods.
_tableView.hidden = Yes;
_tableView.hidden = No;
I'd highly recommend to do this in two separate XIBs. The first should contain a UIViewController (your initial view) and the second a UITableViewController (your table view) class. Both should be handled by a UINavigationController - don't fight the API and try your own hacks if it's not necessary. The mentioned controller classes give you everything you need out of the box.
Well this is not recommended but you can do this by removing and adding tableview..
I have a tableViewController from which i navigate to UIViewController. To save the value of indexPath.row I have used an integer and based on that integer action is performed in UIViewController. Problem is that when I press the back button and selects another index of table, It navigates to UIViewContoller but the action performed is the first one. the ViewDidLoad is not called for the second time.
here is my code.
TableView Code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.iaRecipieViewController) {
self.iaRecipieViewController = [[[iRecipieViewController alloc] initWithNibName:#"iRecipieViewController" bundle:nil] autorelease];
}
if (indexPath.row == 0) {
self.iaRecipieViewController.myLableArray =labelSoupArray ;
}
if (indexPath.row == 1) {
self.iaRecipieViewController.myLableArray =labelSoupArray ;
}
if (indexPath.row == 2) {
self.iaRecipieViewController.myLableArray =labelSoupArray ;
}
// custom string is an NSinteger
self.iaRecipieViewController.customString = indexPath.row;
NSLog(#" int %i",self.iaRecipieViewController.customString);
NSLog(#"index path %i ", indexPath.row) ;
[self.navigationController pushViewController:iaRecipieViewController animated:YES];
[detailTable reloadData];
}
UIViewController Code.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
myLabel.text = [self.myLableArray objectAtIndex:customString];
}
Use viewWillAppear:(BOOL)animated
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
myLabel.text = [self.myLableArray objectAtIndex:customString];
}
viewDidLoad will only get called when the view is loaded; pushing a new ViewController and then removing it won't force the view to be reloaded. viewWillAppear is called before the view is rendered, so you have an opportunity to do things whenever it becomes the primary view.
ViewDidLoad gets called only once when the view is instantiated. Based on your code, you are going back and forth on this view and as such the view is not instantiated (loaded) everytime but rather it was loaded once and now it is really the view disappearing and appearing as you go back and forward to that view.
Put your code in ViewWillAppear or ViewDidAppear.
The method
(void)viewDidLoad
is run when the view gets loaded.
If your view already loaded(means it's still in the memory),maybe it's gone from the screen. But it doesn't mean that the memory is gone; Just re-Run when the view should load to the memory.