code

UIS 검색 디스플레이 컨트롤러/UIS 검색 막대를 사용하여 NSFetched Results Controller(핵심 데이터)를 필터링하는 방법

starcafe 2023. 6. 27. 22:26
반응형

UIS 검색 디스플레이 컨트롤러/UIS 검색 막대를 사용하여 NSFetched Results Controller(핵심 데이터)를 필터링하는 방법

코어데이터 기반 아이폰 앱에서 검색 코드를 구현하려고 합니다.어떻게 진행해야 할지 잘 모르겠습니다.앱에 주 TableView에 대한 데이터를 검색하기 위한 술어가 있는 NSFetchedResultsController가 이미 있습니다.코드를 너무 많이 변경하기 전에 올바른 길을 가고 있는지 확인하고 싶습니다.많은 예시들이 CoreData가 아닌 어레이 기반이기 때문에 혼란스럽습니다.

다음은 몇 가지 질문입니다.

  1. 일치하는 항목만 검색하는 두 번째 NSFetchedResultsController가 필요합니까? 아니면 기본 TableView와 동일한 항목을 사용할 수 있습니까?

  2. 동일한 것을 사용하는 경우 FRC 캐시를 지우고 handleSearchForTerm:searchString 메서드에서 술어를 변경하는 것처럼 간단합니까?술어는 검색어뿐만 아니라 초기 술어도 포함해야 합니까? 아니면 술어를 사용하여 데이터를 검색한 것을 기억합니까?

  3. 원래 결과로 돌아가려면 어떻게 해야 합니까?검색 술어를 0으로 설정하면 됩니까?애초에 FRC 결과를 검색하는 데 사용된 원래 술어를 죽이지 않을까요?

FRC와 함께 검색을 이용한 코드의 예를 가진 사람이 있다면 매우 감사하겠습니다!

저는 사실 이것을 제 프로젝트 중 하나에 구현했습니다(당신의 질문과 다른 오답은 무엇을 해야 할지 암시했습니다).나는 Sergio의 답변을 시도했지만 실제로 기기에서 실행할 때 예외 문제가 발생했습니다.

예, 두 개의 가져오기 결과 컨트롤러를 만듭니다. 하나는 일반 디스플레이용이고 다른 하나는 UIS 검색 막대의 테이블 보기용입니다.

하나의 FRC(NSFetchedResultsController)만 사용하는 경우 FRC의 필터링된 버전을 검색하는 동안 원래 UITableView(검색 중 활성화된 검색 테이블 뷰가 아님)에 콜백이 있을 수 있으며, 잘못된 섹션 또는 행 수에 대한 예외가 표시됩니다.섹션.

다음은 제가 한 일입니다. 속성 fetchedResultsController 및 searchFetchedResultsController로 사용할 수 있는 FRC가 두 개 있습니다.검색이 없는 한 searchFetchedResultsController를 사용하면 안 됩니다(검색이 취소되면 아래에서 이 개체가 해제되었음을 알 수 있습니다).모든 UITableView 메서드는 쿼리할 테이블 뷰와 정보를 가져올 해당 FRC를 파악해야 합니다.또한 FRC 위임 방법은 업데이트할 tableView를 파악해야 합니다.

이것이 얼마나 상용어구 코드인지 놀랍습니다.

헤더 파일의 관련 비트:

@interface BlahViewController : UITableViewController <UISearchBarDelegate, NSFetchedResultsControllerDelegate, UISearchDisplayDelegate> 
{
    // other class ivars

    // required ivars for this example
    NSFetchedResultsController *fetchedResultsController_;
    NSFetchedResultsController *searchFetchedResultsController_;
    NSManagedObjectContext *managedObjectContext_;

    // The saved state of the search UI if a memory warning removed the view.
    NSString        *savedSearchTerm_;
    NSInteger       savedScopeButtonIndex_;
    BOOL            searchWasActive_;
}
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSFetchedResultsController *fetchedResultsController;

@property (nonatomic, copy) NSString *savedSearchTerm;
@property (nonatomic) NSInteger savedScopeButtonIndex;
@property (nonatomic) BOOL searchWasActive;

구현 파일의 관련 비트:

@interface BlahViewController ()
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSFetchedResultsController *searchFetchedResultsController;
@property (nonatomic, retain) UISearchDisplayController *mySearchDisplayController;
@end

