解析搜索表未返回正确结果

Posted

技术标签:

【中文标题】解析搜索表未返回正确结果【英文标题】:Parse search table not returning correct results 【发布时间】:2015-03-17 23:05:11 【问题描述】:

我使用 parse 作为我的应用程序的后端。我发现了几种不同的方法来使用 Parse tableview 实现搜索栏功能。我从 Parse 档案中找到的这个想法在初始视图和刷新时显示了所有对象,但是当我搜索时它不会返回正确的结果。如果我输入一个字母“a”,它会返回一些包含“a”的对象,但如果我输入更多字母或我知道应该找到的实际单词,它会返回一个空白表。搜索时还会发出警告:正在主线程上执行长时间运行的 Parse 操作。我已经工作和研究了几个星期,无法超越这一点。实现文件见代码。

#import "RecipeBookViewController.h"
#import "SearchedResultCell.h"
#import "RecipeDetailViewController.h"
#import "HotelViewController.h"
#import "Recipe.h"

static NSString *const NothingFoundCellIdentifier = @"NothingFoundCell";

@interface RecipeBookViewController ()


@end


@implementation RecipeBookViewController 



@synthesize searchedBar;
@synthesize searchResults;
@synthesize recipesTable;

- (id)initWithCoder:(NSCoder *)aCoder

self = [super initWithCoder:aCoder];
if (self) 
    // Custom the table

    // The className to query on
    self.parseClassName = @"Recipe";

    // The key of the PFObject to display in the label of the default cell         style
    self.textKey = @"name";

    // Whether the built-in pull-to-refresh is enabled
    self.pullToRefreshEnabled = YES;

    // Whether the built-in pagination is enabled
    self.paginationEnabled = NO;

    // The number of objects to show per page
    //self.objectsPerPage = 10;

return self;


- (void)didReceiveMemoryWarning 
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.


#pragma mark - UIViewController

- (void)viewDidLoad

[super viewDidLoad];

    UINib *cellNib = [UINib nibWithNibName:NothingFoundCellIdentifier     bundle:nil];
    [self.tableView registerNib:cellNib     forCellReuseIdentifier:NothingFoundCellIdentifier];

[self.searchedBar becomeFirstResponder];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(refreshTable:)
                                             name:@"refreshTable"
                                           object:nil];


- (void)refreshTable:(NSNotification *) notification

// Reload the recipes
[self loadObjects];


- (void)viewDidUnload

[super viewDidUnload];
// Release any retained subviews of the main view.
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"refreshTable"         object:nil];


#pragma mark - UISearchBarDelegate

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar

[searchResults removeAllObjects];

[self.searchedBar resignFirstResponder];

searchResults = [NSMutableArray arrayWithCapacity:10];

//#warning Put your ClassName here
PFQuery *query = [PFQuery queryWithClassName:@"Recipe"];

//#warning put key that you want to search here
[query whereKey:@"name" containsString:searchedBar.text];

NSArray *results = [query findObjects];

[searchResults addObjectsFromArray:results];

//#warning put your key here
[query orderByAscending:@"name"];

//[self queryForTable];
[self loadObjects];



#pragma mark - PFQueryTableViewController

- (void)objectsWillLoad 
[super objectsWillLoad];

// This method is called before a PFQuery is fired to get more objects


- (void) objectsDidLoad:(NSError *)error

[super objectsDidLoad:error];

NSLog(@"error: %@", [error localizedDescription]);


#pragma mark - Query

- (PFQuery *)queryForTable

PFQuery *query;

if (self.searchResults == 0) 
    query = [PFQuery queryWithClassName:self.parseClassName];
 else 
    query = [PFQuery queryWithClassName:self.parseClassName];

    NSString *searchThis = [searchedBar.text lowercaseString];
    //#warning key you wanted to search here
    [query whereKeyExists:@"name"];
    [query whereKey:@"name" containsString:searchThis];


[query orderByAscending:@"name"];

// If Pull To Refresh is enabled, query against the network by default.
if (self.pullToRefreshEnabled) 
    query.cachePolicy = kPFCachePolicyNetworkOnly;


// If no objects are loaded in memory, we look to the cache first to fill the     table
// and then subsequently do a query against the network.
if (self.objects.count == 0) 
    query.cachePolicy = kPFCachePolicyCacheThenNetwork;


return query;


