Modifying a NSMutableArray from a TableCell - ios

I have a TableView (named myTableView) that contains prototype cells (named: TableCell) inside a ViewController (not TableViewController, named: ViewController).
Each cell has 4 different textfields that display data from different NSMutableArrays (declared in ViewController.h and named: Legajos, Nombres, Cbus, Sueldos, Contribuciones), so for example the cell at row 0 will display the objects at index 0 from Legajos, Nombres, etc... All of this is working, I am even able to add and delete rows with no problem.
Now my problem. I have textfields (declared TableCell.h) that display text from NSMutableArrays (declared in ViewController.h), but I was only able to make it a "one way trip", that is to say, the textfields only show text from the NSMutableArrays but I also need them to modify the NSMutableArray so I can save that array and then load it.
The NSMutableArrays declaration: (ViewController.h)
#property (strong, nonatomic) NSMutableArray *Legajos;
#property (strong, nonatomic) NSMutableArray *Nombres;
#property (strong, nonatomic) NSMutableArray *Cbus;
#property (strong, nonatomic) NSMutableArray *Sueldos;
#property (strong, nonatomic) NSMutableArray *Contribuciones;
Here is how the cells get their text: (ViewController.m)
cell.legajo.text = [Legajos objectAtIndex:indexPath.row];
cell.nombre.text = [Nombres objectAtIndex:indexPath.row];
cell.cbu.text = [Cbus objectAtIndex:indexPath.row];
cell.sueldo.text = [Sueldos objectAtIndex:indexPath.row];
cell.contribucion.text = [Contribuciones objectAtIndex:indexPath.row];
And this are the IBOutlets of the cells: (TableCells.h)
#property (strong, nonatomic) IBOutlet UILabel *legajo;
#property (strong, nonatomic) IBOutlet UITextField *nombre;
#property (strong, nonatomic) IBOutlet UITextField *cbu;
#property (strong, nonatomic) IBOutlet UITextField *sueldo;
#property (strong, nonatomic) IBOutlet UITextField *contribucion;
Sorry if its hard to understand. Thanks for any help given.

Easieast way would probably be to add (void) textFieldDidEndEditing:(UITextField *)textField method to your UITextField delegate. You can either assign a tag to each UITextField upon creation so you know which array to edit or I believe NSIndexPath *indexPath = [self.tableView indexPathForCell:(CustomCell*)[[textField superview] superview]];might do the trick.
(void) textFieldDidEndEditing:(UITextField *)textField {
NSIndexPath *indexPath = [self.tableView indexPathForCell:(CustomCell*)[[textField superview] superview]];
switch(indexPath.section)
{
case '0':
// edit object in first array at index indexPath.row
[firstArray replaceObjectAtIndex:indexPath.row withObject:textField.text];
break;
case '1':
// edit object in second array at index indexPath.row
[secondArray replaceObjectAtIndex:indexPath.row withObject:textField.text];
break;
case '2':
// edit object in third array at index indexPath.row
[thirdArray replaceObjectAtIndex:indexPath.row withObject:textField.text];
break;
case '3':
// edit object in fourth array at index indexPath.row
[fourthArray replaceObjectAtIndex:indexPath.row withObject:textField.text];
break;
case '0':
// edit object in fifth array at index indexPath.row
[fifthArray replaceObjectAtIndex:indexPath.row withObject:textField.text];
break;
default :
}
}
Here is a quick example I've typed up.

Related

Autolayout labels with UIView and Labels inside UIView

