UITableView doesn't refresh when NSPredicate set

流过昼夜 提交于 2020-01-06 18:43:31

问题


Preface: I tried [self.tableview reloadData]. My app doesn't crash, but it doesn't refresh, either.

I'm trying to display 2 sets of results on one TableViewController depending upon whether an NSPredicate is set. I'm trying to find a jargon free answer how I can update a UITableViewController once a predicate is set.

My data displays properly the when the view initially loads. My predicate sets properly, all the log statements I've thrown in return values...but nothing happens when it's set.

I know this is a startlingly stupid question, but I'm too dumb figure it out. Every answer I've found involves a UISearchBar, deprecated methods, or is a snippet of an answer, etc.

What I'd like to display:

1) A vanilla fetchRequest that displays everything--this works: everything in my managedObjectContext which is set up in my viewDidLoad w/o an NSPredicate.

2) Once I set an NSPredicate, I'd like to update the tableView--This doesn't crash, but it doesn't update the tableView

On MyTableViewController, I have a popover which instantiates when I click a UIBarButtonItem on MyTableViewController. On the popover, I set a predicate on MyTableViewController.

Basically, I'd like to toggle what's displayed and that display toggle is driven by whether my variable is nil (everything displays) or filtered (variable sets a predicate).

I'm either the first or the dumbest person to attempt this feat of software engineering. I'll wager the latter, given how many times I've seen this as an end-user. If you know what I'm doing wrong, I'd be grateful to hear from you. Thank you for reading.

I have two entities: PointOfInterest and LocationCategory. I have a UIBarButton that triggers a popover of which MyTableViewController is a delegate. Clicking on the popover sets the selectedCategory property on MyTableViewController.:

// This gets set by PopoverTableViewController    
@property (nonatomic, strong) LocationCategory *selectedCategory;     

// This is set on `MyTableViewController`
@property (nonatomic, strong) NSPredicate *searchPredicate;

The property gets set correctly on MyTableViewController. I'm trying to use the selectedCategory object as the basis for a predicate to display "filtered" list of 'pointOfInterest' objects. I left out the boilerplate code from this TVC, but I've got the tableView delegate methods on the TVC.

I think I need to set my fetchedResultsController to nil and reinstantiate it w/ a predicate in my refreshTableViewController method. It doesn't crash, but it doesn't work, either.

Here's the viewDidLoad of MyTableViewController:

- (void)viewDidLoad {
    [super viewDidLoad];

    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    self.managedObjectContext = appDelegate.managedObjectContext;

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    NSLog(@"savedPOI managedObjectContext is %@", self.managedObjectContext);

    // Initialize fetch request
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]initWithEntityName:@"PointOfInterest"];

    // Add sort descriptors
    [fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]];

    // Initialize Fetched Results Controller
    self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];

    // Configure a fetchedResultsController
    [self.fetchedResultsController setDelegate:self];

    // Perform fetch
    NSError *error = nil;
    [self.fetchedResultsController performFetch:&error];

    if (error) {
        NSLog(@"Unable to perform fetch");
        NSLog(@"%@, %@", error, error.localizedDescription);
    }

    // This sets up an observer that listens for when `selectedCategory` is set
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(refreshTableViewController:) name:@"CategorySelected" object:nil];    
}

Once my selectedCategory is set, I have the following method set to run. It doesn't crash, but it doesn't refresh MyTableViewController. I suspect I've got a minor error here, but I'm not sure what I'm doing wrong.

- (void)refreshTableViewController:(NSNotification *)notification {
    if ([[notification name]isEqualToString:@"CategorySelected"]) {
        NSLog(@"NSNotification on SavedPOITableViewController's self.selectedCategory is %@", self.selectedCategory.categoryName);

        // Nuke the cache that was loaded in viewDidLoad
        [NSFetchedResultsController deleteCacheWithName:@"PointOfInterest"];

        // Nuke the fetchedResultsController alloc/inited in viewDidLoad
        self.fetchedResultsController = nil;

        // Alloc init a new fetchRequest
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

        // Set the entity
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"PointOfInterest" inManagedObjectContext:self.managedObjectContext];
        [fetchRequest setEntity:entity];

        // Add sort descriptors
        [fetchRequest setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]];

        // Reinstantiate the fetchedResultsController
            self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];

        NSString *predicateString = self.selectedCategory.categoryName;
        NSLog(@"predicateString is %@", predicateString);

        self.searchPredicate = [NSPredicate predicateWithFormat:@"locationCategory.categoryName == %@", predicateString];
        NSLog(@"self.searchPredicate in refreshTableViewController is %@", predicateString);

        // Do the fetchRequest with the predicate
        [fetchRequest setPredicate:self.searchPredicate];

        // Perform fetch
        NSError *error = nil;
        [self.fetchedResultsController performFetch:&error];

        if (error) {
            NSLog(@"Unable to perform fetch");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
        [self.tableView reloadData];        


    }
}

Just for completeness' sake, here's my PointOfInterest & LocationCategory classs:

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class LocationCategory;

@interface PointOfInterest : NSManagedObject

@property (nonatomic, retain) NSString * note;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSString * address;
@property (nonatomic, retain) NSNumber * latitude;
@property (nonatomic, retain) NSNumber * longitude;
@property (nonatomic, retain) NSString * phoneNumber;
@property (nonatomic, retain) NSString * url;
@property (nonatomic, retain) LocationCategory *locationCategory;

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class PointOfInterest;

@interface LocationCategory : NSManagedObject

@property (nonatomic, retain) id categoryColor;
@property (nonatomic, retain) NSString * categoryName;
@property (nonatomic, retain) NSSet *pointOfInterest;
@end

回答1:


I figured it out:

I added this to my implementation file on MyTableViewController:

@synthesize fetchedResultsController = _fetchedResultsController;

As I expected, I was missing something startlingly stupid--and I was **RIGHT!!

I read this post on Ray Wenderlich's website and I noticed it had that line in the implementation, but I didn't. I've never encountered the need to use @synthesize and I've seen mentions elsewhere that "you almost never need it", etc. Well, turns out, you do!

http://www.raywenderlich.com/14742/core-data-on-ios-5-tutorial-how-to-work-with-relations-and-predicates

This post on StackOverflow covers the basics of @synthesize.

What exactly does @synthesize do?



来源:https://stackoverflow.com/questions/29856403/uitableview-doesnt-refresh-when-nspredicate-set

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!