/*
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:    (NSInteger)section
 
 if (searchResults == nil) 
 return 0;
  else if ([searchResults count] == 0) 
 return 1;
  else 
 return [self.objects count];
 
 
 */



// Override to customize the look of a cell representing an object. The     default is to display
// a UITableViewCellStyleDefault style cell with the label being the first key     in the object.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:        (NSIndexPath *)indexPath object:(PFObject *)object

static NSString *simpleTableIdentifier = @"RecipeCell";

UITableViewCell *cell = [tableView     dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault     reuseIdentifier:simpleTableIdentifier];
    

// Configure the cell
PFFile *thumbnail = [object objectForKey:@"imageFile"];
PFImageView *thumbnailImageView = (PFImageView*)[cell viewWithTag:100];
thumbnailImageView.image = [UIImage imageNamed:@"recipeBoxImage2.jpg"];
thumbnailImageView.file = thumbnail;
[thumbnailImageView loadInBackground];

UILabel *nameLabel = (UILabel*) [cell viewWithTag:101];
nameLabel.text = [object objectForKey:@"name"];

UILabel *prepTimeLabel = (UILabel*) [cell viewWithTag:102];
prepTimeLabel.text = [object objectForKey:@"prepTime"];

static NSString *LoadMoreCellIdentifier = @"LoadMoreCell";

UITableViewCell *loadcell = [self.tableView     dequeueReusableCellWithIdentifier:LoadMoreCellIdentifier];
if (!cell) 
    loadcell = [[UITableViewCell alloc]     initWithStyle:UITableViewCellStyleDefault reuseIdentifier:LoadMoreCellIdentifier];


return cell;


- (void)configureSearchResult:(SearchedResultCell *)cell atIndexPath:    (NSIndexPath *)indexPath object:(PFObject *)object

static NSString *simpleTableIdentifier = @"RecipeCell";

SearchedResultCell *searchcell = [self.tableView     dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (searchcell == nil) 
    searchcell = [[SearchedResultCell alloc]     initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];


// Configure the cell
PFFile *thumbnail = [object objectForKey:@"imageFile"];
PFImageView *thumbnailImageView = (PFImageView*)[cell viewWithTag:100];
thumbnailImageView.image = [UIImage imageNamed:@"recipeBoxImage2.jpg"];
thumbnailImageView.file = thumbnail;
[thumbnailImageView loadInBackground];

UILabel *nameLabel = (UILabel*) [cell viewWithTag:101];
nameLabel.text = [object objectForKey:@"name"];

UILabel *prepTimeLabel = (UILabel*) [cell viewWithTag:102];
prepTimeLabel.text = [object objectForKey:@"prepTime"];



// Set CellForRowAtIndexPath
- (UITableViewCell *)searchtableView:(UITableView *)searchtableView     cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object

static NSString *CellIdentifier = @"SearchResultCell";

//Custom Cell
SearchedResultCell *cell = [searchtableView     dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) 
    cell = [[SearchedResultCell alloc]     initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];


if ([searchResults count] == 0) 
    //cell.mainTitle.text = @"Nothing Found";
    return [self.tableView     dequeueReusableCellWithIdentifier:NothingFoundCellIdentifier];
 else 
    //#warning put your ClassName here
    PFObject *object = [PFObject objectWithClassName:@"Recipe"];
    object = [searchResults objectAtIndex:indexPath.row];
    [self configureSearchResult:cell atIndexPath:indexPath object:object];
    //[self configureSearchResult:cell atIndexPath:indexPath object:object];

    return cell;


- (UITableViewCell *)tableView:(UITableView *)tableView     cellForNextPageAtIndexPath:(NSIndexPath *)indexPath 
static NSString *LoadMoreCellIdentifier = @"LoadMoreCell";

UITableViewCell *cell = [tableView     dequeueReusableCellWithIdentifier:LoadMoreCellIdentifier];
if (!cell) 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault     reuseIdentifier:LoadMoreCellIdentifier];

return cell;


//// Set TableView Height for Load Next Page
//- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:    (NSIndexPath *)indexPath 
//    if([self.objects count] == indexPath.row) 
//        // Load More Cell Height
//        return 60.0;
//     else 
//        return 80.0;
//    
//


#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath


[tableView deselectRowAtIndexPath:indexPath animated:YES];

[searchedBar resignFirstResponder];

if ([self.objects count] == indexPath.row) 
    [self loadNextPage];
 else 
    PFObject *photo = [self.objects objectAtIndex:indexPath.row];
    NSLog(@"%@", photo);

    // Do something you want after selected the cell



