Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString nric]: - iphone

I get this error when i play with the searchbar that I have just implemented.. Some letters work while others will crash with the error in the title. The error seems to be here but i cannot figure out what is wrong with it : "cell.textLabel.text = info.nric;".
Someone please help =(
- (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] autorelease];
}
// Set up the cell...
if(searching){
PatientInfo *info = [copyListOfItems objectAtIndex:indexPath.row];
cell.textLabel.text = info.nric;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%i, %i", info.category, info.age];
}
else {
//First get the dictionary object
NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Patients"];
PatientInfo *info = [array objectAtIndex:indexPath.row];
// NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.textLabel.text = info.nric;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%i, %i", info.category, info.age];
}
return cell;
}

One of the arrays that you think contains only PatientInfo objects actually contains an NSString. So when you then write info.nric, it's asking that NSString for its nric property, which of course doesn't exist. The actual error would be wherever you're mistakenly putting a string in the array (either copyListOfItems or listOfItems).

Replace with the following code, you will know what exactly is going wrong in your code:
PatientInfo *info = [copyListOfItems objectAtIndex:indexPath.row];
if((nil != info) && ([info isKindOfClass:[PatientInfo class]))
{
if([info respondsToSelector:#selector(nric)])
{
cell.textLabel.text = info.nric;
}
}

Related

UITableViewCell Repeating images

I am trying to add a favourites images in the table view cell. I am using this code
static NSString *CellIdentifier = #"memberCell";
MemberCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *item = self.searchList[indexPath.row];
cell.memberFullName.text = [item[#"full_name"] uppercaseString] ;
cell.memberPosition.text = [item[#"title"] length] < 1 ? [NSString stringWithFormat:#"%#", item[#"districts"]] : [NSString stringWithFormat:#"%#, %#", item[#"title"], item[#"districts"]];
cell.memberRoom.text = [NSString stringWithFormat:#"Rm %#", item[#"room_number"] ];
[cell.memberImage setImageWithURL:[NSURL URLWithString:item[#"image_thumb"]]
placeholderImage:[UIImage imageNamed:#"placeholder"]];
if(![item[#"fid"] isEqualToString:#"0"]) {
[cell.memberFavoriteImage setImage:[UIImage imageNamed:#"favorite"]];
}
The problem i am having is the favourite images are showing on multiple cells even though the condition if(![item[#"fid"] isEqualToString:#"0"]) is passed only for 1 cell, when i do a NSLog, the condition is passed once only but the images are displayed is a systematic order (that is each 9th row), when i scroll all the way down and come back the order completely changes and images are shown in different rows. I am not sure what is happening, please help.
The dequeue instruction potentially returns an existing instance of cell
try this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [NSString stringWithFormat:#"%d_%d",indexPath.section,indexPath.row];
MemberCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MemberCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *item = self.searchList[indexPath.row];
cell.memberFullName.text = [item[#"full_name"] uppercaseString] ;
cell.memberPosition.text = [item[#"title"] length] < 1 ? [NSString stringWithFormat:#"%#", item[#"districts"]] : [NSString stringWithFormat:#"%#, %#", item[#"title"], item[#"districts"]];
cell.memberRoom.text = [NSString stringWithFormat:#"Rm %#", item[#"room_number"] ];
[cell.memberImage setImageWithURL:[NSURL URLWithString:item[#"image_thumb"]]placeholderImage:[UIImage imageNamed:#"placeholder"]];
if(![item[#"fid"] isEqualToString:#"0"]) {
[cell.memberFavoriteImage setImage:[UIImage imageNamed:#"favorite"]];
} else {
[cell.memberFavoriteImage setImage:nil];
}
return cell;
}
NSString *CellIdentifier = [NSString stringWithFormat:#"%d_%d",indexPath.section,indexPath.row];
MemberCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MemberCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *item = self.searchList[indexPath.row];
cell.memberFullName.text = [item[#"full_name"] uppercaseString] ;
cell.memberPosition.text = [item[#"title"] length] < 1 ? [NSString stringWithFormat:#"%#", item[#"districts"]] : [NSString stringWithFormat:#"%#, %#", item[#"title"], item[#"districts"]];
cell.memberRoom.text = [NSString stringWithFormat:#"Rm %#", item[#"room_number"] ];
[cell.memberImage setImageWithURL:[NSURL URLWithString:item[#"image_thumb"]]placeholderImage:[UIImage imageNamed:#"placeholder"]];
if(![item[#"fid"] isEqualToString:#"0"]) {
[cell.memberFavoriteImage setImage:[UIImage imageNamed:#"favorite"]];
}
return cell;

Searching a UITableview

I am trying to do a search in a UITableview. I have implemented the UISearchDisplayDelegate, UISearchBarDelegate method at the correct way. This is how my cellForRowAtIndexPath looks like.
- (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];
}
if (tableView == self.searchDisplayController.searchResultsTableView){
Contact *contact = [self.filteredListContent objectAtIndex:indexPath.row];
NSString *text = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
NSLog(#"CellForRowAtIndexPath contact text is %#",text);
cell.textLabel.text = text;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}else{
NSString *alphabet = [firstIndex objectAtIndex:[indexPath section]];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF.name beginswith[c] %#",alphabet];
NSArray *contacts = [listContent filteredArrayUsingPredicate:predicate];
Contact *contact = [contacts objectAtIndex:indexPath.row];
NSString *text = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
cell.textLabel.text = text;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
return cell;
}
And this is my filterContentForSearchText method
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
[self.filteredListContent removeAllObjects]; // First clear the filtered array.
for (Contact *contact in listContent)
{
NSString *searchString = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
NSRange range = [searchString rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
[self.filteredListContent addObject:contact];
[self.searchDisplayController.searchResultsTableView reloadData];
}
}
}
The strange thing is. In my cellForRowAtIndexPath it returns me the correct data. But the tableview itselfs keeps given me the NO RESULTS label.
Any help with this?
Follow this tutorial how-to-add-search-bar-uitableview ..
Just see the method cellForRowAtIndexPath: in which how to set the search array when user searched record from UISearchBar...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"RecipeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [searchResults objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [recipes objectAtIndex:indexPath.row];
}
return cell;
}
Use an array to show data in table(showDataArray)
Use an array to store all input values(dataArray)
Use showDataArray to populate your table always
In the searchfield when charecter range changes call a method to filter the data using predicate from dataArray
Save the value to showDataArray
Call for table reloadData
First add UISearchBar on top of UITabelView documentation
And then Take Two NSMutableArray and add one array to another array in ViewDidLoad method such like,
self.listOfTemArray = [[NSMutableArray alloc] init]; // array no - 1
self.ItemOfMainArray = [[NSMutableArray alloc] initWithObjects:#"YorArrayList", nil]; // array no - 2
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray]; // add 2array to 1 array
And Write following delegate Method of UISearchBar
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText
{
NSString *name = #"";
NSString *firstLetter = #"";
if (self.listOfTemArray.count > 0)
[self.listOfTemArray removeAllObjects];
if ([searchText length] > 0)
{
for (int i = 0; i < [self.ItemOfMainArray count] ; i = i+1)
{
name = [self.ItemOfMainArray objectAtIndex:i];
if (name.length >= searchText.length)
{
firstLetter = [name substringWithRange:NSMakeRange(0, [searchText length])];
//NSLog(#"%#",firstLetter);
if( [firstLetter caseInsensitiveCompare:searchText] == NSOrderedSame )
{
// strings are equal except for possibly case
[self.listOfTemArray addObject: [self.ItemOfMainArray objectAtIndex:i]];
NSLog(#"=========> %#",self.listOfTemArray);
}
}
}
}
else
{
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray ];
}
[self.tblView reloadData];
}
And Write in cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Foobar"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Foobar"];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.textLabel.textColor = [UIColor blackColor];
}
cell.textLabel.text = [self.listOfTemArray objectAtIndex: indexPath.row];
return cell;
}

how to read Plist data to UITableView [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to Get Data from a PList into UITableView?
I have a plist with Dictionary and numbers of strings per dictionary.show into the url below.and this list of items is in thousands in the plist.
Now want to display these list into the tableview
.
now how can i display this plist into the UITableView
what I am trying is:
- (id)readPlist:(NSString *)fileName
{
NSString *error;
NSPropertyListFormat format;
id plist;
NSString *localizedPath = [[NSBundle mainBundle] pathForResource:#"A" ofType:#"plist"];
dic =[NSDictionary dictionaryWithContentsOfFile:localizedPath];
plist = [NSPropertyListSerialization propertyListFromData:dic mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if (!plist) {
NSLog(#"Error reading plist from file '%s', error = '%s'", [localizedPath UTF8String], [error UTF8String]);
[error release];
}
return plist;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
dict =[self readPlist:#"A"];
return dict.allKeys.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
dict = [self readPlist:#"A"];
key = [dict.allKeys objectAtIndex:section];
return [[dict valueForKey:key] 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] autorelease];
}
cell.textLabel.text = [[dict objectForKey:key] objectAtIndex:indexPath.row];
return cell;
}
UPDATE 2: You need to set the delegate and datasource for your tableView in your xib or ViewController.
In your ViewController.h file
#interface ViewController:UIViewController <UITableViewDelegate, UITableDataSource>
Try this code which I have written for you.
- (void)viewDidLoad {
tableView.delegate = self;
tableView.dataSource = self;
NSString *path = [[NSBundle mainBundle] pathForResource:#"Filename" ofType:#"plist"];
NSArray *contentArray = [NSArray arrayWithContentsOfFile:path];
// Having outlet for tableArray variable.
tableArray = [[NSMutableArray alloc]initWithArray:contentArray copyItems:YES];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [tableArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// In your case dictionary contains strings with keys and values. The below line returns dictionary only. not array..
NSDictionary *dictionary = [tableArray objectAtIndex:section];
return dictionary.allKeys.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
}
NSDictionary *dictionary = [tableArray objectAtIndex:indexPath.section];
NSArray *keysArray = dictionary.allKeys;
// This below line display the key in textLabel
cell.textLabel.text = [keysArray objectAtIndex:indexPath.row];
// Below line will display the value of a key in detailTextLabel.
cell.detailTextLabel.text = [dictionary valueForKey:[keysArray objectAtIndex:indexPath.row]];
return cell;
}
UPDATE 2: After I have seen your plist in my MAC, I have found out that we are working with array of dictionaries in your A.plist.
So I found there is a bug in our code itself. Not in the plist file and you can use your 8000 data plist too.. Its working too. I have checked out totally. Now you can get the above Code and start work with.
store Plist data in array
- (id)readPlist:(NSString *)fileName
{
NSString *error;
NSPropertyListFormat format;
id plist;
NSString *localizedPath = [[NSBundle mainBundle] pathForResource:#"A" ofType:#"plist"];
// declare your array in .h file
array = [NSArray arrayWithContentsOfFile:localizedPath];
plist = [NSPropertyListSerialization propertyListFromData:dic mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if (!plist) {
NSLog(#"Error reading plist from file '%s', error = '%s'", [localizedPath UTF8String], [error UTF8String]);
[error release];
}
return plist;
}
and then write it in table
- (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];
}
cell.textLabel.text = [array objectAtIndex:indexPath.row] valueForKey:#"keyname"];;
return cell;
}

How can I display all the rows from a database in a tableview

I am using this code to display all the rows from database, but when the tableview loads only the last row shows up.. what am I doing wrong. Please help!!
- (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];
}
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (!mutableFetchResults)
{
NSLog(#"Cant Fetch");
}
//compare fetched data with user input abd login if match
for(Event *ev in mutableFetchResults)
{
NSString *cellValue=[ev VidField];
NSString *cellValue1=[ev ImgField];
NSLog(#"%#",cellValue);
NSLog(#"%#",cellValue1);
[cell.textLabel setText:cellValue];
cell.image = [UIImage imageNamed:cellValue1];
}
return cell;
}
you should do like this;
in .h file;
NSMutableArray *myFetchResults;
in .m file;
-(void)getAllDataFromDatabase{ // call it to get data
myFetchResults = [[NSMutableArray alloc] init];
//database connection codes
myFetchResults = mutableFetchResults; // now you have an array with all objects.
}
in UITableView cellForRowAtIndexPath delegate method:
{
Event *ev = (Event*)[myFetchResults objectAtindex:indexPath.row];
cell.textLabel.Text = [ev VidField];
cell.image = [UIImage imageNamed:[ev ImgField]];
}
i think this will work.
This code repeatedly sets different values to the same cell instance, so it will end up set to whatever the last event in your fetch results is. Your cellForRowAtIndexPath method should be using the indexPath.row to set the values for a cell from the specific event at that point in your mutableFetchResults - if this is an array, it would be something like:
Event *ev = [mutableFetchResults objectAtIndex:indexPath.row];
NSString *cellValue=[ev VidField];
NSString *cellValue1=[ev ImgField];
NSLog(#"%#",cellValue);
NSLog(#"%#",cellValue1);
[cell.textLabel setText:cellValue];
cell.image = [UIImage imageNamed:cellValue1];
return cell;
It is hard to give any more details without seeing more code, but this should set you on the right path.
You're just overwriting the value in cell.textLabel. If your for loop were unfurled it would look something like this:
cell.textLabel = row1Text
cell.textLabel = row2Text
...
cell.textLabel = rowNText
You should set your cell text in – tableView:cellForRowAtIndexPath: using the indexPath.row to select which record you want.
You should use if(Condition) for it. Because, for() iterate until last record will be get and set record's data.
i think at first take your mutableFetchResults in viewdidload then retain the [mutableFetchResults retain].
then number of rows of table will be [mutableFetchResults count]
then in make this code...
- (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];
}
NSString *cellValue=[indexpath.row VidField];
NSString *cellValue1=[indexpath.row ImgField];
NSLog(#"%#",cellValue);
NSLog(#"%#",cellValue1);
[cell.textLabel setText:cellValue];
cell.image = [UIImage imageNamed:cellValue1];
return cell;
}
if any code you do not understand then tell me...because i faced same problem...if you want to see more the see my solution....What will be the numberOfRowsInSection return type for uitableview when XML data is retrieved?

iphone Odd Problem when using a custom cell

Please note where I have the NSLOG. All it is displaying in the log is the first three items in the nameSection. After some testing, I discovered it is displaying how many keys there are because if I add a key to the plist, it will log a fourth item in log.
nameSection should be an array of the strings that make up the key array in the plist file.
the plist file has 3 dictionaries, each with several arrays of strings. The code picks the dictionary I am working with correctly, then should use the array names as sections in the table and the strings en each array as what to display in each cell.
so if the dictionary i am working with has 3 arrays, NSLOG will display 3 strings from the first array:
2010-05-01 17:03:26.957 Checklists[63926:207] string0
2010-05-01 17:03:26.960 Checklists[63926:207] string1
2010-05-01 17:03:26.962 Checklists[63926:207] string2
then stop with: 2010-05-01 17:03:26.963 Checklists[63926:207] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[NSCFArray objectAtIndex:]: index (3) beyond bounds (3)'
if i added an array to the dictionary, it log 4 items instead of 3.
I hope this explanation makes sense...
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [keys count];
}
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger) section {
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
return [nameSection count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = [indexPath section];
NSString *key = [keys objectAtIndex: section];
NSArray *nameSection = [names objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
static NSString *ChecklistCellIdentifier = #"ChecklistCellIdentifier ";
ChecklistCell *cell = (ChecklistCell *)[tableView
dequeueReusableCellWithIdentifier: SectionsTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChecklistCell"
owner:self options:nil];
for (id oneObject in nib)
if ([oneObject isKindOfClass:[ChecklistCell class]])
cell = (ChecklistCell *)oneObject;
}
NSUInteger row = [indexPath row];
NSDictionary *rowData = [self.keys objectAtIndex:row];
NSString *tempString = [[NSString alloc]initWithFormat:#"%#",[nameSection objectAtIndex:row]];
NSLog(#"%#",tempString);
cell.colorLabel.text = [tempArray objectAtIndex:0];
cell.nameLabel.text = [tempArray objectAtIndex:1];
return cell;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
-(NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section{
NSString *key = [keys objectAtIndex:section];
return key;
}
In tableView:cellForRowAtIndexPath: you're doing this:
NSDictionary *rowData = [self.keys objectAtIndex:row];
This has at least two problems:
Based on your implementation of numberOfSectionsInTableView:, it seems you have one key per section. This code is looking for a key for every row in the current indexPath.section.
In tableView:numberOfRowsInSection:, -[keys objectAtIndex:] returns an NSString. Here you're treating it as an NSDictionary.
Found the problem. It was this (pointless) line of code. Removed it and it worked fine.
NSDictionary *rowData = [self.keys objectAtIndex:row];