Tableview cell with textfields and button - ios

I have a tableviewcell that has two text fields and a button.
The idea is that you fill in the text field, but the button will bring up another viewcontroller that has some sort of calculator.
My problem comes with bringing the value back into the right cell and textfield.
I get at the button click with this in the Configure cell;
[cell setDidTapButtonBlock:^(id sender) {
[self countNotes:cashoutLine.cashCurrency cell:cell];
}];
This calls this extract of code;
-(void)countNotes:(Currency *)cashCurrency cell:(PouchEntryViewCell *)cell
{
NotesCountViewController *notesCountVC = [[NotesCountViewController alloc] init];
notesCountVC.noteCurrency = cashCurrency;
notesCountVC.notesDelegate = self;
notesCountVC.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:notesCountVC animated:YES completion:nil];
}
All good and the new viewcontroller shows up.
I do the work there and pass back the total using delegate. It arrives happily in the first view controller, but then I'm stuck.
How can I get it to populate the correct cell?

Assuming you're presenting the calculator from the ViewController that acts as the UITableViewDataSource delegate, you can find the correct cell to update the textfield by creating a NSIndexPath property in your NotesCountViewController. Before you present the view controller, set the property. When it is dismissed, pass the NSIndexPath back to your UITableViewDataSource viewController, and find the correct cell with that.
-(void)countNotes:(Currency *)cashCurrency cell:(PouchEntryViewCell *)cell atIndex:(NSIndexPath *)indexPath
{
NotesCountViewController *notesCountVC = [[NotesCountViewController alloc] init];
notesCountVC.noteCurrency = cashCurrency;
notesCountVC.cellIndexPath = indexPath;
notesCountVC.notesDelegate = self;
notesCountVC.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:notesCountVC animated:YES completion:nil];
}
Then get the cell in the Delegate callback with
PouchEntryViewCell *cell = (PouchEntryViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
cell.textField.text = #"New Text";

In NotesCountViewController
- (id) initWithIndexPath:(NSIndexPath *) indexPath {
self = [super init];
if (self) {
self.indexPath = indexPath;
}
return self;
}
Declare this in your .h and also add an indexPath property.. Then just add the self.indexPath in your delegate call back.
To call it just do:
NotesCountViewController *notesCountViewController = [[NotesCountViewController alloc] initWithIndexPath:[self.tableView indexPathForCell:cell];
Then to retrieve the cell in the del callback:
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

Related

Reload data is not calling cellForRowAtIndexPath:

I've been banging my head against the wall since I thought I tried everything possible on stackoverflow.
So currently I am creating a table like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
NSLog(#"CHECK IF THIS IS CALLED");
static NSString *CellIdentifer = #"CellIdentifier";
CBPeripheral *placeHolder;
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifer];
// Using a cell identifier will allow your app to reuse cells as they come and go from the screen.
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifer];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
placeHolder = _connectedPeripherals[indexPath.row];
cell.textLabel.text = placeHolder.name;
}
return cell;
}
and I am calling [self.tableView reloadData] from another function that I call. I know it's getting called in that function, but cellForRowAtIndexPath does not get called again.
I created a UITableView property on my .h file
#property (strong, nonatomic) UITableView *tableView;
And created the table like this
self.tableView = [[UITableView alloc] init];
self.tableView.rowHeight = 60.0f;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
[self.view addSubview:self.tableView];
[self.view addConstraints:#[ [HTConstraints leftAlignView:self.tableView
toView:self.view
withSpacing:5],
[HTConstraints topAlignView:self.tableView
toView:self.view
withSpacing:5],
[HTConstraints rightAlignView:self.tableView
toView:self.view
withSpacing:5],
[HTConstraints bottomAlignView:self.tableView
toView:self.view
withSpacing:5],
]];
So far what I've tried was making sure that [self.tableView reloadData] was being called in the Main thread. Making sure my sections did not return 0.
Edit
This is my reloadData function and is called in another class
by [[RootViewController sharedInstance] reloadData]; and the log prints when I call it.
- (void)reloadData {
NSLog(#"Reloading");
[self.tableView reloadData];
}
set a break point inside -(void)reloadData or try to append the count of your UITableView datasource in your NSLog.
Usually cellForRowAtIndexPath is not getting call because it does not have anything to display.
I saw, in your code you forgot to add your tableView as a subView to the controller.
Add below code after your tableView's initialization
[self.view addSubview:tableView];

Passing value of labels in prepareforsegue

Using the prepareforsegue method, I need to pass the value of each label to the next viewcontroller class. I know I should pass the values in each cell as a single object to the next viewcontroller class, however I am not sure the best way to go about it.
In your next controller, you need to have a variable in the .h file that you can set. Then in prepareForSeque, you can do:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"detailSegue"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
NextViewController *dest = [segue destinationViewController];
NSArray* labels = [[NSArray alloc] initWithObjects: [cell viewWithTag:1], [cell viewWithTag:2], [cell viewWithTag:3], [cell viewWithTag:4], nil];
dest.labels = labels;
}
}
Then in your destination controller's initWithFrame, you can iterate each label and call: text:
for (UILabel* label in self.labels)
{
NSLog(#"%#", [label text]);
}
Don't pass anything. In prepareforSegue, create a reference of source view controller in DestinationVC (Example below)
[(DestinationVC *)segue.destinationViewController sourceVC] = self;
Then in DestinationVC, refer to tableview property of source view controller, run a loop to refer all the cells (example below)
for (NSUInteger i = 0; i < [self.tableView numberOfRowsInSection:0]; i++) {
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathWithIndex:i]];
//Refer to all subviews and see if they are UIlabel
}