#pragma mark - UIScrollViewDelegate


- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 
[self.searchedBar resignFirstResponder];


//- (void)tableView:(UITableView *)tableView commitEditingStyle:    (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath     *)indexPath
//
//    // Remove the row from data model
//    PFObject *object = [self.objects objectAtIndex:indexPath.row];
//    [object deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) 
//        [self refreshTable:nil];
//    ];
//


- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
if ([segue.identifier isEqualToString:@"showRecipeDetail"]) 
    NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
    RecipeDetailViewController *destViewController =     segue.destinationViewController;

    PFObject *object = [self.objects objectAtIndex:indexPath.row];
    Recipe *recipe = [[Recipe alloc] init];
    recipe.name = [object objectForKey:@"name"];
    recipe.imageFile = [object objectForKey:@"imageFile"];
    recipe.prepTime = [object objectForKey:@"prepTime"];
    recipe.ingredients = [object objectForKey:@"ingredients"];
    recipe.instructions = [object objectForKey:@"instructions"];
    recipe.servings = [object objectForKey:@"servings"];
    recipe.hotelSite = [object objectForKey:@"hotelSite"];
    recipe.recipeType = [object objectForKey:@"recipeType"];
    destViewController.recipe = recipe;




@end

【问题讨论】:

【参考方案1】:

找到这个 - 希望它可以帮助其他人 - 归功于 Bizzi-Body

https://github.com/Bizzi-Body/ParseTutorial-Part-2

//
//  GourmetChefViewController.m
//
//  Created by RedMac on 3/19/15.
//

#import "RecipeBookViewController.h"


@interface RecipeBookViewController ()

NSMutableArray *totalStrings;
NSMutableArray *filteredStrings;

BOOL isFiltered;


@end

@implementation RecipeBookViewController

#pragma mark -
#pragma mark UIViewController

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad

[super viewDidLoad];
self.mySearchBar.delegate =self;
self.myTableView.delegate = self;
self.myTableView.dataSource=self;

[self retrieveFromParse];




- (void) retrieveFromParse 
PFQuery *retrieveRecipes = [PFQuery queryWithClassName:@"Recipe"];
[retrieveRecipes  whereKeyExists:@"name"];

[retrieveRecipes findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) 
    if (!error) 
        NSLog(@"%@", objects);
        totalStrings = [[NSMutableArray alloc] initWithArray:objects];

    
    [self.myTableView reloadData];
];




-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
return 1;

-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *) searchText
if (searchText.length ==0)
    isFiltered =NO;
else
    isFiltered =YES;


    filteredStrings=[[NSMutableArray alloc]init];
    for(PFObject *element in totalStrings) 
        NSString * str = [element objectForKey:@"name"];
        NSLog(@"%@", NSStringFromClass([element class])); // you thought that totalStrings
        // contained NSString objects,
        // but it contains PFObjects.
        NSRange stringRange =[str rangeOfString:searchText options:NSCaseInsensitiveSearch];

        if (stringRange.location !=NSNotFound) 
            // you need to add the PFObject back to make your cellForRowAtIndexPath: method
            // work.
            [filteredStrings addObject:element]; // used to be :str
        
    


[self.myTableView reloadData];


//table view datasource and delegate method.....

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

if (isFiltered)
    return [filteredStrings count];
return [totalStrings count];


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


UITableViewCell *cell= [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
if (!cell)
    cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

if(!isFiltered)

    PFObject *tempObject =[totalStrings objectAtIndex: indexPath.row];
    cell.textLabel.text = [tempObject objectForKey:@"name"];

else

    PFObject *tempObject2 =[filteredStrings objectAtIndex: indexPath.row];
    cell.textLabel.text =[tempObject2  objectForKey:@"name"];

return cell;



- (void)didReceiveMemoryWarning 
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);


@end

【讨论】:

以上是关于解析搜索表未返回正确结果的主要内容,如果未能解决你的问题,请参考以下文章

从多个解析类正确返回结果

ElasticSearch - SpringBoot整合ES:解析搜索返回字段

UITableView / UISearchBar 返回不正确的结果

当搜索包含特殊字符时,Azure 搜索服务筛选器 search.ismatch() 未返回正确结果

SQL BETWEEN 查询返回不正确的结果

REST API 响应状态代码 - 搜索返回单个结果的 GET