Search code examples
ios8nsmutablearraynsarraysubquerynspredicate

NSPredicate issue for Nested objects IOS


How can i use NSPredicate on "self.tableInfo" (NSMutableArray) to get object of CheckIn using predicate key "name" with following structure. As self.tableInfo has an array of SectionInfo and every SectionInfo has its cells(CellInfo) inside and each cell has checkin object.

- (void)configureView   {
    self.tableInfo = [NSMutableArray alloc]init];
    self.filteredTableInfo = [NSMutableArray alloc]init];
    NSArray *checkIns =  [CheckIn MR_findAll];
    SectionInfo*checkInSection = [SectionInfo section];
    for (CheckIn *checkIn in checkIns) {
        CellInfo *listCell = (CellInfo *)[CellInfo cell];
        listCell.className = NSStringFromClass([FeedListCell class]);
        listCell.height = 260;
        listCell.object = checkIn;
        [checkInSection.cells addObject:listCell];
    }
    if ([checkIns count] > 0) {
        self.tableInfo = [NSMutableArray arrayWithArray:@[checkInSection]];
        self.filteredTableInfo = self.tableInfo;
        [self.tableView setHidden:NO];
        [self.tableView reloadData];
    }
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    if (self.tableInfo) {
        return self.tableInfo.count;
    }
    return 0;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (self.tableInfo && (section < self.tableInfo.count) ) {
        SectionInfo *sectionInfo = [self.tableInfo objectAtIndex:section];
        return sectionInfo.numberOfCells;
    }
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    SectionInfo *sectionInfo = self.tableInfo[indexPath.section];
    CellInfo *formInfoCell = sectionInfo.cells[indexPath.row];
    CheckIn *checkin = formInfoCell.object;
    NSLog(@"%@", checkIn.name);
}

The way i am using is something like:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    if([searchText length] != 0) {
        [self filterContentForSearchText:searchText];
    }
}
- (void)filterContentForSearchText:(NSString *)searchText   {
    NSPredicate *namePredicate = [NSPredicate predicateWithFormat:@"ANY cells.object.name contains[c] %@", searchText];
    NSArray * filteredArray = [self.filteredTableInfo filteredArrayUsingPredicate:namePredicate];
    self.tableInfo = [NSMutableArray arrayWithArray:@[filteredArray]];
    [self.tableView reloadData];
}

This returns me always zero count. Any better idea to handle this thing?


Solution

  • It looks like you have a couple problems with this predicate. First of all, in your predicate you are searching based on "CellInfo.object" SELF.cells.object contains[c] %@ instead of "CellInfo.object.name" like it seems you want to be doing.

    Secondly, when searching an array within an array (in your case SectionInfo.cells within your tableInfo array) you can't simply use dot notation to search the inner array. You have to specify what items you want in the array that match your query. You can do this by using one of the keywords ANY ALL or NONE.

    For example, to get any SectionInfo that has a CellInfo whose CheckIn.name contains the search text you would want to do this:

    NSPredicate *namePredicate = [NSPredicate predicateWithFormat:@"ALL cells.object.name contains[c] %@", searchText"];
    NSArray *filteredSections = [self.tableInfo filteredArrayUsingPredicate:namePredicate]
    

    However, this returns an array of SectionInfo's instead of CheckIn objects like you wanted. In order to get CheckIn objects instead you must first create an array of all the CheckIn objects first. You can do this by using the valueForKeyPath method on NSArray. You can then search that array using a simpler predicate.

    NSArray *allCheckInObjects = [self.tableInfo valueForKeyPath:@"@distinctUnionOfArrays.cells.object"];
    NSPredicate *namePredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", searchText];
    NSArray *filteredCheckInObjects = [allCheckInObjects filteredArrayUsingPredicate:namePredicate];
    

    Hope this helps!