问题
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