모든 UITableViewDelegate/DataSource 메서드를 사용할 때 올바른 FRC를 검색할 수 있는 유용한 메서드를 만들었습니다.

- (NSFetchedResultsController *)fetchedResultsControllerForTableView:(UITableView *)tableView
{
    return tableView == self.tableView ? self.fetchedResultsController : self.searchFetchedResultsController;
}

- (void)fetchedResultsController:(NSFetchedResultsController *)fetchedResultsController configureCell:(UITableViewCell *)theCell atIndexPath:(NSIndexPath *)theIndexPath
{
    // your cell guts here
}

- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)theIndexPath
{
    CallTableCell *cell = (CallTableCell *)[theTableView dequeueReusableCellWithIdentifier:@"CallTableCell"];
    if (cell == nil) 
    {
        cell = [[[CallTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CallTableCell"] autorelease];
    }

    [self fetchedResultsController:[self fetchedResultsControllerForTableView:theTableView] configureCell:cell atIndexPath:theIndexPath];
    return cell;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{
    NSInteger count = [[[self fetchedResultsControllerForTableView:tableView] sections] count];

    return count;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    NSInteger numberOfRows = 0;
    NSFetchedResultsController *fetchController = [self fetchedResultsControllerForTableView:tableView];
    NSArray *sections = fetchController.sections;
    if(sections.count > 0) 
    {
        id <NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:section];
        numberOfRows = [sectionInfo numberOfObjects];
    }

    return numberOfRows;

}

검색 줄의 위임 방법:

#pragma mark -
#pragma mark Content Filtering
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSInteger)scope
{
    // update the filter, in this case just blow away the FRC and let lazy evaluation create another with the relevant search info
    self.searchFetchedResultsController.delegate = nil;
    self.searchFetchedResultsController = nil;
    // if you care about the scope save off the index to be used by the serchFetchedResultsController
    //self.savedScopeButtonIndex = scope;
}


#pragma mark -
#pragma mark Search Bar 
- (void)searchDisplayController:(UISearchDisplayController *)controller willUnloadSearchResultsTableView:(UITableView *)tableView;
{
    // search is done so get rid of the search FRC and reclaim memory
    self.searchFetchedResultsController.delegate = nil;
    self.searchFetchedResultsController = nil;
}

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

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] 
                               scope:[self.searchDisplayController.searchBar selectedScopeButtonIndex]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}

