xcode Loading a text string into a UISearchControl

2019-08-09 04:46发布

I was using this example for searching through a UICollectionView: https://github.com/ihomam/CollectionViewWithSearchBar/blob/master/collevtionViewWithSearchBar/CollectionViewController.m

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

    // Configure the cell
    if (self.searchBarActive) {
        cell.laName.text = self.dataSourceForSearchResult[indexPath.row];
    } else {
        cell.laName.text = self.dataSource[indexPath.row];
    }
    return cell;
}

...only my app is setup a little differently:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    PlaceCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

    Place *p = [_entries objectAtIndex:indexPath.item];
    if (self.searchBarActive) {
        cell.placeName.text = self.dataSourceForSearchResult[indexPath.item];
    } else {
        cell.placeName.text = p.PName;
        cell.placeImg.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:p.PImage]]];
    }
    return cell;
}

So if I just run it the way it is then self.dataSourceForSearchResult[indexpath.item] will return EVERYTHING and I get an error because it's not returning a string...

'Can't use in/contains operator with collection <Place: 0x17d8ad70> (not a collection)'

but what I want it to do is search through the p.PName results. Something like:

self.dataSourceForSearchResult[p.PName indexpath.item]

1条回答
我欲成王,谁敢阻挡
2楼-- · 2019-08-09 04:59

Having looked through the github code I think that the core of your problem lies somewhere else.

The problem lies here :

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope{
    NSPredicate *resultPredicate    = [NSPredicate predicateWithFormat:@"self contains[c] %@", searchText];
    self.dataSourceForSearchResult  = [self.dataSource filteredArrayUsingPredicate:resultPredicate];
}

What this method does is it filters matching items from self.datasource (which I assume you renamed to self.entries, and I hope you also did it here) based on the predicate. The predicate is a little tricky to understand, especially if you have no previous experience with them. Let's break it down :

  • self - in this context it means the object that will be checked against the condition. This object will be an element of the array.

  • contains[c] - this is the condition. The self will be checked if it contains something. The [c] means that the check will be case insensitive.

  • %@ - this is the 'something'. It will be replaced with searchText.

This worked in the example because the array contained NSString objects and NSPredicate knows how to check if they contain something (a substring). Since your array consists of Place objects the NSPredicate doesn't know how to check if they contain something (a subplace? :P).

To fix this replace the predicate with this one self.PName contains[c] %@. This one will acces the PName property of each object of array and check whether it contains the substring.

You can read more on NSPredicate on NSHipster and in the docs


As to the second problem, self.dataSourceForSearchResult[indexpath.item] will not in fact return an NSString but a Place object, though not EVERYTHING, but one of the filtered ones. It was actually never reached in your app, as it crashed earlier. No offence, but I think that you don't entirely understand the whole order of things in this code. To break it down :

  1. The view controller is shown and the searchbar is empty so the cells are drawn, based on data in self.datasource (or self.entries as you renamed it). collectionView:cellForItemAtIndexPath: is being called.
  2. User inputs something in the search bar. (this triggers searchBar:textDidChange:).
  3. The matching objects are filtered into self.dataSourceForSearchResult array.
  4. The collection view gets reloaded.
  5. The cells are redrawn (collectionView:cellForItemAtIndexPath: is being called again), but since the searchbar is not empty, we now use only objects from self.dataSourceForSearchResult.

So to make it work your - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath; should look like this :

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    PlaceCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

    Place *p;
    // retrieve item from appropriate array
    if (self.searchBarActive) {
        p = self.dataSourceForSearchResult[indexPath.item];
    } else {
        p = self.entries[indexPath.item];
    }

    // populate the cell - we do this regardless of whether the searchbar is active or not
    cell.placeName.text = p.PName;
    cell.placeImg.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:p.PImage]]];

    return cell;
}
查看更多
登录 后发表回答