I have a UITableView with 3 sections that are hard coded. Everything is working fine, but I am not sure if I am doing it correctly.
Define number of rows in section:
- (NSInteger)tableView:(UITableView *)tblView numberOfRowsInSection:(NSInteger)section
{
NSInteger rows;
//Bio Section
if(section == 0){
rows = 2;
}
//Profile section
else if(section == 1){
rows = 5;
}
//Count section
else if(section == 2){
rows = 3;
}
}
return rows;
}
Here is where I build my cells:
- (UITableViewCell *)tableView:(UITableView *)tblView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tblView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.numberOfLines = 5;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:(10.0)];
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
if ([self.message_source isEqualToString:#"default"]) {
if (indexPath.section == 0) {
if (indexPath.row == 0) {
cell.textLabel.text = [Utils formatMessage:[NSString stringWithFormat: #"%#", mySTUser.bio]];
cell.detailTextLabel.text = nil;
}
else if(indexPath.row == 1){
cell.textLabel.text = [NSString stringWithFormat: #"%#", mySTUser.website];
cell.detailTextLabel.text = nil;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
} //more code exists, but you get the point...
Now I define my number of sections
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tblView
{
return 3;
}
Is this the proper way of hard-coding my UITableView? Will I run into any issues when cells are reused?
You might consider using a switch-case tree with an enumerated type, to replace the if conditionals that test for various hard-coded integers. This blog post explains this option in more detail. Using switch-case with your table view delegate methods will make your code much more readable and flexible. Otherwise, your reuse code looks correct.
Related
I have a UITableView that should have 33 rows. Each row represents a specific time slot in a day. When the view that holds the table view loads, I need it to populate each row accordingly.
I have an array of reservation objects that gets passed to the view. Each reservation contains a slot number, a reservation name and the duration of the reservation in slots.
What is the best way to populate the table, I am currently iterating through the array of reservations in the - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method.
This is not giving me the results or the behavior I am expecting. The performance is extremly poor as it keeps iterating through loops and cells that shouldn't be blue are blue after scrolling. What is the best way to approach this? I have included the code below.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 33;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSString *timeStamp = [NSString stringWithFormat:#"%.2f", (indexPath.row + 14.0 ) / 2.0];
timeStamp = [timeStamp stringByReplacingOccurrencesOfString:#".50" withString:#":30"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"%#: ", timeStamp];
for (Reservation *temp in bookingsArray) {
if ((temp.slotNumber - 1) == indexPath.row) {
cell.textLabel.text = [NSString stringWithFormat:#"%#: %#", timeStamp, temp.reservationName];
cell.contentView.backgroundColor = [UIColor blueColor];
}
for (NSNumber *tempNo in temp.slotIdentifiers) {
if ([tempNo intValue] -1 == indexPath.row) {
//cell.textLabel.text = [NSString stringWithFormat:#"%#: Booked", timeStamp];
cell.contentView.backgroundColor = [UIColor blueColor];
}
}
}
return cell;
}
UPDATE
Trying the following gives me strange behaviour where all the cells turn blue after I start scrolling.
- (void)viewDidLoad
{
[super viewDidLoad];
bookManager = appDelegate.bookingManager;
bookingsArray = [[NSArray alloc] initWithArray:[bookManager getBookingsForCourt:1 onDate:[NSDate date]]];
namesArray = [[NSMutableDictionary alloc] init];
slotIndexSet = [NSMutableIndexSet indexSet];
for (int c = 0; c < 33; c++) {
[namesArray setObject:#"Available" forKey:[NSNumber numberWithInt:c]];
}
for (Reservation *temp in bookingsArray) {
[namesArray setObject:temp.reservationName forKey:[NSNumber numberWithInt:temp.slotNumber]];
for (NSNumber *slotNo in temp.slotIdentifiers) {
[slotIndexSet addIndex:[slotNo intValue] + 1];
}
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSString *timeStamp = [NSString stringWithFormat:#"%.2f", (indexPath.row + 14.0 ) / 2.0];
timeStamp = [timeStamp stringByReplacingOccurrencesOfString:#".50" withString:#":30"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"%#: ", timeStamp];
cell.textLabel.text = [namesArray objectForKey:[NSNumber numberWithInt:indexPath.row]];
if ([slotIndexSet containsIndex:indexPath.row]) {
cell.contentView.backgroundColor = [UIColor blueColor];
}
return cell;
}
You need to do two things to speed this up:
Convert bookingsArray to a bookingBySlotNumber array in such a way that the object at index i has slotNumber - 1 equal to i. You can do it by iterating over the original bookings array when you receive it.
Create a NSIndexSet called isBookedBySlotNumber containing indexes of items that have been booked. You can prepare it by going through all Reservation.slotIdentifiers, and marking the indexes of isBookedBySlotNumber for items that have been booked.
With these two pre-processed items in place, you can eliminate the nested loops altogether: the outer one will be replaced by a lookup in bookingBySlotNumber, and the inner one - by a loopup in isBookedBySlotNumber.
I have a tableview which has a list of options the user has selcected( It is an edit page ).
the tableview looks as below
Apple UITableViewCellAccessoryCheckmark
Orange UITableViewCellAccessoryNone
Pineapple UITableViewCellAccessoryCheckmark Banana
UITableViewCellAccessoryNone
- (void)viewDidLoad {
self.mySavedFruitsArray = [myDBOperations getMyFruitsList:[appDelegate getDBPath]:self.myId];
}
/ Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
//-------------------------------------------------------------------------------
{
static NSString *CellIdentifier = #"PoemTypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"MyIdentifier"]autorelease];
}
NSDictionary *aDict = [self.myFruitsArr objectAtIndex:indexPath.row];
NSString *aValue = [aDict objectForKey:#"value"];
NSString *aId = [aDict objectForKey:#"key"];
cell.textLabel.text = aValue;
cell.accessoryType = UITableViewCellAccessoryNone;
NSDictionary *aSavedDict = [self.mySavedFruitsArray objectAtIndex:indexPath.row];
NSString *Value = [aSavedDict objectForKey:#"value"];
NSString *Id = [aSavedDict objectForKey:#"key"];
if ( aId == Id ){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
mySavedFruitsArray - it holds the user selected fruits.
myFruitsArr - this has common list of fruits
now i would like to know how to display UITableViewCellAccessoryCheckmark for cell which matches with mySavedFruitsArray.
I mean , in this edit view i want to display the fruits list with user selected option.
Pls let me know how to do that.
I tried like this, but no use.
/ Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
//-------------------------------------------------------------------------------
{
static NSString *CellIdentifier = #"PoemTypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"MyIdentifier"]autorelease];
}
NSDictionary *aDict = [self.myFruitsArr objectAtIndex:indexPath.row];
NSString *aValue = [aDict objectForKey:#"value"];
NSString *aId = [aDict objectForKey:#"key"];
cell.textLabel.text = aValue;
cell.accessoryType = UITableViewCellAccessoryNone;
NSDictionary *aSavedDict = [self.mySavedFruitsArray objectAtIndex:indexPath.row];
NSString *Value = [aSavedDict objectForKey:#"value"];
NSString *Id = [aSavedDict objectForKey:#"key"];
if ( aId == Id ){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
pls note self.mySavedFruitsArray may not be equal to myFruitsArr always ( because user may select only one fruit).
if ( aId == Id ){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
string comparison is wrong. You should compare strings this way:
if([aId isEqualToString:Id]) {
....
}
instead of checking if ( aId == Id ) which compares the strings as identical objects,
use if ([aID isEqualToString:Id]) which compares strings
In a version downloaded yesterday (6/8/14), UITableViewCellAccessoryCheckmark and UITableViewCellAccessoryNone is not valid. It was throwing compiler errors for me. I think you are supposed to use it as an enum, like so:
if item.completed {
cell!.accessoryType = UITableViewCellAccessoryType.Checkmark
} else {
cell!.accessoryType = UITableViewCellAccessoryType.None
}
With this change, my code compiles and the behavior appears in the simulator.
Sorry I don't know which version to look up (UIKit?), I'm new to iOS development.
I have a UITableView that I'm using to try and display 2 different objects - receipts and milages.
This is the original code I was using to try and accomplish this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Project *project = [[Project alloc] init];
project = [appDelegate.projects objectAtIndex:indexPath.section];
if (indexPath.row >= [project.receipts count])
{
if (indexPath.row >= [project.milages count]){
return NULL;
}
else {
//Create a new journey cell and set its UI values
MilageCell *cell = (MilageCell *)[tableView
dequeueReusableCellWithIdentifier:#"MilageCell"];
Milage *milage = [project.milages objectAtIndex:indexPath.row];
cell.locationLabel.text = milage.location;
cell.dateLabel.text = [NSString stringWithFormat:#"%#", milage.date];
cell.totalLabel.text = [NSString stringWithFormat:#"£%#", milage.total];
return cell;
}
}
else
{
ReceiptCell *cell = (ReceiptCell *)[tableView
dequeueReusableCellWithIdentifier:#"ReceiptCell"];
Receipt *receipt = [project.receipts objectAtIndex:indexPath.row];
cell.dateLabel.text = receipt.receiptDate;
cell.descriptionLabel.text = receipt.descriptionNote;
cell.amountLabel.text = [NSString stringWithFormat:#"£%#", receipt.amount];
return cell;
}
}
I'm aware that if I have 1 object in each of the arrays (project.receipts and project.milages) then this code won't work at all. I also know you can't return NULL from this method. What I'm trying to do is somehow display all my receipt objects, then all my milage objects (so say section 0 in the table view had 3 receipts and 3 milages, it would firstly display the receipts, then the milages). However I have absolutely no idea how to do this, can someone explain how I might solve this problem? Is there some way I could construct a single array of all the milage and receipt objects and then somehow discern which what kind of object I have in this method in order to use the appropriate cell type?
Thanks a lot,
Jack
Try this, I've just removed an if condition and subtracted the [project.milages count] from the index.row for the Receipt cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Project *project = [[Project alloc] init];
project = [appDelegate.projects objectAtIndex:indexPath.section];
if (indexPath.row >= [project.milages count]){
ReceiptCell *cell = (ReceiptCell *)[tableView
dequeueReusableCellWithIdentifier:#"ReceiptCell"];
Receipt *receipt = [project.receipts objectAtIndex:indexPath.row-[project.milages count]];
cell.dateLabel.text = receipt.receiptDate;
cell.descriptionLabel.text = receipt.descriptionNote;
cell.amountLabel.text = [NSString stringWithFormat:#"£%#", receipt.amount];
return cell;
}
else {
//Create a new journey cell and set its UI values
MilageCell *cell = (MilageCell *)[tableView
dequeueReusableCellWithIdentifier:#"MilageCell"];
Milage *milage = [project.milages objectAtIndex:indexPath.row];
cell.locationLabel.text = milage.location;
cell.dateLabel.text = [NSString stringWithFormat:#"%#", milage.date];
cell.totalLabel.text = [NSString stringWithFormat:#"£%#", milage.total];
return cell;
}
}
You can also use an UITableView with two different sections.
I want two create 2 sections uitableview
so I did the following code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#" I entered numberOfSectionsInTableView");
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section = 0 ) {
1;
}
else {
9;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSLog(#" I entered cellForRowAtIndexPath");
NSLog(#"the Caf files count is : %d",[self.CafFileList count] );
NSLog(#" the txt file %d",[self.TXTFileList count] );
if (indexPath.section == 0 ) { // Enter here twice , even I say it contain only one row
NSLog(#"////////////////////////Section 0 %d" , [indexPath row] );
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[[cell textLabel] setText:[self.TXTFileList objectAtIndex:[indexPath row] ] ];
return cell;
}
else if (indexPath.section == 0 && indexPath.row < [self.TXTFileList count] ){
NSLog(#"////////////////////////Section 1 %d" , [indexPath row] );
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[[cell textLabel] setText:[self.CafFileList objectAtIndex:[indexPath row]] ];
return cell;
}
}
the problem is that it Enter here twice , even I say it contain only one row
if (indexPath.section == 0 ) {
any idea how to solve that
You don't return row numbers in numberOfRowsInSection, you just enter a number, but return nothing.
Also,
if (section = 0 ) {
sets section to 0, you want to use the == operator.
if (section == 0 ) {
return 1;
}
else {
return 9;
}
Also your code:
else if (indexPath.section == 0 && indexPath.row < [self.TXTFileList count] ){
You never generate cell for section == 1. seem will crash or wrong reusing cell
I have displayed the datas in grouped table view. The data's are displayed in the table view from XML parsing. I have 2 section of the table view, the section one has three rows and section two has two rows.
section 1 -> 3 Rows
section 2 - > 2 Rows.
Now i want to check, if anyone of the string is empty then i should remove the empty cells, so i have faced some problems, if i have removed any empty cell, then it will changed the index number. So how can i check, anyone of the field is empty?, Because some times more number of empty field will come, so that the index position will be change. So please send me any sample code or link for that? How can i achieve this?
Sample code,
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) {
if([userEmail isEqualToString:#" "] || [phoneNumber isEqualToString:#" "] || [firstName isEqualToString:#" "])
{
return 2;
}
else {
return 3;
}
}
if (section == 1) {
if(![gradYear isEqualToString:#" "] || ![graduate isEqualToString:#" "]) {
return 1;
}
else
{
return 2;
}
return 0;
}
Please Help me out!!!
Thanks.
As per my understanding, you dont want to add the row where data is empty, so ill suggest you should perpare the sections data before telling the table view about the sections and rows.
So, may be following code can help you..., i have tested it you just need to call the method "prepareSectionData" from "viewDidLoad" method and define the section arrays in .h file.
- (void) prepareSectionData {
NSString *userEmail = #"";
NSString *phoneNumber = #"";
NSString *firstName = #"";
NSString *gradYear = #"";
NSString *graduate = #"";
sectionOneArray = [[NSMutableArray alloc] init];
[self isEmpty:userEmail]?:[sectionOneArray addObject:userEmail];
[self isEmpty:phoneNumber]?:[sectionOneArray addObject:phoneNumber];
[self isEmpty:firstName]?:[sectionOneArray addObject:firstName];
sectionTwoArray = [[NSMutableArray alloc] init];
[self isEmpty:gradYear]?:[sectionTwoArray addObject:gradYear];
[self isEmpty:graduate]?:[sectionTwoArray addObject:graduate];
}
-(BOOL) isEmpty :(NSString*)str{
if(str == nil || [[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0)
return YES;
return NO;
}
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(section == 0){
return [sectionOneArray count];
} else if (section == 1) {
return [sectionTwoArray count];
}
return 0;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
if(indexPath.section == 0){
cell.textLabel.text = [sectionOneArray objectAtIndex:indexPath.row];
} else if (indexPath.section == 1) {
cell.textLabel.text = [sectionTwoArray objectAtIndex:indexPath.row];
}
return cell;
}
#Pugal Devan,
Well, you can keep the data in one array, but the problem in that case is, you have to take care of array bounds and correct indexes for different sections. For each section indexPath.row will start from index 0, and if your data is in single array, you have to manage the row index by your self. But still if you want to keep it, you can do like:
int sectionOneIndex = 0;
int sectionTwoIndex = 3;
NSMutableArray *sectionArray = [[NSMutableArray alloc] initWithObjects:#"email", #"Name", #"address", #"zipCode", #"country", nil];
Above two integers represents the starting position of elements of your different sections. First 3 objects from the section Array are the part of section One, and last two objects are the part of section two. Now you need to return correct row count.
For that you may write:
if(section == 0) return [sectionArray count] - (sectionTwoIndex-1); //returns 3
else if(section == 1) return [sectionArray count] - sectionTwoIndex; //returns 2
OR if your count is static you may put constant values in return.
And at the time you read from array, you will just add this index in row value, which will return the correct position of your element for the current cell.
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
if(indexPath.section == 0){
cell.textLabel.text = [sectionArray objectAtIndex:indexPath.row + sectionOneIndex];
} else if (indexPath.section == 1) {
cell.textLabel.text = [sectionArray objectAtIndex:indexPath.row + sectionTwoIndex];
}
return cell;
}