I am new to the autolayout thing, was trying to design the given screen for Compact Width|Regular Height via Storyboard. It seems Very simple cause there is none dynamic fields. I was following apple documentation, and setting constraints for each UIView. Its working fine if there would be no View(shown in purple color). But there is some requirement(have to hide the View based on star rating), thats why added this UIView containing dispatch details, complaint category, screenshot etc. e.g- For Invoice Number I set Top Space,Leading Space, Trailing Space and for the label(shown in green color) Top Space, Leading Space, Trailing Space so that height of invoice Number wouldn't be ambiguous rep, Repeated same for all Views. UIView(purple) constraints are Trailing Space to:SuperView, Bottom space to:SuperView, Bottom space to:Remarks Equals:15, Top Space Equals to:StarRating Equals:8. After that I have added constraints for the fields inside the purple View same as the other Views like Invoice Number. But not getting the desired result for different screen size. Any help would be much appreciated.
Use a UITableView to lay out this screen. You can use a static content table view, laid out entirely in the storyboard. Make the purple part its own section. In your UITableViewController subclass, you don't need to implement most data source / delegate methods (because you're using static content). Just override tableView:numberOfRowsInSection: to return 0 for the optional section if you don't want to show it, and use -[UITableView reloadSections:withRowAnimation;] to update the table view. Here's my test code:
#import "ViewController.h"
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UITableViewCell *topMarginCell;
#property (strong, nonatomic) IBOutlet UIButton *star1;
#property (strong, nonatomic) IBOutlet UIButton *star2;
#property (strong, nonatomic) IBOutlet UIButton *star3;
#property (strong, nonatomic) IBOutlet UIButton *star4;
#property (strong, nonatomic) IBOutlet UIButton *star5;
#property (strong, nonatomic) NSArray<UIButton *> *starButtons;
#property (nonatomic) NSInteger rating;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.starButtons = #[ self.star1, self.star2, self.star3, self.star4, self.star5 ];
self.tableView.backgroundColor = self.topMarginCell.backgroundColor;
}
- (void)reloadDispatchSection {
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
}
- (IBAction)starButtonWasTapped:(UIButton *)button {
NSInteger buttonIndex = [self.starButtons indexOfObject:button];
if (buttonIndex == NSNotFound) { return; }
self.rating = buttonIndex + 1;
[self.starButtons enumerateObjectsUsingBlock:^(UIButton * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj setTitle:(idx <= buttonIndex ? #"★" : #"☆") forState:UIControlStateNormal];
}];
[self reloadDispatchSection];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 1 && (self.rating == 0 || self.rating >= 4)) {
return 0;
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
#end
Result:

UILabel displaying (null) in custom UItableviewcell

I can't figure out why my UILabels in my custom TableViewCell are nil in CellForRowAtIndexPath. I used the same method as I did for a previous TableView in another view Controller. Here's what I already checked:
Cell Style is Custom
Cell has a unique identifier "profilecell"
Cell's class is of the desired custom type
data source and delegated are connected to the View Controller
Each of the 5 buttons/labels is connected to its respective property in the custom class
Dynamic Prototypes is selected
I am able to change the background color of the cell and populate the textLabel.text -- it's just my UILabels that aren't filled.
Here is CellForRowAtIndexPath. It's the exact same method as my other TableVC, which works. Also, I don't need to actually reuse this custom cell, should I be using a different method?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifierProfile = #"profilecell";
ProfileSection0TableViewCell *profilecell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierProfile];
if (profilecell == nil) {
profilecell = [[ProfileSection0TableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifierProfile];
}
if (indexPath.section == 0) {
[profilecell setBackgroundColor:[UIColor colorWithRed:54/255.0f green:61/255.0f blue:147/255.0f alpha:1.0f]];
if (indexPath.row == 0) {
profilecell.labelName.text = _userProfile.fullName;
NSString *test = [NSString stringWithFormat:#"%#", profilecell.labelName.text];
NSLog(#"text %#", test); //shows that label is (null)
profilecell.labelName.textColor = [UIColor whiteColor];
//profilecell.labelSpecialty.text = _userProfile.specialty;
//profilecell.labelSpecialty.textColor = [UIColor whiteColor];
}
}
return profilecell;
}
Thanks so much in advance.
.h file:
#interface ProfileSection0TableViewCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel* labelName;
#property (nonatomic, weak) IBOutlet UILabel* labelSpecialty;
#property (nonatomic, weak ) IBOutlet UILabel* labelCurrentRole;
#property (nonatomic, weak) IBOutlet UILabel* labelPosition;
#property (nonatomic, weak) IBOutlet UIButton* facePicture;
#end
.m file:
#implementation ProfileSection0TableViewCell
#synthesize labelName, labelSpecialty, labelPosition, facePicture, labelCurrentRole;
#end
EDIT:
It looks like ProfileSection0TableViewCell is allocated properly, but the member vars inside the cell are nil. And in outlets, here are the connections:
facePicture - Button
labelName- UILabel "person"
labelPosition - UILabel "position"
List item - UILabel "specialty"
labelCurrentRole - UILabel titled school
Either _userProfile.fullName is nil or profilecell.labelName is nil
If you made the cell in interface builder, did you hook up the outlet to labelName correctly?

How to pass indexPath from button inside footer to segue?

I'm working on a custom layout collectionView which has quilt look and each section has a footer. Two buttons are inside footer and each button has a segue to another view(I set segues using IB).
Footer has its own indexPath which was assigned in a UICollectionViewFlowLayout class(Where I made a custom layout). The indexPath of footer is like this - {section - row} {0-0} {1-0} {2-0}....
I want to keep this indexPath information to use at the another view which is linked to two buttons.
I tried "convertPoint: toView: ... indexPathForRowAtPoint" way but didn't work. I think it's because the buttons are not belong to collectionViewItem but belong to Footer.
In this situation, what is the best way of passing each footerView's indexPath to segue?
Any solution with code example will be greatly appreciated.
// CollectionView DataSource
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath {
Footer *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter
withReuseIdentifier:#"Footer"
forIndexPath:indexPath];
// set button images and labels
[footerview setButton];
// debug code : show current section number
footerview.footerLabel.text = [NSString stringWithFormat:#"Section %li", (long)indexPath.section];
return footerview;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"SeeAllPictures"]) {
// how to pass indextPath?
}
else if([[segue identifier] isEqualToString:#"GoDiary"]) {
// how to pass indextPath?
}
}
Below is header of Footer class
#import <UIKit/UIKit.h>
#interface Footer : UICollectionReusableView
#property (strong, nonatomic) IBOutlet UILabel *footerLabel;
#property (strong, nonatomic) IBOutlet UIButton *seeAllPictures;
#property (strong, nonatomic) IBOutlet UIButton *goDiary;
#property (strong, nonatomic) IBOutlet UIImageView *seeAllPicturesImage;
#property (strong, nonatomic) IBOutlet UILabel *seeAllPicturesLabel;
#property (strong, nonatomic) IBOutlet UIImageView *goDiaryImage;
#property (strong, nonatomic) IBOutlet UILabel *goDiaryLabel;
- (void)setButton;
#end
try the following:
imagine a reusable view with two buttons (leftButton and rightButton). in your reusable view classes .h file add a property for the indexpath:
#property (strong, nonatomic) NSIndexPath *indexPath;
then in your viewcontrollers viewForSupplementaryElementOfKind method:
CustomFooterView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"FooterView" forIndexPath:indexPath];
footerView.indexPath = indexPath;
[footerView.leftButton addTarget:self action:#selector(leftButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[footerView.rightButton addTarget:self action:#selector(rightButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
then implement the two methods:
- (void)leftButtonTapped:(UIButton *)sender {
[self performSegueWithIdentifier:#"LeftButtonSegue" sender:sender];
}
- (void)rightButtonTapped:(UIButton *)sender {
[self performSegueWithIdentifier:#"RightButtonSegue" sender:sender];
}
and finally in your viewcontrollers prepareForSegue method:
CustomFooterView *footerView = (CustomFooterView *)((UIButton *)sender).superview;
NSLog(#"perform segue from indexpath %ld, %ld", (long) footerView.indexPath.section, (long) footerView.indexPath.row);
IMPORTANT
the buttons have to be direct childs of the reusable view to make
(CustomFooterView *)((UIButton *)sender).superview
work. and of course you have to connect the segues LeftButtonSegue and RightButtonSegue in storyboard.

Prototype cell won't show content

I have designed a cell in storyboard, then created a custom UITableViewCell subclass (BasicCell) and assigned it to it. Also set the proper identifiers. I created outlets of the custom cell in that class. Then in my UITableViewController subclass (where I have two types of prototype cells), the cells content won't show up. What am I doing wrong?
BasicCell.h
#interface BasicCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *scorevalue;
#property (strong, nonatomic) IBOutlet UILabel *avgvalue;
#property (strong, nonatomic) IBOutlet UILabel *rankvalue;
#property (strong, nonatomic) IBOutlet UILabel *scorelabel;
#property (strong, nonatomic) IBOutlet UILabel *categorylabel;
#property (strong, nonatomic) IBOutlet UILabel *ranklabel;
#end
TableViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifierBasic = #"basic";
static NSString *CellIdentifierDetailed = #"detailed";
UITableViewCell *cell;
if(indexPath.row==0){
// Create first cell
cell = [[BasicCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifierBasic];
}
else{
// Create all others
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierDetailed forIndexPath:indexPath];
}
// Configure the cell...
switch ([indexPath row])
{
case 0:
{
BasicCell *basicCell = (BasicCell *)cell;
basicCell.scorelabel.text = #"test";
basicCell.categorylabel.text = #"test";
basicCell.ranklabel.text = #"test";
basicCell.scorevalue.text = #"test";
basicCell.avgvalue.text = #"test";
basicCell.rankvalue.text = #"test";
}
}
In your storyboard,
Create two prototype cell.
Change one of your prototype cell's custom class. Set it BasicCell.
Make sure that you set appropriate cell identifier for each type of cell.
Don't alloc init if it's indexPath.row == 0 but dequeue with appropriate identifier.
It should work.
Note: You should declare your IBOutlets as weak not as strong. Cell's view has already strong pointer to them. You don't have to own them.

How to get the multiple selected CollectionViewCell from the UICollectionView?

I create a xib file and add a Collection View Cell. I add the progress bar in header file of cell like the following code.
#import <UIKit/UIKit.h>
#import "MobileVLCKit/VLCMediaThumbnailer.h"
#interface AITFileCell_grid : UICollectionViewCell <VLCMediaThumbnailerDelegate>
#property (strong, nonatomic) IBOutlet UIImageView *fileIcon;
#property (strong, nonatomic) IBOutlet UILabel *fileName;
#property (strong, nonatomic) IBOutlet UILabel *fileSize;
#property (strong, nonatomic) NSURL *filePath ;
+ (NSString *)reuseIdentifier ;
#end
#interface AITFileCell_grid()
{
BOOL fetching ;
#public
UIProgressView *dlProgress;
UILabel *dlProgressLabel;
}
#end
I also create another xib file and add the Collection View for loading Collection View Cell.
I want to selected multiple file and hide the progress bar on each cell by button.
But I can not get the cell when I click the delete button by following code.
- (IBAction) buttonCancel:(id)sender {
if(self.collectionView.indexPathsForSelectedItems > 0){
for(NSIndexPath *indexPath in self.collectionView.indexPathsForSelectedItems){
AITFileCell_grid *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"AITFileCell_grid" forIndexPath:indexPath];
//Hide the progress bar
cell->dlProgressLabel.text = #"0%";
cell->dlProgress.hidden = YES;
cell->dlProgressLabel.hidden = YES;
}
}
[self setEditing:NO animated:YES];
}
I set the breakpoint to the cell->dlProgressLabel.text = #"0%"; , it show the nil in the log...and the progress bar didn't change anything.
But I can set the value to cell->dlProgressLabel.text and set value to cell->dlProgress in NSTimer.
Why the cell define in the UIButton seems not be efficient ?...
Can someone help and teach me how to solve ?
You are dequeuing Cell by doing
AITFileCell_grid *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:#"AITFileCell_grid" forIndexPath:indexPath];
which could be different from what you have been selected, instead get the selected cell from the collectionView
AITFileCell_grid *cell = [self.collectionView cellForItemAtIndexPath: indexPath]

Resources