FRC 위임 방법에서 업데이트를 가져올 때 올바른 테이블 보기를 사용해야 합니다.

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
{
    UITableView *tableView = controller == self.fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;
    [tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller 
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex 
     forChangeType:(NSFetchedResultsChangeType)type 
{
    UITableView *tableView = controller == self.fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;

    switch(type) 
    {
        case NSFetchedResultsChangeInsert:
            [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller 
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)theIndexPath 
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath 
{
    UITableView *tableView = controller == self.fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;

    switch(type) 
    {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:theIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self fetchedResultsController:controller configureCell:[tableView cellForRowAtIndexPath:theIndexPath] atIndexPath:theIndexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:theIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{
    UITableView *tableView = controller == self.fetchedResultsController ? self.tableView : self.searchDisplayController.searchResultsTableView;
    [tableView endUpdates];
}

기타 보기 정보:

- (void)loadView 
{   
    [super loadView];
    UISearchBar *searchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 44.0)] autorelease];
    searchBar.autoresizingMask = (UIViewAutoresizingFlexibleWidth);
    searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
    self.tableView.tableHeaderView = searchBar;

    self.mySearchDisplayController = [[[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self] autorelease];
    self.mySearchDisplayController.delegate = self;
    self.mySearchDisplayController.searchResultsDataSource = self;
    self.mySearchDisplayController.searchResultsDelegate = self;
}

- (void)didReceiveMemoryWarning
{
    self.searchWasActive = [self.searchDisplayController isActive];
    self.savedSearchTerm = [self.searchDisplayController.searchBar text];
    self.savedScopeButtonIndex = [self.searchDisplayController.searchBar selectedScopeButtonIndex];

    fetchedResultsController_.delegate = nil;
    [fetchedResultsController_ release];
    fetchedResultsController_ = nil;
    searchFetchedResultsController_.delegate = nil;
    [searchFetchedResultsController_ release];
    searchFetchedResultsController_ = nil;

    [super didReceiveMemoryWarning];
}

- (void)viewDidDisappear:(BOOL)animated
{
    // save the state of the search UI so that it can be restored if the view is re-created
    self.searchWasActive = [self.searchDisplayController isActive];
    self.savedSearchTerm = [self.searchDisplayController.searchBar text];
    self.savedScopeButtonIndex = [self.searchDisplayController.searchBar selectedScopeButtonIndex];
}

- (void)viewDidLoad
{
    // restore search settings if they were saved in didReceiveMemoryWarning.
    if (self.savedSearchTerm)
    {
        [self.searchDisplayController setActive:self.searchWasActive];
        [self.searchDisplayController.searchBar setSelectedScopeButtonIndex:self.savedScopeButtonIndex];
        [self.searchDisplayController.searchBar setText:savedSearchTerm];

        self.savedSearchTerm = nil;
    }
}

FRC 생성 코드:

- (NSFetchedResultsController *)newFetchedResultsControllerWithSearch:(NSString *)searchString
{
    NSArray *sortDescriptors = // your sort descriptors here
    NSPredicate *filterPredicate = // your predicate here

    /*
     Set up the fetched results controller.
     */
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *callEntity = [MTCall entityInManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:callEntity];

    NSMutableArray *predicateArray = [NSMutableArray array];
    if(searchString.length)
    {
        // your search predicate(s) are added to this array
        [predicateArray addObject:[NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", searchString]];
        // finally add the filter predicate for this view
        if(filterPredicate)
        {
            filterPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:filterPredicate, [NSCompoundPredicate orPredicateWithSubpredicates:predicateArray], nil]];
        }
        else
        {
            filterPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicateArray];
        }
    }
    [fetchRequest setPredicate:filterPredicate];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                                                                                managedObjectContext:self.managedObjectContext 
                                                                                                  sectionNameKeyPath:nil 
                                                                                                           cacheName:nil];
    aFetchedResultsController.delegate = self;

    [fetchRequest release];

    NSError *error = nil;
    if (![aFetchedResultsController performFetch:&error]) 
    {
        /*
         Replace this implementation with code to handle the error appropriately.

         abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
         */
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return aFetchedResultsController;
}    

- (NSFetchedResultsController *)fetchedResultsController 
{
    if (fetchedResultsController_ != nil) 
    {
        return fetchedResultsController_;
    }
    fetchedResultsController_ = [self newFetchedResultsControllerWithSearch:nil];
    return [[fetchedResultsController_ retain] autorelease];
}   

- (NSFetchedResultsController *)searchFetchedResultsController 
{
    if (searchFetchedResultsController_ != nil) 
    {
        return searchFetchedResultsController_;
    }
    searchFetchedResultsController_ = [self newFetchedResultsControllerWithSearch:self.searchDisplayController.searchBar.text];
    return [[searchFetchedResultsController_ retain] autorelease];
}   

어떤 사람들은 이것이 한 번으로 이루어질 수 있다고 말했습니다.NSFetchedResultsController그게 제가 한 일이고, 여기 세부사항이 있습니다.이 솔루션에서는 테이블을 필터링하고 검색 결과의 다른 모든 측면(정렬 순서, 셀 레이아웃 등)을 유지하려고 한다고 가정합니다.

두가지 에서 두 합니다.UITableViewController하위 클래스(해당되는 경우 적절한 @sysize 및 dealloc 사용):

@property (nonatomic, retain) UISearchDisplayController *searchController;
@property (nonatomic, retain) NSString *searchString;

번째, 두검번로, 합니다.viewDidLoad:의 의방의 UITableViewController하위 클래스:

UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0,0,self.tableView.frame.size.width,44)]; 
searchBar.placeholder = @"Search";
searchBar.delegate = self;
self.searchController = [[[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self] autorelease];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;   
self.searchController.searchResultsDelegate = self; 
self.tableView.tableHeaderView = self.searchController.searchBar;
[searchBar release];

셋째, 다음을 구현합니다.UISearchDisplayController다음과 같은 위임 메서드:

// This gets called when you start typing text into the search bar
-(BOOL)searchDisplayController:(UISearchDisplayController *)_controller shouldReloadTableForSearchString:(NSString *)_searchString {
   self.searchString = _searchString;
   self.fetchedResultsController = nil;
   return YES;
}

// This gets called when you cancel or close the search bar
-(void)searchDisplayController:(UISearchDisplayController *)controller willUnloadSearchResultsTableView:(UITableView *)tableView {
   self.searchString = nil;
   self.fetchedResultsController = nil;
   [self.tableView reloadData];
}

에서.fetchedResultsController the 방법변경NSPredicate의 에 따라self.searchString정의됨:

-(NSFetchedResultsController *)fetchedResultsController {
   if (fetchedResultsController == nil) {

       // removed for brevity

      NSPredicate *predicate;

      if (self.searchString) {
         // predicate that uses searchString (used by UISearchDisplayController)
         // e.g., [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@", self.searchString];
          predicate = ... 
      } else {
         predicate = ... // predicate without searchString (used by UITableViewController)
      }

      // removed for brevity

   }

   return fetchedResultsController;
} 

이 일을 성공시키려면 몇 번의 시도가 필요했습니다.

제가 이해한 핵심은 여기에 두 개의 tableview가 있다는 것을 깨닫는 것이었습니다.하나는 내 뷰 컨트롤러에 의해 관리되고 하나는 검색 뷰 컨트롤러에 의해 관리되며 어떤 것이 활성화되어 있고 올바른 작업을 수행하는지 테스트할 수 있습니다.설명서도 도움이 되었습니다.

http://developer.apple.com/library/ios/ #documentation/uikit/reference/UISearchDisplayController_Class/Reference/Reference.html

제가 한 일은 이렇습니다.

searchIsActive 플래그가 추가되었습니다.

@interface ItemTableViewController : UITableViewController <NSFetchedResultsControllerDelegate, UISearchDisplayDelegate, UISearchBarDelegate> {

    NSString *sectionNameKeyPath;
    NSArray *sortDescriptors;


@private
    NSFetchedResultsController *fetchedResultsController_;
    NSManagedObjectContext *managedObjectContext_;

    BOOL searchIsActive;

}

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSString *sectionNameKeyPath;
@property (nonatomic, retain) NSArray *sortDescriptors;
@property (nonatomic) BOOL searchIsActive;

구현 파일에 합성을 추가했습니다.

그런 다음 검색을 위해 다음 방법을 추가했습니다.

#pragma mark -
#pragma mark Content Filtering

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    NSFetchRequest *aRequest = [[self fetchedResultsController] fetchRequest];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", searchText];

    [aRequest setPredicate:predicate];

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // Handle error
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }  

}

