即使核心数据实体具有数据,FetchedResultsController也返回null

时间:2015-11-07 13:36:45

标签: ios core-data nsfetchedresultscontroller

我将表与自定义UITableViewCell分组。我正在使用AFNetworking调用Web服务并将它们存储在Core Data Entity中。我使用NSFetchedResultsViewController显示Core Data表中的数据。我也搜索了tableview。出于某种原因,即使核心数据实体中存在数据,NSFetchedResultsController也不会返回任何数据。你能帮忙解决这个问题吗?这是我的代码。

#import "MasterViewController.h"
#import "DetailViewController.h"

@interface MasterViewController ()
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;

@end

@implementation MasterViewController
@synthesize fetchedResultsController;

- (void)viewDidLoad {
    [super viewDidLoad];
    appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
}

-(void)viewDidAppear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"RackStatusViewLoaded" object:self];
    self.navigationItem.title = [defaults objectForKey:@"loggedInUserSelectedStoreName"];
    NSString *activeStockTakeRequestPath = [NSString stringWithFormat:@"%@/stocktake/store/%@/activestocktake",[appDelegate baseUrl],[defaults objectForKey:@"loggedInUserSelectedStoreId"]];
    
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:[appDelegate baseUrl]]];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET"
                                                            path:activeStockTakeRequestPath
                                                      parameters:nil];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    [httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSInteger statusCode = operation.response.statusCode;
       // NSLog(@"AFNetowrking Response: %@", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
        NSLog(@"AF Status Code %d",statusCode);
        NSError *error;
        NSMutableDictionary *returnedDict = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
        if (statusCode==200)
        {
            NSLog(@"Status 200");
            [defaults setBool:true forKey:@"isActiveStockTakeForCurrentStore"];
            [defaults setObject:returnedDict[@"id"] forKey:@"ActiveStockTakeid"];
            [defaults setObject:returnedDict[@"name"] forKey:@"ActiveStockTakeName"];
            [defaults setObject:returnedDict[@"onDate"] forKey:@"ActiveStockTakeDate"];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"setTitleForCurrentActiveStock" object:self];
            NSLog(@"isActiveStock? %@",[defaults objectForKey:@"isActiveStockTakeForCurrentStore"]);
            NSLog(@"ActiveStockTakeid? %@",[defaults objectForKey:@"ActiveStockTakeid"]);
            NSLog(@"ActiveStockTakeName? %@",[defaults objectForKey:@"ActiveStockTakeName"]);
            NSLog(@"ActiveStockTakeDate? %@",[defaults objectForKey:@"ActiveStockTakeDate"]);
            [defaults synchronize];
            
            self.fetchedResultsController = nil;
            NSManagedObjectContext *context = [appDelegate managedObjectContext];

            NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"RackStockTakeStatus"];

            [self requestLocationDataWithStatus];
            
            NSError *error = nil;
            
            NSArray *results = [context executeFetchRequest:request error:&error];
            
            if (error != nil) {
                //Deal with failure
            }
            else {
                NSLog(@"Data from Core Data %@", results);
                NSLog(@"Count From Core Data Entity : %d",[results count]);
            }
            [self performFetchForItemsInStore];
            [self.tableView reloadData];
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
       }
    }];
    [operation start];
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    appDelegate.selectedRackForTakeStock = [self.fetchedResultsController objectAtIndexPath:indexPath];
    NSLog(@"Selected Rack %@",appDelegate.selectedRackForTakeStock);
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    [defaults setObject:cell.textLabel.text forKey:@"selectedRackInTakeStock"];
    [defaults synchronize];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    NSLog(@"Number of Rows: %d",[sectionInfo numberOfObjects]);
    return [sectionInfo numberOfObjects];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    NSLog(@"Number of Sections: %d",[[self.fetchedResultsController sections] count]);
    return [[self.fetchedResultsController sections] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"takeStockCell";
    
    UITableViewCell * cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    RackStockTakeStatus *rackStockTakeStatus = [self.fetchedResultsController objectAtIndexPath:indexPath];
    UILabel *rackName, *status, *user, *progress;
    
    rackName = (UILabel *)[cell viewWithTag:1];
    rackName.text = rackStockTakeStatus.locName;
    
    status = (UILabel *)[cell viewWithTag:2];
    status.text = rackStockTakeStatus.status;
    status.text = rackStockTakeStatus.status;
    
    progress = (UILabel *)[cell viewWithTag:3];
    if (rackStockTakeStatus.percentCompleted!=nil)
    {
        progress.text = [NSString stringWithFormat:@"Progress: %@%%",rackStockTakeStatus.percentCompleted];
    }
    
    if (rackStockTakeStatus.stockTakeByUser!=nil)
    {
        user = (UILabel *)[cell viewWithTag:4];
        user.text = rackStockTakeStatus.stockTakeByUser;
    }
}

