from NSFetchedResults objectAtIndex:0 returning 0
I've been banging my head on this one specific issue for about 2 hours now, reading through documentation and examples and I just can't wrap my head around it. I have core data models Person and Photo, and they're linked. I'm trying to display a UITableView with the contents and
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
keeps returning 0. Here is the relevant code. I know there is data in my core data because I can look at it with sqlite in terminal.
AppDelegate.h
@interface PaparazziAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UITabBarController *tabController;
UINavigationController *mainNavController;
UINavigationController *recentsNavController;
PersonListViewController *personListView;
PhotoListViewController *recentsList;
PhotoDetailViewController *photoDetail;
FlickrFetcher *fetcher;
NSManagedObjectContext *currentContext;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabController;
@property (nonatomic, retain) IBOutlet UINavigationController *mainNavController, *recentsNavController;
@end
AppDelegate.m
#import "PaparazziAppDelegate.h"
@implementation PaparazziAppDelegate
@synthesize window;
@synthesize tabController, mainNavController, recentsNavController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Setup the database instances for access.
fetcher = [FlickrFetcher sharedInstance];
// Check to see if the database exists, if not, load the plist and populate.
if ([fetcher databaseExists])
NSLog(@"I'm here!");
else {
NSLog(@"No database yet!");
currentContext = [fetcher managedObjectContext];
/* -- REMOVED FOR READABILITY --
A chunk of code for creating fresh data from a plist if the database doesn't yet exist.
I know this part works because I can see the data using the terminal */
[currentContext release];
}
// End of the plist loading and database creation.
personListView = [[PersonListViewController alloc] initWithStyle:UITableViewStylePlain];
personListView.title = @"Contacts";
[mainNavController pushViewController:personListView animated:NO];
[personListView release];
recentsList = [[PhotoListViewController alloc] initWithNibName:@"PhotoListViewController" bundle:[NSBundle mainBundle]];
recentsList.title = @"Recents";
[recentsNavController pushViewController:recentsList animated:NO];
[recentsList release];
// setting up view icons
UITabBarItem *contactsIcon = [[UITabBarItem alloc]
initWithTabBarSystemItem:UITabBarSystemItemContacts tag:0];
mainNavController.tabBarItem = contactsIcon;
[contactsIcon release];
UITabBarItem *recentsIcon = [[UITabBarItem alloc]
initWithTabBarSystemItem:UITabBarSystemItemRecents tag:0];
recentsNavController.tabBarItem = recentsIcon;
[recentsIcon release];
[self.window addSubview:tabController.view];
// Override point for custom开发者_如何学运维ization after application launch.
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[window release];
[tabController release];
[mainNavController release];
[recentsNavController release];
[fetcher release];
[super dealloc];
}
@end
PersonListViewController.h
#import <UIKit/UIKit.h>
#import "FlickrFetcher.h"
#import "Person.h"
#import "Photo.h"
@interface PersonListViewController : UITableViewController {
NSArray *listOfPeople;
FlickrFetcher *fetcher;
NSManagedObjectContext *currentContext;
NSFetchedResultsController *fetchedResultsController;
}
@property (nonatomic, retain) NSArray *listOfPeople;
@property (nonatomic, retain) NSManagedObjectContext *currentContext;
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@end
And the trouble file, PersonListViewController.m
#import "PersonListViewController.h"
@implementation PersonListViewController
@synthesize listOfPeople, currentContext, fetchedResultsController;
#pragma mark -
#pragma mark Initialization
- (id)initWithStyle:(UITableViewStyle)style {
// Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
self = [super initWithStyle:style];
if (self) {
// Custom initialization.
fetcher = [FlickrFetcher sharedInstance];
currentContext = [fetcher managedObjectContext];
fetchedResultsController = [fetcher fetchedResultsControllerForEntity:@"Person" withPredicate:nil];
}
return self;
}
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Contacts";
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
Person *person = [fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [person name];
// Configure the cell...
return cell;
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc {
[super dealloc];
}
@end
I have a feeling I'm missing something simple or 1 off, but I just can't seem to find it. [FlickrFetcher sharedInstance] returns a singleton, if I toss a few breakpoints into each .m file, I can see that the object id of *fetcher in each area is the same.
It looks like you haven't used performFetch: to execute the fetched results controller's request. viewWillAppear:
is usually a good place to do it:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {
NSLog(@"fetch error: %@", error);
}
}
As an aside - you might consider initialising your fetchedResultsController in viewDidLoad
rather than initWithStyle:
, then you can drop it in viewDidUnload
and hence free up some memory if the OS needs to unload the view controller.
精彩评论