#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:nil];

    return YES;
}

/*
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
    return YES;
}
*/

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
    [self setSearchIsActive:YES];
    return;
}

- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller 
{
    NSFetchRequest *aRequest = [[self fetchedResultsController] fetchRequest];

    [aRequest setPredicate:nil];

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // Handle error
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }  

    [self setSearchIsActive:NO];
    return;
}

그러면 컨트롤러에서 내용이 변경됩니다.

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
{
    if ([self searchIsActive]) {
        [[[self searchDisplayController] searchResultsTableView] beginUpdates];
    }
    else  {
        [self.tableView beginUpdates];
    }
}

컨트롤러가 콘텐츠를 변경했습니다.

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{
    if ([self searchIsActive]) {
        [[[self searchDisplayController] searchResultsTableView] endUpdates];
    }
    else  {
        [self.tableView endUpdates];
    }
}

그리고 술어를 재설정할 때 캐시를 삭제합니다.

이게 도움이 되길 바랍니다.

Swift 3.0, UIS 검색 컨트롤러, NSFetched Results Controller 및 핵심 데이터

3.0과 함께 Swift 3합니다.Core Data모델에서 개체를 필터링하고 검색하려면 단일 대리자 메서드와 몇 줄의 코드가 필요합니다.모든 기능을 구현한 경우에는 필요하지 않습니다.FRC그리고 그들의delegate및 법뿐만아라니방.searchController.

UISearchResultsUpdating 방법

func updateSearchResults(for searchController: UISearchController) {

    let text = searchController.searchBar.text

    if (text?.isEmpty)! {
       // Do something 
    } else {
        self.fetchedResultsController.fetchRequest.predicate = NSPredicate(format: "( someString contains[cd] %@ )", text!)
    }
    do {
        try self.fetchedResultsController.performFetch()
        self.tableView.reloadData()
    } catch {}
}

바로 그거야!도움이 되길 바랍니다!감사해요.

저는 같은 과제에 직면했고 그것을 해결할 수 있는 가장 간단한 방법을 찾았습니다.요약: 다음과 매우 유사한 방법을 하나 더 정의해야 합니다.-fetchedResultsController사용자 지정 복합 술어를 사용합니다.