- (void)requestLocationDataWithStatus {
    NSLog(@"Entering requestDataItemsForStore");
    
    NSString *requestPath = [NSString stringWithFormat:@"/stocktake/stocktake/%@/usr/1/locwithstatus",[defaults objectForKey:@"loggedInUserSelectedStoreId"]];

    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:[appDelegate baseUrl]]];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET"
                                                            path:requestPath
                                                      parameters:nil];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    [httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSInteger statusCode = operation.response.statusCode;
       // NSLog(@"AFNetowrking Response: %@", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
        NSLog(@"AF Status Code %d",statusCode);
        NSError *error;
        NSMutableDictionary *returnedDict = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
        if (statusCode==200)
        {
            for (NSDictionary *rackStockTakeStatus in returnedDict) {
                RackStockTakeStatus *rackStockTakeStatusObj;
                rackStockTakeStatusObj.stockTakeLocId = rackStockTakeStatus[@"stockTakeLocId"];
                rackStockTakeStatusObj.stockTakeUuid = rackStockTakeStatus[@"stockTakeUuid"];
                rackStockTakeStatusObj.locId = rackStockTakeStatus[@"locId"];
                rackStockTakeStatusObj.locName = rackStockTakeStatus[@"locName"];
                rackStockTakeStatusObj.status = rackStockTakeStatus[@"status"];
                rackStockTakeStatusObj.stockTakeByUser = rackStockTakeStatus[@"stockTakeByUser"];
                rackStockTakeStatusObj.stockTakeByUserId = rackStockTakeStatus[@"stockTakeByUserId"];
                rackStockTakeStatusObj.beginTime = rackStockTakeStatus[@"beginTime"];
                [self saveDataToCoreDataEntity:rackStockTakeStatusObj];
            }
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    }];
    [operation start];
}


- (NSFetchedResultsController *)fetchedResultsController {
    
    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }
    
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"RackStockTakeStatus" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    NSSortDescriptor *rackNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"locName" ascending:YES];
    NSArray *sortDescriptors = @[rackNameDescriptor];
    [fetchRequest setSortDescriptors:sortDescriptors];
   fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
    fetchedResultsController.delegate = self;
    return fetchedResultsController;
}

- (void)fetchItemsForStore {
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"RackStockTakeStatus" inManagedObjectContext:context];
   [request setEntity:entity];
    NSError *error;
    [context executeFetchRequest:request error:&error];
}

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    NSLog(@"Begin Updates");
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    
    UITableView *tableView = self.tableView;
    
    switch(type) {
            
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
            
        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
            
        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
            
        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    switch(type) {
            
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
            
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    NSLog(@"End Updates");
    [self.tableView endUpdates];
}

-(void)performFetchForItemsInStore
{
    NSLog(@"Entering performFetchForItemsInStore");
    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
    }
}

- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    NSLog(@"Cancelled - searchDisplayControllerDidEndSearch");
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"RackStockTakeStatus" inManagedObjectContext:context];
   [fetchRequest setEntity:entity];
    NSSortDescriptor *rackNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"locName" ascending:YES];
    NSArray *sortDescriptors = @[rackNameDescriptor];
    [fetchRequest setSortDescriptors:sortDescriptors];
    fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
    fetchedResultsController.delegate = self;
    [self performFetchForItemsInStore];
    [self.tableView reloadData];
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    NSInteger searchOption = controller.searchBar.selectedScopeButtonIndex;
    return [self searchDisplayController:controller shouldReloadTableForSearchString:searchString searchScope:searchOption];
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
    NSString * searchString = controller.searchBar.text;
    return [self searchDisplayController:controller shouldReloadTableForSearchString:searchString searchScope:searchOption];
}

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString*)searchString searchScope:(NSInteger)searchOption {
    
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"locName contains[cd] %@", searchString];
    [self.fetchedResultsController.fetchRequest setPredicate:predicate];
    [self.fetchedResultsController.fetchRequest setFetchLimit:100];
    
    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    TODO: "Error Handling / Error message";
    }
    return YES;
}

-(void)saveDataToCoreDataEntity:(RackStockTakeStatus *) rackStockTakeStatus
{
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    NSManagedObject *rackStockTakeStatusManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"RackStockTakeStatus" inManagedObjectContext:context];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.stockTakeLocId forKey:@"stockTakeLocId"];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.stockTakeUuid forKey:@"stockTakeUuid"];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.locId forKey:@"locId"];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.locName forKey:@"locName"];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.status forKey:@"status"];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.stockTakeByUser forKey:@"stockTakeByUser"];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.stockTakeByUserId forKey:@"stockTakeByUserId"];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.beginTime forKey:@"beginTime"];
    [rackStockTakeStatusManagedObject setValue:rackStockTakeStatus.percentCompleted forKey:@"percentCompleted"];

    NSError *error = nil;
    if (![context save:&error]) {
        NSLog(@"Save Failed for Data %@! %@ %@", rackStockTakeStatus, error, [error localizedDescription]);
    }
}

1 个答案:

答案 0 :(得分:0)

当您收到回复时,会在其中填写未初始化的CoreData对象。

        if (statusCode==200)
        {
            for (NSDictionary *rackStockTakeStatus in returnedDict) {
                RackStockTakeStatus *rackStockTakeStatusObj; // !!! MISSING INITIALIZATION HERE
                rackStockTakeStatusObj.stockTakeLocId = rackStockTakeStatus[@"stockTakeLocId"];

当你填充它时,它可以指向任何内存。

这种情况的常见做法是为其ID获取已存在的CoreData对象。如果此ID不存在任何对象,则应创建新对象。 在用数据填充后,控制器将获取结果。

        if (statusCode==200)
        {
            for (NSDictionary *rackStockTakeStatus in returnedDict) {
                NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"RackStockTakeStatus"];
                request.fetchLimit = 1;
                request.predicate = [NSPredicate predicateWithFormat:@"stockTakeLocId = %@", rackStockTakeStatus[@"stockTakeLocId"]];
                NSError *error = nil;
                RackStockTakeStatus *rackStockTakeStatusObj = [[context executeFetchRequest:request error:&error] firstObject];
                if (nil == rackStockTakeStatusObj)
                {
                     rackStockTakeStatusObj = [NSEntityDescription insertNewObjectForEntityForName:@"RackStockTakeStatus" inManagedObjectContext:context]
                     rackStockTakeStatusObj.stockTakeLocId = rackStockTakeStatus[@"stockTakeLocId"];
                }
                ...