Frage

I have a little problem with my searchbar for a tableview

I have made a tableview with an array tableViewArray.
The tableViewArray consists of many rows of another array consisting of [text, distance]. Everything is working fine.
Now i added a searchBar and a searchdisplaycontroller, that searched based on a new array of string (from the "text" object of the tableViewArray). I thought the search should only be available for the text, and the search method is implemented on that.

Now when i get the search result, it looks good, and the search returns expected rows. The problem is with the search tableViews subtitle. It is showing the distances for row 1, 2, 3 for the tableViewArray.

I need it to map the distance to the text shown in the search tableview rows. I imagine i need to make a new table view array for the search results consisting of [text distance]. the text is not a problem since it is from the search result, but how do i map the new distance to the old distance???

The search method im using in the search delegate is :

searchResults = [[NSArray alloc]init];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@",
                            searchText];
searchResults = [searchItems  filteredArrayUsingPredicate:resultPredicate];

Hope somebody can help :) Thanks in advance!

The original code:

- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section
{

    if (theTableView == self.searchDisplayController.searchResultsTableView) {
        return [searchResults count];
    } else {
        return [tableViewArray count];
    }
}  

- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:     UITableViewCellStyleSubtitle
                                  reuseIdentifier: CellIdentifier] ;

     if (theTableView == self.searchDisplayController.searchResultsTableView) {

    } else {
         cell = [theTableView dequeueReusableCellWithIdentifier:CellIdentifier     forIndexPath:indexPath];
}

    // Configure the cell...
    // cell.textLabel.numberOfLines = 0;
   // cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;

    if (theTableView == self.searchDisplayController.searchResultsTableView) {
        cell.textLabel.text = [searchResults objectAtIndex:indexPath.row];
    } else {
        cell.textLabel.text = [[[tableViewArray objectAtIndex:indexPath.row]     objectAtIndex:0] subtitle];
}

    cell.detailTextLabel.textColor = [UIColor redColor];




float blabla=  [[[tableViewArray objectAtIndex:indexPath.row] objectAtIndex: 1] doubleValue];
if (blabla < 1000) {
         cell.detailTextLabel.text = [NSString stringWithFormat:@"%.2f m",blabla];
} else {
         cell.detailTextLabel.text = [NSString stringWithFormat:@"%.2f km",blabla/1000];
}





NSString *text = [[[tableViewArray objectAtIndex:indexPath.row] objectAtIndex:0] subtitle];
NSRange q8RangeValue = [text rangeOfString:@"Q8" options:NSCaseInsensitiveSearch];
NSRange okRangeValue = [text rangeOfString:@"OK" options:NSCaseInsensitiveSearch];

if (q8RangeValue.length >0  ) {
        cell.imageView.image = [UIImage imageNamed:@"q8.png"];
} else if (okRangeValue.length >0 ) {
        cell.imageView.image = [UIImage imageNamed:@"OK logo.png"];

} else {
        cell.imageView.image = nil;
}

return cell;
}

And where i make the array for the search:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {

NSLog(@"didUpdateToLocation Location calculator distance array for the tableView");

NSMutableArray * distancesInReverseOrder = [[NSMutableArray alloc] init];



for (int i = 0; i<allAnnotations.count; i++) {

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0] ;
CLLocationCoordinate2D annotationCoord = [[allAnnotations objectAtIndex:indexPath.row] coordinate];


CLLocation *location = [[CLLocation alloc] initWithLatitude:annotationCoord.latitude  longitude:annotationCoord.longitude];

distanceToMe = [newLocation distanceFromLocation:location];

[distancesInReverseOrder insertObject:[NSNumber numberWithFloat: distanceToMe] atIndex:0];

}


distances = [[NSMutableArray alloc] initWithArray:[[distancesInReverseOrder reverseObjectEnumerator] allObjects]];

// Assuming you have your points on the map in an NSArray called
// allAnnotations and your distances in distances, create a
// new mutable array to hold both
tableViewArray = [[NSMutableArray alloc] init];

// Iterate over all of the points, and add a new element to the mutable
// array which is a new array containing a point and its distance
for (int i = 0; i < allAnnotations.count; i++) {
    NSArray *newItem = [NSArray arrayWithObjects: [allAnnotations objectAtIndex: i], [distances objectAtIndex: i], nil];
    [tableViewArray addObject: newItem];
}