나의 개인적인 경우에 나의-fetchedResultsController다음과 같이 표시됩니다.

- (NSFetchedResultsController *) fetchedResultsController
{
    if (fetchedResultsController != nil)
    {
        return fetchedResultsController;
    }
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Client"
                                              inManagedObjectContext:[[PTDataManager sharedManager] managedObjectContext]];
    [fetchRequest setEntity:entity];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"agency_server_id == %@", agency.server_id];
    fetchRequest.predicate = predicate;

    NSSortDescriptor *sortByName1Descriptor = [[NSSortDescriptor alloc] initWithKey:@"lastname" ascending:YES];
    NSSortDescriptor *sortByName2Descriptor = [[NSSortDescriptor alloc] initWithKey:@"firstname" ascending:YES];
    NSSortDescriptor *sortByName3Descriptor = [[NSSortDescriptor alloc] initWithKey:@"middlename" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortByName1Descriptor, sortByName2Descriptor, sortByName3Descriptor, nil];

    fetchRequest.sortDescriptors = sortDescriptors;

    fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:[[PTDataManager sharedManager] managedObjectContext] sectionNameKeyPath:nil cacheName:nil];
    fetchedResultsController.delegate = self;
    return fetchedResultsController;
}

보시다시피, 저는 한 기관의 고객들을 데려오고 있습니다.agency.server_id술어결과적으로 콘텐츠를 검색하는 중입니다.tableView(모든 것이 의 구현과 관련됨)tableView그리고.fetchedResultsController코드는 꽤 표준적입니다.구현하기searchField내가 정의하는 것은UISearchBarDelegate위임 방식나는 검색 방법으로 그것을 촉발하고 있습니다, 라고 말합니다.-reloadTableView:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    [self reloadTableView];
}

그리고 물론 정의는.-reloadTableView:

- (void)reloadTableView
{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Client"
                                              inManagedObjectContext:[[PTDataManager sharedManager] managedObjectContext]];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sortByName1Descriptor = [[NSSortDescriptor alloc] initWithKey:@"lastname" ascending:YES];
    NSSortDescriptor *sortByName2Descriptor = [[NSSortDescriptor alloc] initWithKey:@"firstname" ascending:YES];
    NSSortDescriptor *sortByName3Descriptor = [[NSSortDescriptor alloc] initWithKey:@"middlename" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects: sortByName1Descriptor, sortByName2Descriptor, sortByName3Descriptor, nil];
    fetchRequest.sortDescriptors = sortDescriptors;

    NSPredicate *idPredicate = [NSPredicate predicateWithFormat:@"agency_server_id CONTAINS[cd] %@", agency.server_id];
    NSString *searchString = self.searchBar.text;
    if (searchString.length > 0)
    {
        NSPredicate *firstNamePredicate = [NSPredicate predicateWithFormat:@"firstname CONTAINS[cd] %@", searchString];
        NSPredicate *lastNamePredicate = [NSPredicate predicateWithFormat:@"lastname CONTAINS[cd] %@", searchString];
        NSPredicate *middleNamePredicate = [NSPredicate predicateWithFormat:@"middlename CONTAINS[cd] %@", searchString];
        NSPredicate *orPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:[NSArray arrayWithObjects:firstNamePredicate, lastNamePredicate, middleNamePredicate, nil]];
        NSPredicate *andPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:idPredicate, nil]];
        NSPredicate *finalPred = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:orPredicate, andPredicate, nil]];
        [fetchRequest setPredicate:finalPred];
    }
    else
    {
        [fetchRequest setPredicate:idPredicate];
    }

    self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:[[PTDataManager sharedManager] managedObjectContext] sectionNameKeyPath:nil cacheName:nil];
    self.fetchedResultsController.delegate = self;

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error])
    {
        NSLog(@"Unresolved error %@, %@", [error localizedDescription], [error localizedFailureReason]);
    }; 

    [self.clientsTableView reloadData];
}

이 코드 묶음은 처음의 "표준"과 매우 유사합니다.-fetchedResultsController 그러나 if-else 문장 안에는 다음이 있습니다.

+andPredicateWithSubpredicates:이 방법을 사용하여 우리는 술어를 설정하여 우리의 첫 번째 주요 페치의 결과를 저장할 수 있습니다.tableView

