I'm trying to find selected people in an array. I'm correctly getting where no one is selected, however, if one person in a group is selected, all people in the group are selected.
After a long head-scratching session, I could use some help to see if there is something obvious.
This action is going on in cellForRowAtIndexPath like this:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%s", __FUNCTION__);
static NSString *pCell = #"Cell";
PeopleCell *cell = (PeopleCell *)[aTableView dequeueReusableCellWithIdentifier:pCell];
if (cell == nil) {
cell = [[PeopleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:pCell];
}
people = [peopleArray objectAtIndex:[indexPath row]];
NSString *text = [people objectForKey:#"name"];
cell.textLabel.text = text;
if (selectedPeopleinGroup.count == 0) {
//no people selected in this group
NSLog(#"none");
cell.isSelected = [selectedPeopleinGroup containsObject:text] == NO;
} else {
//there are some people in this group - find out who they are
NSLog(#"some");
NSString *key1 = [selectedPeopleinGroup valueForKey:#"personKey"];
NSString *key2 = [people valueForKey:#"personKey"];
NSLog (#"key1 %#", key1 );
NSLog (#"key2 %#", key2 );
if (key1 == key2) {
cell.isSelected = [selectedPeople containsObject:text] == YES;
} else {
cell.isSelected = [selectedPeople containsObject:text] == NO;
}
}
return cell;
}
The cell is a subclassed UITableViewCell that has a checkmark image on the left side of the cell if selected and a different image if not selected. Many thanks.
This looks odd:
NSString *key1 = [selectedPeopleinGroup valueForKey:#"personKey"];
if selectedPeopleInGroup is an array, then valueForKey: returns an array of the results of calling valueForKey on each object in the array. So you are assigning an array to a string.
I'm surprised that the compiler is not issuing a warning about this. I'm also surprised that the log statements don't show odd values.
Related
I'm making an 'Add Friend' function, where it's possible to search on a username. I have a responeObject that contains an array of users. I only want to get the #"name" object for all the users and then list them in the TableView. If I search on "e" i get 3 results:
responseObject: (
{
id = 1;
isUsersAccount = 0;
name = Eshixf;
},
{
id = 3;
isUsersAccount = 0;
name = Neigstal;
},
{
id = 4;
isUsersAccount = 0;
name = Howie;
})
How can I get out all 3 names in 3 different cells?
And why does I get an error when I running the code with this line inside?:
NSDictionary *nameDict = [[friendRow objectAtIndex:0]objectForKey:#"name"];
It gives me this error:
-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x7faec35f4d40
Thank you!
you can get all names with simple iteration over response.
NSArray *response = friendRow[0]; // this is result dictionaries in an array. actually it is your responseObject.
//NSMutableArray *names = [NSMutableArray new];
names = [NSMutableArray new];//if declared outside the method, use this array as a dataSource for tableView.
for(NSDictionary *dict in response)
{
[names addObject:dict[#"name"]];
}
NSLog("names %#", names);
//refresh your tableview;
[yourTableView reloadData];
EDIT for TableView:
create names in interface as
NSMutableArray *names;
in delegate method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[cell.textLabel setText:names[indexPath.row]];
return cell;
}
with this method, tableview will know how many cells it needs.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [names count];
}
I need to get part of the selected row's data (cell.textLabel.text). The problem is this is what is in the cell (according to the debugger) and I can't figure out how to get to it. This is the line of code in -didSelectRowAtIndexPath
NSString *cellText = selectedCell.textLabel.text;
and this is what's in selectedCell.textLabel.text:
For the life of me, I can't figure out how to get the 1st of the 3 parts.
Any ideas/comments/answers would be greatly appreciated!
Have you tried something like this?
NSString *cellText = selectedCell.textLabel.text;
NSArray *components = [cellText componentsSeparatedByString:#" "];
if (components.count > 0) {
NSString *firstPart = components[0];
NSLog(#"%#", firstPart);
}
I got it to work; this is the code:
- (void) tableView:(UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
if(isFiltered) {
Books *su = filteredTableData[indexPath.row];
passedSKU = su.sku;
}
else {
// get the key from the cell that was selected from the list
Books *selectedBook = [booksArray objectAtIndex:indexPath.row];
passedSKU = selectedBook.sku;
}
// programmatically set the tabBar index
[self.tabBarController setSelectedIndex: 1];
}
Previously, I had a large-ish dataset (~530 records) being displayed in a tableview. The data was held in an array of dictionaries with two keys, ID and name. Previously, I tapped a cell, it added a check mark, and it sent the cell row number to a 'selectedArray'. As I had already alphabetically sorted them (still in one section), the indexPath.row which was stored in the selectedArray corresponded to the dictionaries' array index, so I could pull data (the ID) from the record.
I decided that I would split this into headers by alphabetical order (which was an absolute pain, I don't see why it's such a complex process to insert headers into a list of records). But now, as I only used indexPath.row, when I tick the first one, it ticks the first record of each section, and only returns the number 0, so I only get the first record in the whole dataset. Is there a simple way to correct this? Really appreciate any help.
cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"inviteCell"];
// cell.accessoryType = UITableViewCellAccessoryCheckmark;
if ([checkedCells objectForKey:[NSNumber numberWithInt:indexPath.row]] != nil) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
// NSDictionary *friend = [sortedFriendsArray objectAtIndex:indexPath.row];
//---get the letter in the current section---
NSString *alphabet = [nameIndex objectAtIndex:[indexPath section]];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF.name beginswith[c] %#", alphabet];
NSArray *states = [sortedFriendsArray filteredArrayUsingPredicate:predicate];
if ([states count]>0) {
//---extract the relevant state from the states object---
NSDictionary *friend = [states objectAtIndex:indexPath.row];
long long fbid = [[friend objectForKey:#"id"]longLongValue];
NSString *name = [friend objectForKey:#"name"];
NSString *urlString = [NSString stringWithFormat:#"https://graph.facebook.com/%qi/picture?type=square",fbid];
NSURL *url = [NSURL URLWithString:urlString];
UILabel *eventNameLabel = (UILabel *) [cell viewWithTag:1];
eventNameLabel.text = name;
UIImageView *eventLogo = (UIImageView*) [cell viewWithTag:2];
eventLogo.image = [UIImage imageNamed:#"112-group.png"];
// eventLogo.image = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];;
}
return cell;
}
CURRENT didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSNumber *indexNumber = [NSNumber numberWithInt:indexPath.row];
NSDictionary *friend = [sortedFriendsArray objectAtIndex:indexPath.row];
long long fbid = [[friend objectForKey:#"id"]longLongValue];
NSNumber *fbidNum = [NSNumber numberWithLongLong:fbid];
if ([checkedCells objectForKey:indexNumber] != nil) {
[checkedCells removeObjectForKey:indexNumber];
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
[checkedCells setObject:fbidNum forKey:indexNumber];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
NSLog(#"Cell Pressed: %#",indexNumber);
NSLog(#"FBID: %lld",fbid);
NSLog(#"Array: %#",checkedCells);
}
It looks like you're only saving the checked cells by row, not by section and row. At minimum, don't you need to be testing the section as well as the row in this block of code?
if ([checkedCells objectForKey:[NSNumber numberWithInt:indexPath.row]] != nil) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
It's late, and I don't have my Mac handy to try this code, so maybe I'm missing something obvious. I'm not sure what you're talking about only returning zero ... is that indexPath.row?
EDIT:
To account for the section in your data array, I'd suggest storing the data as a dictionary of arrays, one dictionary entry keyed by each letter, with the inner array holding all of the entries starting with that letter. It's a little more complicated to retrieve the data, but it correctly accounts for the section.
I supposed you could create some kind of an offset to account for the number of entries in each section and then use that to index into a flat array, but that would be a lot harder to maintain, in my view. I think the dictionary of arrays is the way to go.
I'm stuck with a problem populating an UITableView.
I have got an NSMutableArray with customers. It looks like this:
customer
first letter="A"
customer name="Adwars Inc."
customer
first letter="A"
customer name="Amman Co."
customer
first letter="B"
customer name="Building Inc."
customer
first letter="C"
customer name="Computer Co."
So I've got an object customer, which separates me each customer. And i've got some keys for each object.
In my second NSArray i've got all my first letters, which appear in my customer data. It look like this:
A
B
C
D
G
J
M
S
Z
I was able to get my right section count and rows in section, but when i try to populate my table view it always look like this:
SCREENSHOT
HERE IS MY CODE
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"CustomerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
for(int i = 0; i < [firstletters count]; i++)
{
if (indexPath.section == i) {
for(int count = 0 ;count < [customers count]; count++)
{
NSString *firstletter;
NSString *key;
key = [firstletters objectAtIndex:indexPath.section];
firstletter = [[customers objectAtIndex:count] objectForKey: #"FirstLetter"];
if ([key isEqualToString:firstletter]) {
cell.textLabel.text = [[customers objectAtIndex:count] objectForKey: #"S_NAME1"];
cell.detailTextLabel.text = [[customers objectAtIndex:count] objectForKey: #"s_town"];
}
}
}
}
return cell;
}
What do i have to do to make it work?
I know you have already accepted an answer, but I just wanted to offer another thought on how this might be done with data structured in a different way. If you had a dictionary where the keys were the first letter of your customers' names, and the values were the customer objects whose first letter was the same as the key, then you wouldn't have to do any looping (I don't know if you're still doing that in your solution). I made an example project (to see if this would work) that structures the data this way, except that my "objects" are just the names of companies rather than customer objects. In my table view controller I have:
- (void)viewDidLoad {
[super viewDidLoad];
self.companyDict = [NSMutableDictionary dictionary];
NSArray *aArray = [NSArray arrayWithObjects:#"Abercrombie & Fitch",#"Altera",#"Agilent",#"Allelix",#"Abbott Laboratories", nil];
NSArray *cArray = [NSArray arrayWithObjects:#"CocaCola",#"Continental",#"ConocoPhillips", nil];
NSArray *mArray = [NSArray arrayWithObjects:#"Myriad Genetics",#"Myrexis",#"Microsoft",#"McDonald's", nil];
NSArray *nArray = [NSArray arrayWithObjects:#"Nokia",#"NPS Pharmaceuticals",#"Norelco",#"Netflix",#"Nextel",#"Navistar International", nil];
[self.companyDict setValue:aArray forKey:#"A"];
[self.companyDict setValue:cArray forKey:#"C"];
[self.companyDict setValue:mArray forKey:#"M"];
[self.companyDict setValue:nArray forKey:#"N"];
self.keys = [[self.companyDict allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.keys.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.companyDict valueForKey:[self.keys objectAtIndex:section]]count];
}
- (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];
}
NSArray *theArray = [self.companyDict valueForKey:[self.keys objectAtIndex:indexPath.section]];
cell.textLabel.text = [theArray objectAtIndex:indexPath.row];
return cell;
}
For every cell, you're iterating through all the customers, repeatedly setting (and resetting) the textLabel and detailTextLabel for every customer whose first letter matches the current section (but you're not considering whether the index of that customer in that section matches the current indexPath.row or not). This means that in your code every cell will have the textLabel and detailTextLabel for the last customer whose first letter matches the current section's first letter.
Try this TableKit library.
This case the solution will be clean and elegant:
NSMutableDictionary* sectionMap = [NSMutableDictionary dictionaryWithCapacity:30];
for(NSDictionary* c in customers) {
NSString* firstLetter = [c objectForKey:#"FirstLetter"];
NSString* name = [c objectForKey:#"S_NAME1"];
NSString* town = [c objectForKey:#"s_town"];
TKSection* section = [sectionMap objectForKey:firstLetter];
if(!section) {
section = [TKSection sectionWithCells:nil];
section.headerTitle = firstLetter;
[sectionMap setObject:section forKey:firstLetter];
}
TKCell* cell = [TKStaticCell cellWithStyle:UITableViewCellStyleSubtitle text:name detailText:town];
[section addCell:cell];
}
self.sections = [sectionMap allValues];
TRY THIS (Copy and paste this code):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] init];
cell = nil;
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"CustomerCell"] autorelease];
cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
}
for(int i = 0; i < [firstletters count]; i++) {
if (indexPath.section == i) {
for(int count = 0 ;count < [customers count]; count++) {
cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
NSString *firstletter = nil;
NSString *key = nil;
key = [firstletters objectAtIndex:indexPath.section];
firstletter = [[customers objectAtIndex:count] objectForKey: #"FirstLetter"];
if ([key isEqualToString:firstletter]) {
cell.textLabel.text = [[customers objectAtIndex:count] objectForKey: #"S_NAME1"];
cell.detailTextLabel.text = [[customers objectAtIndex:count] objectForKey: #"s_town"];
}
}
}
}
return cell;
}
I have a problem that should be quite common. I have an Array of data called taskList this comes from a JSON and has several user data. So far, so good. I make the first objectForKey:#"desc" and returns the result (Description of user) but when I try to add another objectForKey (age for example) it shows only the age :( This is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"] autorelease];
}
NSLog(#"%#",taskList);
cell.textLabel.text = [[taskList objectAtIndex:indexPath.row] objectForKey:#"desc"];
return cell;
cell.textLabel.text = [[taskList objectAtIndex:indexPath.row] objectForKey:#"age"];
return cell;
}
do this instead:
NSString *desc = [[taskList objectAtIndex:indexPath.row] objectForKey:#"desc"];
NSString *age = [[taskList objectAtIndex:indexPath.row] objectForKey:#"age"];
cell.textLabel.text = [desc stringByAppendingString:age];
return cell;
Another example, which formats the string (in this case the only difference is that I'm adding a space between the two but it introduces you to a very very helpful method) (and uses the two strings that we created above):
NSString *textForMyLabel = [NSString stringWithFormat:#"%# %#", desc, age];
cell.textLabel.text = textForMyLabel;
Or to do the same thing without the temporary variable textForMyLabel use:
cell.textLabel.text = [desc stringByAppendingFormat:#" %#", age];
In the code you've posted, you'll never get to the 'age' portion since it will return after setting 'desc'. Even if you fix that, you're still assigning desc and age to the same field in the cell, which isn't likely to be what you want.