// Now, sort the new array based upon the distance in the second element
// of each array (ie, the distance).
[tableViewArray sortUsingComparator: ^(id obj1, id obj2) {
    NSNumber *dist1 = [obj1 objectAtIndex:1];
    NSNumber *dist2 = [obj2 objectAtIndex:1];

    return [dist1 compare:dist2];
}];

searchResults = [NSMutableArray arrayWithCapacity:[tableViewArray count]];




searchItems = [[NSMutableArray alloc] init];

for (int i = 0; i < allAnnotations.count; i++) {
    NSArray *newItem = [NSArray arrayWithObjects: [[[tableViewArray objectAtIndex:i] objectAtIndex:0] subtitle], @"bla", nil];
    [searchItems addObject: newItem];
}

/*
for (int i=0; i<tableViewArray.count; i++) {
    [searchItems insertObject:[[[tableViewArray objectAtIndex:i] objectAtIndex:0] subtitle] atIndex:0];
}
*/

NSLog(@"searchitems count is %i", searchItems.count);

[tableView reloadData];

[locationManager stopUpdatingLocation];

}

    - (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
 /*
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[searchResults removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@",searchText];

// searchResults = [NSMutableArray arrayWithArray:[[tableViewArray objectAtIndex:1] filteredArrayUsingPredicate:predicate]];

*/

/*

searchResults = [[NSArray alloc]init];

NSPredicate *resultPredicate = [NSPredicate
                                predicateWithFormat:@"SELF contains[cd] %@",
                                searchText];

    searchResults =[searchItems filteredArrayUsingPredicate:resultPredicate];


*/

// Create index set of all objects in textArray that contain searchText:
NSIndexSet *set = [searchItems indexesOfObjectsPassingTest:
                   ^BOOL(NSString *text, NSUInteger idx, BOOL *stop) {
                       NSRange range = [text rangeOfString:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)];
                       return (range.location != NSNotFound);
                   }];

// Filter textArray:
filteredTextArray = [searchItems objectsAtIndexes:set];
// Filter distanceArray:
filteredDistanceArray = [distances objectsAtIndexes:set];

NSLog(@"filtered text array is %@", filteredTextArray);
NSLog(@"filtered distance array is %@",filteredDistanceArray);
War es hilfreich?

Lösung

If I understand your problem correctly, you have 2 separate arrays that are used as data source for the table view, let's call them textArray and distanceArray.

Now you filter the textArray according to the search string and you need the "corresponding" filtering of distanceArray.

One way to do this is to replace filteredArrayUsingPredicate with indexesOfObjectsPassingTest, because that returns a set of matching indices that can be applied to both arrays:

// Create index set of all objects in textArray that contain searchText:
NSIndexSet *set = [textArray indexesOfObjectsPassingTest:
    ^BOOL(NSString *text, NSUInteger idx, BOOL *stop) {
        NSRange range = [text rangeOfString:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)];
        return (range.location != NSNotFound);
    }];

// Filter textArray:
filteredTextArray = [textArray objectsAtIndexes:set];
// Filter distanceArray:
filteredDistanceArray = [distanceArray objectsAtIndexes:set];

Now you can use filteredTextArray and filteredDistanceArray as data source for the search table view.

Alternatively, you could use a single array as data source if each object in the array is for example a dictionary containing both text and distance for one row.

UPDATE: As I understand it now, each item of your tableViewArray is an array with 2 items (one for the text and one for the distance).

In this case I would recommend to filter the tableViewArray directly:

NSIndexSet *set = [tableViewArray indexesOfObjectsPassingTest:
                   ^BOOL(NSArray *item, NSUInteger idx, BOOL *stop) {
                       NSString *subtitle = [[item objectAtIndex:0] subtitle];
                       NSRange range = [subtitle rangeOfString:searchText options:(NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch)];
                       return (range.location != NSNotFound);
                   }];

searchResults = [tableViewArray objectsAtIndexes:set];

Now searchResults is the filtered array, and each item has the same structure as the items in tableViewArray.

This simplifies things in cellForRowAtIndexPath, e.g.

if (theTableView == self.searchDisplayController.searchResultsTableView) {
    cell.textLabel.text = [[[searchResults objectAtIndex:indexPath.row] objectAtIndex:0] subtitle];
     distance = [[[searchResults objectAtIndex:indexPath.row] objectAtIndex: 1] doubleValue];
} else {
    cell.textLabel.text = [[[tableViewArray objectAtIndex:indexPath.row] objectAtIndex:0] subtitle];
    distance = [[[tableViewArray objectAtIndex:indexPath.row] objectAtIndex: 1] doubleValue];
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top