+orPredicateWithSubpredicates이 방법을 사용하여 검색 쿼리에 의해 기존 가져오기를 필터링하고 있습니다.searchBar

마지막에 저는 술어 배열을 이 특정한 fetch에 대한 복합 술어로 설정하고 있습니다. 그리고 필요한 술어에 대해서는 OR, 선택 사항에 대해서는 OR.

그게 다야!더 이상 구현할 필요가 없습니다.해피 코딩!

실시간 검색을 사용하고 있습니까?

그렇지 않은 경우 이전에 사용한 검색과 함께 배열(또는 NSFetchedResultsController)을 원할 수 있습니다. 사용자가 "검색"을 누르면 FetchedResults에 술어를 변경하도록 지시합니다.

어느 쪽이든 매번 Fetched Results를 다시 작성해야 합니다.코드를 많이 복제해야 하고 표시되지 않는 항목에서 메모리를 낭비할 필요가 없기 때문에 NSFetched Results Controller를 하나만 사용하는 것이 좋습니다.

NSString "searchParameters" 변수가 있는지 확인하고 필요에 따라 FetchedResults 메서드가 이 변수를 재구성합니다. 가능한 경우 검색 매개 변수를 사용하여 다음 작업을 수행해야 합니다.

searchParameters를 something(또는 모든 결과를 원하는 경우 0)으로 설정합니다.

해제하고 현재 NSFetchedResultsController 개체를 0으로 설정합니다.

테이블 데이터를 다시 로드합니다.

간단한 코드는 다음과 같습니다.

- (void)searchString:(NSString*)s {
    self.searchResults = s;
    [fetchedResultsController release];
    fetchedResultsController = nil;
    [self.tableView reloadData];
}

-(NSFetchedResultsController *)fetchedResultsController {
    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"EntityName" inManagedObjectContext:self.context];
    [fetchRequest setEntity:entity];

    [fetchRequest setFetchBatchSize:20];

    // searchResults is a NSString*
    if (searchResults != nil) {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name LIKE %@",searchResults];
        [fetchRequest setPredicate:predicate];
    }

    fetchedResultsController = 
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
        managedObjectContext:self.context sectionNameKeyPath:nil 
        cacheName:nil];
    fetchedResultsController.delegate = self;

    [fetchRequest release];

    return fetchedResultsController;    
}

SWIFT 3.0

textField를 사용합니다. iOS 8부터는 UI 검색 디스플레이 컨트롤러가 사용되지 않습니다. UI 검색 컨트롤러를 사용해야 합니다.검색 컨트롤러를 다루는 대신, 독자적인 검색 메커니즘을 만드는 것은 어떻습니까?더 많은 사용자 지정 및 제어 권한을 가질 수 있으며, 검색 컨트롤러가 변경되거나 더 이상 사용되지 않을 수 있습니다.

제가 사용하는 이 방법은 매우 잘 작동하고 코드가 많이 필요하지 않습니다.그러나 코어 데이터를 사용하고 NSFetched Results Controller를 구현해야 합니다.

먼저 TextField를 만들고 다음 메서드에 등록합니다.

