Search code examples
objective-cuitableviewuisearchdisplaycontroller

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: 'this class is not key value coding-compliant for the key name


Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x9c7aaf0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key name

I searched stackoverflow.com for a solution to this error but I didn't find any. I think I might have a different problem.

I'm trying to implement UISearchdisplaycontroller in my project. I have a UITableview displaying content from a sqlite database and after displaying I want to perform a search. I'm unable to do so. please someone help.

Here is my code:

-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
        NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", searchText];
        searchResults = [jobTitleArray filteredArrayUsingPredicate:resultPredicate];`
}

-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterContentForSearchText:searchString scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
    return YES;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    //int rowCount;
    if (tableView == self.searchDisplayController.searchResultsTableView)
    {

    NSLog(@"Search count %d",[searchResults count]);
    return [searchResults count];


    } else
    {

    NSLog(@"jobTitleArray Search count %d",[jobTitleArray count]);
    return [jobTitleArray count];

    }
    //return rowCount;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    JobDetailViewController *jobD = [[JobDetailViewController alloc] init];`

    NSLog(@"Before: %@", jobD);

    if (tableView == self.searchDisplayController.searchResultsTableView) {
        [self performSegueWithIdentifier: @"showJobDetail" sender: self];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath`
{
    static NSString *CellIdentifier = @"Cell";
    //jobTableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    jobTableCell *cell = (jobTableCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];`

    if (cell == nil) {
        cell = [[jobTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    JobDone *jobD = nil;
    if (tableView == self.searchDisplayController.searchResultsTableView) {

        NSLog(@"job %@",searchResults);
        jobD = [searchResults objectAtIndex:indexPath.row];

    } else
    {
        jobD = [jobTitleArray objectAtIndex:indexPath.row];
    }
    cell.companyLabel.text=[companyArray objectAtIndex:indexPath.row];

    cell.titleLabel.text = [jobTitleArray objectAtIndex:indexPath.row];

    cell.descLabel.text=[descArray objectAtIndex:indexPath.row];
    return cell;
}

Solution

  • Your error message tells you where to look. It says "this class is not key value coding-compliant for the key name". So, where do you use name? It would appear that jobTitleArray does not have an attribute called name.

    I don't see what jobTitleArray looks like, but if it's just an array of strings, perhaps you intended something like:

    NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"self contains[c] %@", searchText];
    

    That uses self rather than name.


    Looking more carefully at your code, I've deduced what jobTitleArray must be: an array of strings.

    But I note that you have separate arrays, jobTitleArray, companyArray, and descArray. This is going to be a problem, because you're filtering on the basis of one of those arrays. So how will you filter the others?!?

    The solution is to keep all three of these in a single array. For example, if you had a single array of the form:

    NSArray *jobs = @[
                        @{@"name" : @"Manager of Purchasing", @"company" : @"Amazon", @"description": @"blah, blah, blah"}, 
                        @{@"name" : @"VP of Sales",           @"company" : @"Ebay",   @"description": @"blah, blah, blah"}
                     ];
    

    Then, your original filter now works:

    NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", searchText];
    

    If you filtered the above for "purchasing", you'd get the full dictionary entry for the Amazon job. This keeps all three attributes in sync with each other.

    Note, this technique works equally well with custom objects, too, but hopefully this illustrates the basic idea: Use single array of objects with multiple properties, and when you filter based upon one of those properties, you get objects will all of their properties still in tact.