Keeping (storing) View Controller content with Storyboard and SASlideMenu

I'm using the SASlideMenu library to implement a left slide menu in my iOS ARC storyboard app. I have added three View Controllers called with the [self performSegueWithIdentifier:#"segueID" sender:self]; code, and the slide menu works fine, but every time it create a NEW INSTANCE of a View Controller while I need to cache each controller content (example, in View Controller 1 we have a text field: If I write a word, after changing VC I must find again same word!). This is generic Storyboard:
This is my UITableView delegate, in SASlideMenuViewController:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:
UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
if (indexPath.row == 0) {
cell.textLabel.text = #"ViewController 1";
}
if (indexPath.row == 1) {
cell.textLabel.text = #"ViewController 2";
}
if (indexPath.row == 2) {
cell.textLabel.text = #"ViewController 3";
}
cell.textLabel.font = [UIFont systemFontOfSize:14];
cell.textLabel.textColor = [UIColor blackColor];
cell.imageView.image = [UIImage imageNamed:#"image.png"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.row==0)
{
[self performSegueWithIdentifier:#"segueID1" sender:self]; // I NEED TO RETRIEVE SAME VIEW CONTROLLER 1 CONTENT AFTER ANOTHER VIEW CONTROLLER CALL!
}
if(indexPath.row==1)
{
//[self performSegueWithIdentifier:#"segueID2" sender:nil]; // I NEED TO RETRIEVE SAME VIEW CONTROLLER 2 CONTENT AFTER ANOTHER VIEW CONTROLLER CALL!
}
if(indexPath.row==2)
{
//[self performSegueWithIdentifier:#"segueID3" sender:nil]; // I NEED TO RETRIEVE SAME VIEW CONTROLLER 3 CONTENT AFTER ANOTHER VIEW CONTROLLER CALL!
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
And this is a screenshot of slide menu in app:
In the author tutorial I can read: "If you are using dynamic cell prototype or you are using static cells and you want to cache the content view controller, assign an identifier that will be returned in the segueIdForIndexPath: method linked to the desired indexPath" but I'm losing my head and I cannot get the precise point.. please can u provide the precise code to resolve this? There is something else to add, but where? I need to reproduce this situation: EVERYTIME I call a View Controller from the left menu I MUST retrieve it identical as I have leaved before another previous VC call. Thanks!
In order to have your code working you need to implement two methods of the SASlideMenuDataSource protocol and you have to initialize the datasource property of your ViewController. Moreover you have to avoid to directly invoke performSegueWithIdentifier and you should avoid to implement tableView:didSelectRowAtIndexPath: method, because otherwise caching will not work.
The first method to implement is configureMenuButton:. You need it because you need the menu button in the content ViewController you are sliding in. One possibility is to copy the icons provided in the example project and add them to your project:
-(void) configureMenuButton:(UIButton *)menuButton{
menuButton.frame = CGRectMake(0, 0, 40, 29);
[menuButton setImage:[UIImage imageNamed:#"menuicon.png"] forState:UIControlStateNormal];
[menuButton setBackgroundImage:[UIImage imageNamed:#"menu.png"] forState:UIControlStateNormal];
[menuButton setBackgroundImage:[UIImage imageNamed:#"menuhighlighted.png"] forState:UIControlStateHighlighted];
[menuButton setAdjustsImageWhenHighlighted:NO];
[menuButton setAdjustsImageWhenDisabled:NO];
}
Than you need to implement segueIdForIndexPath:. The method returns the segueId associated to the indexPath of the row of the menu, looking at your code should be something like:
-(NSString*) segueIdForIndexPath:(NSIndexPath *)indexPath{
if(indexPath.row==0){
return #"vista1";
} else if (indexPath.row==1){
return #"vista2";
}else if(indexPath.row==2){
return #"vista3";
}
return #"vista1";
}
Finally you have to correctly initialize the dataSource property of your ViewController:
-(id) initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
self.slideMenuDataSource = self;
}
return self;
}
I hope you will find the answer useful.

how to make pushViewController: work in the following case?

I have a Navigation Controller embedded in a RootViewController. The elements present inside the RootViewController are a segmented control and a UIView. As the different segments are selected, the UIView displays a corresponding ViewController.
Now each of the ViewController being displayed in the UIView is a UITableViewController.
I need to display the table values as per the segment selections. And also if any of the row of the table is selected, it has to move to a newer ViewController with the detailed view.
I am able to display the UITableViewControllers as per the segment change. However, when i click on the row of the table, the newer ViewController that comes up is blank (Black Screen) even though I have created the particular ViewController in the Storyboard and set up an identifier as well.
Code for the Segmented Control change in ViewController.m
- (void)segmentedControlChangedValue:(UISegmentedControl*)segmentedControl {
int selIndex = segmentedControl.selectedIndex;
if (selIndex == 0)
{
aTable = [[aTableViewController alloc] init];
aTable.view.frame = self.myView.bounds;
[self.myView addSubview:aTable.view];
[self addChildViewController:aTable];
}
if (selIndex == 1)
{
bTable = [[bTableViewController alloc] init];
bTable.view.frame = self.myView.bounds;
[self.myView addSubview:bTable.view];
[self addChildViewController:bTable];
}
if (selIndex == 2)
{
//NSLog (#"Well you selected a 3rd option");
}}
Code for the didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
newDetailController* newController = [self.storyboard instantiateViewControllerWithIdentifier:#"Detail"];
newController = [[newDetailController alloc] init];
[[self navigationController] pushViewController:newController animated:YES];}
The pushViewController pushes an empty view for me even though I have specified the ViewController to use in the Storyboard design and also using an identifier.
Please help me in understanding what I must do to rectify this error.
UPDATE - The above problem has been resolved.
The problem I face now is being unable to access the data in the newViewController.
I pass the data to the newViewController as follows:
Create a class named newClass which contains all the elements I want to pass across.
Create a NSMutableArray "newObjects" in the firstViewController.
Create each newClass object at this method.
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *CellIdentifier = #"Cell";
customBigTableCell *cell = (customBigTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[customBigTableCell alloc] init];
}
cell.name.text = [object objectForKey:#"objName"];
newClass* newObj = [[newClass alloc] init];
newObj.objName = cell.name.text;
[newObjects addObject:newObj];
return cell;
}
Pls pardon me .. for the indenting with the code block is messed up...
Also the PFObject is cos i use Parse for database.
Add the created object to the newObjects array.
In the - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method, this is the code
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
newDetailController* newController = [storyboard instantiateViewControllerWithIdentifier:#"UpcomingDetail"];
obj = [[newClass alloc] init];
NSIndexPath* path = [self.tableView indexPathForSelectedRow];
obj = [newObjects objectAtIndex:path.row];
NSLog(#"Row selected is %ld", (long)path.row); //this returns the correct row selected
NSLog(#"Movie selected is %#", [[newObjects objectAtIndex:path.row] objName]);//however this is not the right one as per the cellForRowAtIndexPath method.
[newController setNewObj:obj];
[[self navigationController] pushViewController:newController animated:YES];
}
When I run this code, the row is selected correctly. However I dont get the corresponding row in the database. The array gets stored with redundant data.
You need to get rid of that middle line:
newController = [[newDetailController alloc] init];
That just redefines newController (as an empty controller with no view set up), which you defined in the first line.

Determining the state of a UISwitch when the UITableCell it is on is clicked

I a newb to IOS programming and I'm having a problem. I've got a table view that I dynamically load with a UISwitch in each cell using the following code in cellForRowAtIndexPath
UISwitch *mySwitch = [[UISwitch alloc]init];
self.myNewSwitch = mySwitch;
[mySwitch release];
[cell setAccessoryView: self.myNewSwitch];
[(UISwitch *)cell.accessoryView addTarget:self action:#selector(changeState:) forControlEvents:UIControlEventValueChanged];
That works fine. When I click on the switch, the code in changeState runs fine.
Here's where my problem is. When the user presses a cell in the table, I want to see what state the switch is in (On or Off). My problem is that I can not figure out how to determine that in the didSelectRowAtIndexPath code. I can determine the correct cell, but I couldn't find out how to access the switch that is on that cell when I searched using Google. Here's my code for didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//If the on/off switch is on, go to the probes page. if off, do not do anything
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//Determine the switch state here.
UISwitch *theSwitch;
theSwitch = ??????? //<- What do I do???
if (theSwitch.isOn) {
//define the probes view controller
Probes *detailViewController = [[Probes alloc] initWithNibName:#"Probes" bundle:nil];
//pass in the ip address
detailViewController.lblIPAddr = cell.detailTextLabel.text;
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
//Deselect this row
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Any help/code will be helpful.
-NCGrimbo
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//If the on/off switch is on, go to the probes page. if off, do not do anything
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//Determine the switch state here.
UISwitch *theSwitch = (UISwitch *)cell.accessoryView ;
if (theSwitch.isOn) {
//define the probes view controller
Probes *detailViewController = [[Probes alloc] initWithNibName:#"Probes" bundle:nil];
//pass in the ip address
detailViewController.lblIPAddr = cell.detailTextLabel.text;
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
//Deselect this row
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
but I don't know why you are using,
UISwitch *mySwitch = [[UISwitch alloc]init];
self.myNewSwitch = mySwitch;
[mySwitch release];
[cell setAccessoryView: self.myNewSwitch];
every time you make new UITableViewCell, self.myNewSwitch is same UISwitch (Last UiSwitch).

Resources