How to reload data from a specific NSMutableArray into a UITableView - ios

Hi I'm using a web service that returns a JSON document. In that document are several objects, each one containing a value for "STATE" (among others like "ADDRESS", "DISTANCE",etc). This "STATE" value can be either "ARCHIVED" or "ACTIVE". What I want to do is to load the objects with "ARCHIVED" value of "STATE" into the archivedProcessTV and the others to activeProcessTV.
I managed to fill both mutable arrays with the desired data but when the TableViews reload, they reload all the objects into the cells.
Here is what I'm doing on connectionDidFinishLoading:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Entrou no connectionDidFinishLoading");
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
process = [[NSJSONSerialization JSONObjectWithData:data options:0 error:nil] objectForKey:#"GetGesturbeDataJsonResult"];
NSInteger i = 0;
archived = [[NSMutableArray alloc] init];
active = [[NSMutableArray alloc] init];
for (NSObject *array1 in process) {
while (i <= process.count) {
if([[[process objectAtIndex:i] objectForKey:#"STATE" ] isEqualToString:#"ARCHIVED"])
{
[archived addObject:[process objectAtIndex:i]];
i++;
}else
[active addObject:[process objectAtIndex:i]];
i++;
}
}
[activeProcessTV reloadData];
[archivedProcessTV reloadData];
}
Thanks for your help!
EDIT:
-(UITableViewCell *)tableView:(UITableView *)atableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
cell.textLabel.text = [[process objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"];
return cell;
}

You appear to have 2 problems:
tableView:cellForRowAtIndexPath: does not check which table view is asking for data
You don't use your specific array contents to populate the table views, you use [[process objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"]; which contains all data
So, at the start of tableView:cellForRowAtIndexPath: you should have an if statement which checks the atableView parameter and decides which array to use. Then, edit the line which updates the cell text to use that array.
- (UITableViewCell *)tableView:(UITableView *)atableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *sourceArray;
if (atableView == self.activeProcessTV) {
sourceArray = self.active;
} else {
sourceArray = self.archived;
}
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
}
cell.textLabel.text = [[sourceArray objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"];
return cell;
}
Aside: this code:
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
needs to be changed to:
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
}
as currently you're always creating a new cell even if you did get a reusable one back...

In-spite of using sourcearray just pass like that below and check:-
-(UITableViewCell *)tableView:(UITableView *)atableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [atableView dequeueReusableCellWithIdentifier:#"a cell"];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"a cell"];
}
if ( atableView ==self.activeProcessTV) {
cell.textLabel.text = [[self.activeProcessTV objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"];
}
else{
cell.textLabel.text = [[self.archived objectAtIndex:indexPath.row] objectForKey:#"DISTANCE"];
}
return cell;
}
Note: Pass the correct array count inside numberOfRowsInSection method of UITableView.

Related

Modifying one cell in CellForRowAtIndexPath changes multiple cells

I have an array of names that I'm showing via tableview. You can select up to a total of 3 names, and you cannot re-select the same names. To do this I implemented the following code in cellForRowAtIndexPath:. When I run the code the names come up fine, but there are multiple red cells with names that I did not select.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSString *sectionTitle = [nameSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionNames = [names objectForKey:sectionTitle];
NSString *name = [sectionNames objectAtIndex:indexPath.row];
cell.textLabel.text = name;
if ([name isEqualToString: self.name1] || [name isEqualToString: self.name2] || [name isEqualToString: self.name3]) {
[cell setUserInteractionEnabled:NO];
cell.backgroundColor = [UIColor redColor];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Reading a similar problem here, they were saying that it's because the cells are being reused - but if this were true, how is the tableview still displaying the correct names in the correct position?
I tried to simplify the code into this, and still to no avail, there were multiple red cells.
myIP = [NSIndexPath indexPathForRow:0 inSection:0];
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TableCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSString *sectionTitle = [nameSectionTitles objectAtIndex:indexPath.section];
NSArray *sectionNames = [names objectForKey:sectionTitle];
NSString *name = [sectionNames objectAtIndex:indexPath.row];
cell.textLabel.text = name;
if (indexPath == myIP) {
cell.backgroundColor = [UIColor redColor];
}
return cell;
}
I can post a screenshot if needed. Note: The intended names were correctly labeled with red.
The issue is happening due to cell re-using. When a cell with red background is re-used it'll still be in red background, you are not re-setting it anywhere in your code. You need to put a else case to your if condition used in cellForRowAtIndexPath: method.
if ([name isEqualToString: self.name1] || [name isEqualToString: self.name2] || [name isEqualToString: self.name3])
{
[cell setUserInteractionEnabled:NO];
cell.backgroundColor = [UIColor redColor];
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
[cell setUserInteractionEnabled:YES];
cell.backgroundColor = [UIColor clearColor];
// Other stuffs
}

UITableView inside UIView - data loads only when scrolling cells outside uitableview

I have a problem using a UITableView inside a UIViewController:
When I start the app the UITableView is shown, but the data from _opponents isn't shown.
When I start scrolling the first cell outside the UITableView, now this cell gets updated.
Also, when I trigger [_topponents reloaddata] manually, the whole UITableView shows the correct data.
What do I have to add or change, so that the data is shown from the beginning?
dataSource and delegate are both connected with the class in the storyboard
Here is my code:
viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
myappdel = (AppDelegate *)[UIApplication sharedApplication].delegate;
self.title = #"New Match";
_lopponent.text = _opponent;
opponents = [[NSMutableArray alloc] init];
NSMutableDictionary *opponent = [[NSMutableDictionary alloc] init];
[opponent setObject:#"opponent A" forKey:#"name"];
[opponent setObject:#"xx matches | xx wins || xx losts" forKey:#"stats"];
[opponent setObject:#"Krems" forKey:#"location"];
NSMutableDictionary *opponent2 = [[NSMutableDictionary alloc] init];
[opponent2 setObject:#"opponent B" forKey:#"name"];
[opponent2 setObject:#"yy matches | yy wins || yy losts" forKey:#"stats"];
[opponent2 setObject:#"Location B" forKey:#"location"];
NSMutableDictionary *opponent3 = [[NSMutableDictionary alloc] init];
[opponent3 setObject:#"opponent C" forKey:#"name"];
[opponent3 setObject:#"zz matches | zz wins || zz losts" forKey:#"stats"];
[opponent3 setObject:#"Location C" forKey:#"location"];
[opponents addObject:opponent];
[opponents addObject:opponent2];
[opponents addObject:opponent3];
[_topponents reloadData];
}
and here my cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"opponentcell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *lopponentname = (UILabel*)[cell viewWithTag:1];
UILabel *lopponentstats = (UILabel*)[cell viewWithTag:2];
UILabel *llocation = (UILabel*)[cell viewWithTag:3];
lopponentname.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"name"];
lopponentstats.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"stats"];
llocation.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"location"];
return cell;
}
I found my fault!
I used to write:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]
but I should use
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
with "forIndexPath"
I think, the trouble is in the cell. Create UITableViewCell subclass.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"opponentcell";
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.lopponentname.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.lopponentstats.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"stats"];
cell.llocation.text = [[opponents objectAtIndex:indexPath.row] objectForKey:#"location"];
return cell;
}
Hope it helps you.
Add this after initialisation of cell. For me works properly.
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
I think you are using custom cel and it looks you have trouble in "cellForRowAtIndexPath". If you using .xib, you may find it useful.
static NSString *cellIdentifier = #"opponentcell";
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
NSArray *nibObjects =[[NSBundle mainBundle] loadNibNamed:#"CustomTableViewCell" owner:nil options:nil];
for (id currentObject in nibObjects)
{
if ([currentObject isKindOfClass:[CustomTableViewCell class]])
{
cell = (CustomTableViewCell *) currentObject;
}
}
[cell initViewStyles];
}
You need to check for condition when cell is nil..
Initially the cell is nil..
So the data is loading only after scrolling...
Add below lines of code in your cellForRowAtIndexPath delegate method after initializing cell.
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Hope this fixes the issue...

UITableViewCell.accessoryView will disappear in iOS 7

I assign some custom view to UITableViewCell.accessoryView, but if I scroll the tableView crazy, some accessoryView will disappear in iOS 7, and if I touch the cell, it's accessoryView can appear, I don't know why, because it's correct in iOS 6. This is my code, someone can help me?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"CELL %d", (int)indexPath.row+1];
NSDictionary * dict = [_dataSource objectAtIndex:indexPath.row];
if ([dict objectForKey:#"switch"])
{
cell.accessoryView = [dict objectForKey:#"switch"];
}
else
{
cell.accessoryView = nil;
}
return cell;
}
When we use ReusableCellWithIdentifier in table view it reuse cells in table, you set cell.accessoryView = nil; it's remove accessory view for all cells in table view with same CellIdentifier try this code, it's solve your problem :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSDictionary * dict = [_dataSource objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryView = [dict objectForKey:#"switch"];
}
cell.textLabel.text = [NSString stringWithFormat:#"CELL %d", (int)indexPath.row+1];
if ([dict objectForKey:#"switch"])
{
cell.accessoryView.hidden=NO;
}
else
{
cell.accessoryView.hidden=YES;
}
return cell;
}

iOS: Tableview multiple selection - AccessoryCheckmark checking reusable cells

I'm using a tableview with sections and multiple selection, but I have an issue with multiple rows being checked when one row is chosen...
I've seen a few other threads about this, but didn't really get a solution...
Here's my code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *) indexPath
{
[employeeTable deselectRowAtIndexPath:[employeeTable indexPathForSelectedRow] animated:NO];
UITableViewCell *cell = [employeeTable cellForRowAtIndexPath:indexPath];
// get the letter in each section
NSString *alphabet = [charIndex objectAtIndex:indexPath.section];
// get the names beginning with the letter
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *names = [listOfNames filteredArrayUsingPredicate:predicate];
NSString *name = [names objectAtIndex:indexPath.row];
for(int i = 0; i < [employeeConnection.employees count]; i++)
{
Employee *aEmployee = [employeeConnection.employees objectAtIndex:i];
NSString *firstName = aEmployee.firstName;
NSString *lastName = aEmployee.lastName;
NSString *fullName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
if([fullName isEqualToString:name])
{
NSLog(#"Name: %#", name);
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// Reflect selection in data model
[chosenEmployees addObject:aEmployee.employeeID];
[chosenEmployeesNames addObject:name];
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
// Reflect deselection in data model
[chosenEmployees removeObject:aEmployee.employeeID];
[chosenEmployeesNames removeObject:name];
}
}
}
}
Update: Added cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.textLabel.textColor = [UIColor whiteColor];
}
// Get the letter in the current section
NSString *alphabet = [charIndex objectAtIndex:[indexPath section]];
// Get the names beginning with the letter
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *names = [listOfNames filteredArrayUsingPredicate:predicate];
if([names count] > 0)
{
// Extract the name
cell.textLabel.text = [names objectAtIndex:indexPath.row];
}
return cell;
}
I would suggest storing an NSMutableSet of either the checked ManagedObject (when using CoreData) or simply the checked IndexPaths. In -cellForRowAtIndexPath: you can then check if the cell is supposed to be checked.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *const identifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
cell.textLabel.textColor = UIColor.whiteColor;
}
if ([self.checkedIndexPaths containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *const cell = [tableView cellForRowAtIndexPath:indexPath];
[table deselectRowAtIndexPath:indexPath animated:NO];
if ([self.checkedIndexPaths containsObject:indexPath]) {
[self.checkedIndexPaths removeObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
else {
[self.checkedIndexPaths addObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
Since cells are being reused, you need to set the accessory mark to on or off for every cell in the table in the cellForRowAtInexPath table datasource method.
So the cell.accessoryType cell property should be soecified in the cellForRowAtInexPath and not the didSelectRow delegate method.
In the didSelectRow, just keep track of the selected rows in an array, and set the cells accessory mark to none or checkmark in the cellForRowAtInexPath dependingon the array value.

UITableViewCell with Checkmark, duplicating checkmarks

So far search on Stack Overflow I havent found a situation that is like mine. Any assistance is greatly appreciated: I keep seeing that if I put a checkmark on Person A, Person H will also have one as well as does a person about 10 away. Basically abut every 10 it repeats a check mark.
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{static NSString *CellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text =
[NSString stringWithFormat:#"%# %#", [[myArrayOfAddressBooks objectAtIndex:indexPath.row] objectForKey:#"FirstName"],[[myArrayOfAddressBooks objectAtIndex:indexPath.row] objectForKey:#"LastName"]];
cell.detailTextLabel.text =
[NSString stringWithFormat:#"%#", [[myArrayOfAddressBooks objectAtIndex:indexPath.row] objectForKey:#"Address"]];
return cell;
}
In my did select row for index path I have this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
cell = [self.tableView cellForRowAtIndexPath: indexPath];
if ([[myArrayOfAddressBooks objectAtIndex:indexPath.row] objectForKey:#"emailSelected"] != #"YES")
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[[myArrayOfAddressBooks objectAtIndex:indexPath.row] setValue:#"YES" forKey:#"emailSelected"];
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
[[myArrayOfAddressBooks objectAtIndex:indexPath.row] setValue:#"NO" forKey:#"emailSelected"];
}
This is due to how UITableView "recycles" UITableViewCell for efficiency purposes, and how you are marking your cells when they are selected.
You need to refresh/set the accessoryType value for every cell you process/create within tableView:cellForRowAtIndexPath:. You properly update the state in your myArrayOfAddressBooks data structure, and you just need to use this information in tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *info = [myArrayOfAddressBooks objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", [info objectForKey:#"FirstName"],[info objectForKey:#"LastName"]];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", [info objectForKey:#"Address"]];
cell.accessoryType = ([[info objectForKey:#"emailSelected"] isEqualString:#"YES"]) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
}
Also, unless there is a good reason for saving the state as #"Yes" or #"No" strings, why not save them as [NSNumber numberWithBool:YES] or [NSNumber numberWithBool:NO]? This will simplify your logic when you want to do comparisons versus having to use isEqualToString: all the time.
e.g.
cell.accessoryType = ([[info objectForKey:#"emailSelected"] boolValue]) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;

Resources