searchTextField?.addTarget(self, action: #selector(textFieldDidChange), for: UIControlEvents.editingChanged)

그런 다음 대상이 추가될 때 선택기에 설명된 textFieldDidChange 메서드를 만듭니다.

func textFieldDidChange() {
    if let queryString = searchTextField.text {
        filterList(queryString)
        self.tableView.reloadData()
    }
}

목록을 다목필니다합링터록을그에서 .filterList()더 복잡한 경우 NSPredicate 또는 NSCombound 서술어를 사용하는 방법.filterList 메서드에서 엔티티 이름과 엔티티 "subCategories" 개체의 이름(하나에서 여러 개의 관계)을 기준으로 필터링합니다.

func filterList(_ queryString: String) {
    if let currentProjectID = Constants.userDefaults.string(forKey: Constants.CurrentSelectedProjectID) {
        if let currentProject = ProjectDBFacade.getProjectWithID(currentProjectID) {
            if (queryString != ""){
                let categoryPredicate = NSPredicate(format: "name CONTAINS[c] %@ && project == %@", queryString, currentProject)
                let subCategoryPredicate = NSPredicate(format: "subCategories.name CONTAINS[c] %@ && project == %@", queryString, currentProject)
                let orPredicate = NSCompoundPredicate(type: .or, subpredicates: [categoryPredicate, subCategoryPredicate])
                fetchedResultsController.fetchRequest.predicate = orPredicate
            }else{
                fetchedResultsController.fetchRequest.predicate = NSPredicate(format: "project == %@", currentProject)
            }

            do {
                try fetchedResultsController.performFetch()
            } catch {
                print("Error:  Could not fetch fetchedResultsController")
            }
        }
    }
}

CoreData를 사용하여 기존 UITableView를 필터링하고 원하는 방식으로 이미 정렬된 간단한 접근 방식입니다.

이 작업은 말 그대로 설정하고 작업하는 데 5분이 걸렸습니다.

나는 존재했습니다.UITableView용사를 CoreData 사용자 작용이 하며 iCloud의 UISearchViewController▁add▁pred▁a다에 간단히 술어를 추가할 수 있었습니다.FetchRequest이사용중에서 FetchResultsController이미 정렬된 데이터를 필터링합니다.

-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    NSPredicate *filterPredicate;

    if(searchText != nil && searchText.length > 0)
        filterPredicate = [NSPredicate predicateWithFormat:@"(someField CONTAINS[cd] %@) OR (someOtherField CONTAINS[cd] %@)", searchText, searchText];
    else
        filterPredicate = nil;

    _fetchedResultsController.fetchRequest.predicate = filterPredicate;

    NSError *error = nil;
    [_fetchedResultsController performFetch:&error];
    [self.tableView reloadData];
}

저는 루카가 이를 위해 더 나은 접근법을 가지고 있다고 생각합니다. 데이터 집합 표본 및 그 이유 참조

그는 사용하지 않습니다.FetchedResultsController때에 더 하면 검색 나타납니다.

저는 제 앱에서 그의 접근 방식을 사용했고 그것은 잘 작동합니다.또한 모델 개체로 작업하려면 가능한 한 단순하게 하고 setProperties에 대한 내 대답을 참조하십시오.가져오는 방법

다음은 거의 모든 곳에 적용할 수 있을 정도로 간단하고 일반적인 여러 데이터 세트를 사용하여 fetchedResults를 처리하는 방법입니다.어떤 조건이 존재할 때 기본 결과를 배열로 가져오기만 하면 됩니다.

NSArray *results = [self.fetchedResultsController fetchedObjects];

기본으로 가져온 결과의 하위 집합을 만들기 위해 배열을 반복하거나 원하는 대로 배열을 쿼리합니다.이제 전체 집합을 사용하거나 어떤 조건이 있을 때 부분 집합을 사용할 수 있습니다.

O'Connor @Josh O'Connor @ O'Connor의 이 정말 마음에 들었습니다.UISearchController이 컨트롤러(Xcode 9)에 레이아웃 버그가 있어 많은 이들이 해결하려고 합니다.

다시 사용하기 시작했습니다.UISearchBar신에대 UITextField그리고 꽤 잘 작동합니다.의 요구사항은 "/" "/" "/" "/" "/" "/" "/"를 생성하는 입니다.NSPredicateFRC로 됩니다.

   class ViewController: UIViewController, UITableViewDelegate, 
 UITableViewDataSource, UISearchBarDelegate {

        @IBOutlet var searchBar: UISearchBar!

         func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

                shouldShowSearchResults = true

                if let queryString = searchBar.text {
                    filterList(queryString)

                    fetchData()
                }
            }



          func filterList(_ queryString: String) {
        if (queryString == "") {
            searchPredicate = nil
    }
        else {
            let brandPredicate = NSPredicate(format: "brand CONTAINS[c] %@", queryString)
            let modelPredicate = NSPredicate(format: "model CONTAINS[c] %@", queryString)
            let orPredicate = NSCompoundPredicate(type: .or, subpredicates: [brandPredicate, modelPredicate])
            searchPredicate = orPredicate
    }

}

...

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        let request = NSFetchRequest<NSFetchRequestResult>(entityName: filmEntity)
        request.returnsDistinctResults = true
        request.propertiesToFetch = ["brand", "model"]

        request.sortDescriptors = [sortDescriptor]
        request.predicate = searchPredicate

마지막으로 검색 막대를 대리자에게 연결합니다.

이것이 다른 사람들에게 도움이 되기를 바랍니다.

언급URL : https://stackoverflow.com/questions/4471289/how-to-filter-nsfetchedresultscontroller-coredata-with-uisearchdisplaycontroll

반응형