How do I get a UITableView' cell's data? - objective-c

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];
}

Related

Implementing copy method - copy whole row

I am trying to copy the row of the NSTableView on clipboard. Here is my code:
- (void) copy:(id)sender
{
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
// I get warning in the line bellow, unused variable changeCount
NSInteger changeCount = [pasteboard clearContents];
NSInteger row = [self.customersViewController.customersTableView selectedRow];
NSTableColumn *columnFirstName = [self.customersViewController.customersTableView tableColumnWithIdentifier:#"firstName"];
NSCell *cellFirstName = [columnFirstName dataCellForRow:row];
NSArray *objectsToCopy = #[[cellFirstName stringValue]];
// I get warning in the line bellow unused variable OK
BOOL OK = [pasteboard writeObjects:objectsToCopy];
}
This code works, and if I select the row in the NSTableView, the content of the firstName column of the selected row is indeed on the pasteboard (I can paste the value in text editor).
However this code have couple of issues:
1. I get 2 warnings as you can see from my comments.I rewrite the code to get rid of the warnings like this. Is anything wrong with the way how I re-write the code?
// warning one
NSInteger changeCount = 0;
changeCount = [pasteboard clearContents];
// warning 2
BOOL OK = NO;
OK = [pasteboard writeObjects:objectsToCopy];
In the code above I name specific which NSTableView I use
...self.customersViewController.customersTableViev....
However If the user switch the view, it may use some other NSTableView...how can I find out from which NSTableView the copy method should copy the row?
If I comment the line where I use specific NSTableView and try to use sender, my app crashes.
//NSInteger row = [self.customersViewController.customersTableView selectedRow];
NSInteger row = [sender selectedRow];
3.How could I write a loop to get all column names instead of specifically write them by hand one by one? I will not know which NSTableView is used anyway....
NSTableColumn *columnFirstName = [self.customersViewController.customersTableView tableColumnWithIdentifier:#"firstName"];
If you don't want the return value you can omit it.
To make you code table view independent you can use firstResponder of the window. Alternatively you can implement copy: in a cubclass of NSTableView. sender is the menu item.
NSTableView's property tableColumns is an array of NSTableColumn.
Here's what I did:
- (void)copy:(id)sender {
NSResponder *firstResponder = self.window.firstResponder;
if (firstResponder && [firstResponder isKindOfClass:[NSTableView class]]) {
NSTableView *tableView = (NSTableView *)firstResponder;
NSArrayController *arrayController = [[tableView infoForBinding:NSContentBinding] objectForKey:NSObservedObjectKey];
// create an array of the keys and formatters of the columns
NSMutableArray *keys = [NSMutableArray array];
for (NSTableColumn *column in [tableView tableColumns]) {
NSString *key = [[column infoForBinding:NSValueBinding] objectForKey:NSObservedKeyPathKey]; // "arrangedObjects.name"
if (key) {
NSRange range = [key rangeOfString:#"."];
if (range.location != NSNotFound)
key = [key substringFromIndex:range.location + 1];
NSFormatter *formatter = [[column dataCell] formatter];
if (formatter)
[keys addObject:#{#"key":key, #"formatter":formatter}];
else
[keys addObject:#{#"key":key}];
}
}
// create a tab separated string
NSMutableString *string = [NSMutableString string];
for (id object in [arrayController selectedObjects]) {
for (NSDictionary *dictionary in keys) {
id value = [object valueForKeyPath:dictionary[#"key"]];
if (value) {
NSFormatter *formatter = [dictionary objectForKey:#"formatter"];
if (formatter)
[string appendFormat:#"%#\t", [formatter stringForObjectValue:value]];
else
[string appendFormat:#"%#\t", value];
}
else
[string appendFormat:#"\t"];
}
[string replaceCharactersInRange:NSMakeRange([string length] - 1, 1) withString:#"\n"];
}
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents];
[pasteboard setString:string forType:NSPasteboardTypeString];
}
}

How to retrieve kABPhoneNumber from Address Book in Cocoa with multiValues?

I'm trying to extract phone numbers from an ABRecord and put it into a NSTableView. It logs the number, but the app crashes when the tableView is scrolled and tries to get more data. Is the way I'm retrieving the number the right way to do so? Its not clear to me why it sometimes fails to load it into the cell.
-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
{
contactCell *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
if( [tableColumn.identifier isEqualToString:#"cell"] )
{
ABPerson *indexedPerson = contactsArr[row];
ABRecord *record = contactsArr[row];
NSString *numberString = #"";
NSString *nameInfo = [NSString stringWithFormat:#"%# %#",
[indexedPerson valueForKey:kABFirstNameProperty],
[indexedPerson valueForKey:kABLastNameProperty]];
//get the number
ABMutableMultiValue *multiValue = [record valueForProperty:kABPhoneProperty];
NSLog(#"currentPerson: %#",indexedPerson);
//see if there is data in the multi value
if ([multiValue valueAtIndex:1]) {
numberString = [multiValue valueAtIndex:1];
} else {
numberString = #"";
}
NSLog(#"%# test", numberString);
//set the strings
[cellView.nameField setTitle:nameInfo];
//set field in cell
[cellView.numberField setTitle:numberString];
return cellView;
}
return cellView;
}
Instead of checking index 0, I was checking index 1. Changing to index 0 in the if statement checking for data in the multivalue resolved the issue.

Trying to identify selected table view cells

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.

Can't change UILabel text in method because of SIGABRT exception.What's wrong?

I' m creating a custom UITableViewCell view. I have a method for UITableViewCell and I have created UILabel memberLabel programmatically:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * const cellIdentifier = #"cellMemberId";
CPNMemberCell *cell = (CPNMemberCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
[[NSBundle mainBundle] loadNibNamed:#"TeamCell" owner:self options:nil];
cell = baseCell;
}
memberLabel = [[UILabel alloc] initWithFrame:CGRectMake(32, 19, 183, 27)];
[cell addSubview:memberLabel];
NSString * const test = #"test input";
memberLabel.text = test;
return cell;
}
So this code works quite well. But when I change test string value to string containing JSON response in MutableDictionary, all fails. I specially output that string to console log in order to be sure it is not empty or whatever. And I have an except during assigning
that string to UILabel:
NSString * const test = [members valueForKey:#"modelId"];
NSLog(#"Output: %#", test);
memberLabel.text = test;
I don't understand what's wrong: response correctly prints to the console, UILabel correctly displays text strings as in the first code block, but when I try to display string with that response I have a SIGABRT exception in the main.
Check what is the data type of test variable. Use:
NSLog(#"data type = %#", [[test class] description]);
Is it printing data type = NSString? If not, that is the issue.
Also try this,
NSString* test = [ _members valueForKey:#"modelId"];
NSLog(#"Testing response in the console: %#", test);
if ([test isKindOfClass:[NSString class]]) {
memberLabel.text = test;
} else {
NSLog(#"test is not a string");
}

Checking/Unchecking a tableviewcell with sections

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.