Setting Accessory on cell in viewDidLoad - ios

I have two table view controllers, "root" and "detail". In my root view I have this cell which says "Status". I need to be able to change that. When I click it i am seguewayd to the detailed view which shows the statuses I can pick (static cells). When I click on a status, a checkmark is displayed. But this checkmark also needs to be displayed when a status is previously chosen. So the checkmark should be visible as soon as I am seguawayd in from the root view.
I am able to display a checkmark next to the status as soon as i click a cell. But when I want the checkmark to be displayed when i'm seguawayd, it doesn't show. This is the code im using
- (void) setCheckmarkOnIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self setCheckmarkOnIndexPath:indexPath];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// indexPathForRow set to the third cell to demo
[self setCheckmarkOnIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
}

You need to store the user selection somewhere, and pass it into your controller (or access it in your controller depending on where it's saved and which object owns that information).
Currently, you don't save the user selection so you can't update the cell. Note also that you should be updating the selected cell in viewDidAppear:, not viewDidLoad, and that you should look at using tableView:willDisplayCell:forRowAtIndexPath: to properly deal with the table view being scrolled (and cells being replaced / reused).

Related

how to use the function dequeueReusableCellWithIdentifier:forIndexPath?

I know that dequeueReusableCellWithIdentifier:forIndexPath is called by tableView method inside the tableviewcontroller. And if I understand correctly, tableView method is called several times until all the cells are populated. But what I don't know is where do you get the value for the parameter IndexPath? I want to use dequeueReusableCellWithIdentifier:forIndexPath for a method that I created because I want to access my cell to copy some values of its properties.
NOTE:
I already populated my cell, which means that I successfully used the method tableView.
(Edit) ADDITIONAL INFO:
I'm trying to create a profile and edit profile tableviews. Inside the profile tableview, I displayed the name, address, contact#, etc., of the user. Also, I have a segue called edit profile. In the edit profile, I have textfields for each category (name, address, etc.). What I want to do is, if I edit the contents of the textfields, I should be able to display the new contents in my profile tableview. An example case would be: in the profile view I'm displaying -> name:human, address:earth (each in its own cell). Now if I go to editprofile tableview, I will edit the contents such that -> name:alien, address:mars. After that, there is a button called 'apply' to end editing of contents and go back to profile tableview. If I go back to profile view, the display should now be name:alien, address:mars and not name:human, address:earth.
Here is some code if it's any help. The code is called by a button in tableviewcontroller. "MyCell" is the class of my cell. This code is not working properly. I hope someone can help me fix this.
- (IBAction)updateCopies:(id)sender {
static NSString *ident = #"MyCell";
NSIndexPath *indexPath;
//create cell
MyCell *cell = [self.tableView dequeueReusableCellWithIdentifier:ident forIndexPath:indexPath];
//create variable for accessing cells
int row = [indexPath row];
_labelValues[row] = cell.textField.text
}
You should only use dequeueReusableCellWithIdentifier when you need to supply the table view with a cell to display. If you want to get the UITableViewCell object at a certain index, you should use cellForRowAtIndexPath.
Your problem
What you really need is a model class. You can then pass this to the edit controller, which changes the properties. Then when you return to the tableView, you can reload it and display the new properties.
What you could also do is create a delegate protocol for your edit profile controller, something like EditProfileViewControllerDelegate with something like:
protocol EditProfileViewControllerDelegate {
- (void)editProfileViewController:(EditProfileViewController *)controller didUpdateName:(NSString *)name address:(NSString *)address;
}
You can implement this delegate in your table view controller and use it to update the values when the text is changed. However, this quickly becomes unwieldy, I would not recommend it over using a proper model class.
You can get indexPath using CGPoint..You can use dequeueResusableCell for reusability of the cell..
- (IBAction)updateCopies:(id)sender {
CGPoint position = [sender convertPoint:CGPointZero
toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:position];
//create variable for accessing cells
MyCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
int row = [indexPath row];
_labelValues[row] = cell.textField.text
}
Hope it helps you..
Use this
- (IBAction)updateCopies:(id)sender {
MyCell *parentCell = (MyCell *)sender.superview;
while (![parentCell isKindOfClass:[MyCell class]]) { // iOS 7 onwards the table cell hierachy has changed.
parentCell = parentCell.superview;
}
UIView *parentView = parentCell.superview;
while (![parentView isKindOfClass:[UITableView class]]) { // iOS 7 onwards the table cell hierachy has changed.
parentView = parentView.superview;
}
UITableView *tableView = (UITableView *)parentView;
NSIndexPath *indexPath = [tableView indexPathForCell:(MyCell *)parentCell];
NSLog(#"indexPath = %#", indexPath);
}
Well I got what you want to accomplish.
Firstly, there is a delegate which is being called when you click/select a cell and go to the Edit Profile page. That delegate is
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
///
}
Make a global variable, say selectedIndexPath which holds the current cell index path which is being edited. Update this value each time when you go to edit profile page.
Like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedIndexPath = indexPath;
// code to go to edit page...
}
Now in your updateCopies Method, do like this
- (IBAction)updateCopies:(id)sender {
//get the existing cell with the indexPath
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[selectedIndexPath]];
[self.tableView endUpdates];
//rest of your code goes here...
}

Why is awakeFromNib called twice from a Cell in a TableView?

I'm trying to understand why awakeFromNib is being called twice in my code. I currently have a tableview that has a special compressible cell that appears once at the end of the table. The first awakeFromNib is being called when the tableview is scrolled to the special cell at the end (which is fine I believe,as the tableview is reusing cells). However, whenever I tap the cell to expand the cell, the awakeFromNib is being called again.
Could anyone explain to me why awakeFromNib is being called twice? And how I could only make it only be called once?
Thanks
EDIT** Code people have requested
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section >= (NSInteger)[self.trip.destinations count]) {
GuestCell *cell = (GuestCell*)[tableView dequeueReusableCellWithIdentifier:GuestCellIdentifier forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell setupCellForGuests:self.trip.guests];
cell.guestExpanded = NO;
NSLog(#"RETURNING CELL");
return cell;
}
// For all other sections
return [self prepareCardCellForIndexPath:indexPath forHeightCalc:NO];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section >= (NSInteger)[self.trip.destinations count]) {
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
You're animating the reload of the expanding row. The table view implements this by creating another cell for the same index path, and animating a transition from the old cell to the new cell. It creates a second instance of your cell prototype, so the second instance also receives the awakeFromNib message. If you log self, you'll see that the address is different the second time.
I don't think you can avoid the creation of a second cell instance (and thus a second awakeFromNib) unless you get rid of the animation. Even then I'm not sure it will reuse the old cell.
If the cell with that nib is only one in the table, then my guess is that it has something to do with animations. I didn't check how tableview handles cells during animation, but for tableview header it asks for another instance and then performs animation (for example fade) - so the old instance is faded out and the new is faded in. At least that's what I think has the highest probability, if you are handling cells correctly.

Capture cell being pressed without didSelectRowAtIndexPath

I have the following UITableViewCell (well, subclassed).
With didSelectRowAtIndexPath it is possible to capture that a cell has been selected in UITableViewController. My problem occurs due to the fact that directly pressing Choose User bypasses the selection of the cell.
How could I allow my UITableViewController to be aware that UITableViewCell foo has been pressed even if the user immediately hits Choose User?
N.B. I don't need the Selection capability per se, this was just by method of knowing that a user had tapped within a cell area.
You could just call the method directly. If we say that for each Choose User button we are setting the row number as the tag and assuming that you don't have sections so everything will happen in section 0 we could do.
- (void)hitChooseUser:(id)sender
{
// Do whatever you want for when a user hits the `Choose User` button
// Code......
// Then do this at the end or whenever you want to do it.
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[sender tag] inSection:0];
// Also assuming you have created you have created you UITableView correctly.
[self tableView:myTableView didSelectRowAtIndexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Do whatever it is you want.
}
I also found this link that may help you Manually call didSelectRowatIndexPath
You could also disable the user interaction with the cell itself by setting userInteractionEnabled: to NO for each cell in cellForRowAtIndexPath: so didSelectRowAtIndexPath: will only get called when you want to call it manually.
Do not call didSelectRowAtIndexPath: It is a UITableViewDelegate method and, where possible, should be used as such (meaning let the UITableView send messages to it). In addition, it creates an unnecessary dependency on UITableView implementation.
That being said, in order to achieve shared behavior that is performed either on button click, or on row selection, refactor it out into a common method that is not coupled with UITableViewDelegate
For example:
-(void)doSomethingCommon {
//do shared code here
}
-(void)chooseUserButtonPressed:(id)sender {
[self doSomethingCommon];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self doSomethingCommon];
}
And if your UITableView shows more than one of these rows, for which you depend on knowing which corresponding model object is related to the cell, than you can use the tag property on UIView subclasses (usually something in your cell) to mark the row that the object is shown in.

How to loop through 5 UITableView cells based on the original cell tapped first

I have an app that lists some data in a tableview, in cells. I want the user to be able to select a table view cell, any one, and have the app cycle through the 5 lower cells. Here is what I have so far:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// Navigation logic may go here. Create and push another view controller.
[self fetchCellsToProcess:indexPath];
}
Here is the fetchCellsToProcess: method:
-(void)fetchCellsToProcess:(NSIndexPath*)indexPath{
for (int cellsToProcess = 0; cellsToProcess < 5; cellsToProcess++) {
//process each cell
//...
}
}
I need use the indexPath to get its indexPath.row. Then add 5 to that indexPath.row and only process the tweets between indexPath.row passed in and indexPath.row+5. What programming logic should I use to cycle through cells x -> x+5?
You should not be using cellForRowAtIndexPath: here: that's part of the presentation logic, while you are working on the model-level logic here.
Look at your cellForRowAtIndexPath: method, and see from where does the text of the cell's labels come. Usually it is an NSArray or some other collection. Your didSelectRowAtIndexPath: method should go directly to that same collection, and grab the info from there.
There is no direct approach to achieve this as dasblinkenlight mentioned
but there is a work around which works for me.
Please follow below approach:
Create your custom button within your custom cell
Create your custom cell class and put button(change type to custom ) do necessary connection custom cell class
create and connect action method named "actionSelectedCell" as below from that button in class you are implementing this logic.
And cellForRowAtIndexPath cell.customButton.text = data from your array or dictionary
- (IBAction)actionSelectedCell:(UIButton *)sender {
// below code for getting selected cell row and its section
UIView *view = sender.superview;
while (view && ![view isKindOfClass:[UITableViewCell self]]) view = view.superview;
UITableViewCell *cell = (UITableViewCell *)view;
indexPathForSelectedCell = [self.tableViewListViewVC indexPathForCell:cell];
NSLog(#"cell is in section %d, row %d", indexPathForSelectedCell.section, indexPathForSelectedCell.row);// so now you are getting indexpath for selected cell
// now you can create simple loop logic to get required data and do whatever you like post it to something or store it for any other use
NSString *strFifthCellContent = [NSString stringWithFormat:#"%#",[dataArray ObjectAtIndex:indexPathForSelectedCell.row+5]]; // in this way you can get data from any cell
}

Is it possible to switch view to tableview from same view?

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..

Resources