【问题标题】:Inserting a relationship object into a core data object automatically inserts it multiple times将关系对象插入核心数据对象会自动插入多次
【发布时间】:2014-10-10 14:29:21
【问题描述】:

我有 2 个实体:项目和任务。一个项目可以有很多任务。一对多的关系。

我有一个表格视图控制器,它列出了选定项目的所有任务。还有另一个视图控制器,用于向给定项目添加新任务。问题是添加新任务时,插入不止一次,有时两次有时三次。

我意识到: 第一次添加任务,添加1个任务,第二次添加任务,添加2个任务,第3个任务,添加3个任务等等。

我不知道问题到底出在哪里。

请有人帮忙。

AddTaskViewController 有一个来自 TasksTableViewController 的模态序列

TasksTableViewController.h

#import <UIKit/UIKit.h>
#import "Project.h"
#import "Task.h"

@interface MATasksTableViewController : UITableViewController


@property (strong, nonatomic) NSIndexPath *passedPath;
@property (strong, nonatomic) Project *project;
@property (strong, nonatomic) NSString *taskTitleString;
@property (strong, nonatomic) NSArray *tasksArray;

@end

TasksTableViewController.m

#import "MATasksTableViewController.h"
#import "Project.h"
#import "Task.h"
#import "MACoreDataStack.h"
#import "MAAddTaskViewController.h"

@interface MATasksTableViewController () <NSFetchedResultsControllerDelegate>

@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;

@end

@implementation MATasksTableViewController

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.fetchedResultsController performFetch:nil];
    _project = [self.fetchedResultsController objectAtIndexPath:_passedPath];
    _tasksArray = [_project.task allObjects];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#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.
    //return [_tasksArray count];
    return [_tasksArray count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    // Configure the cell...

    Task *t = [_tasksArray objectAtIndex:indexPath.row];
    cell.textLabel.text = t.title;

    return cell;
}


-(NSFetchRequest *)projectListFetchRequest {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Project"];

    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"dueDate" ascending:YES]];

    return fetchRequest;
}

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

    MACoreDataStack *coreDataStack = [MACoreDataStack defaultStack];
    NSFetchRequest *fetchRequest = [self projectListFetchRequest];
    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:coreDataStack.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        MACoreDataStack *coreDataStack = [MACoreDataStack defaultStack];
        Task *t = [_tasksArray objectAtIndex:indexPath.row];
        [_project removeTaskObject:t];
        [coreDataStack saveContext];
        [self performFetchAgain];
    } else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }   
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
    if ([[segue identifier] isEqualToString:@"AddTaskSegue"]) {
        UINavigationController *navController = (UINavigationController*)[segue destinationViewController];
        MAAddTaskViewController *destinationVC = [navController topViewController];
        destinationVC.project = self.project;
        destinationVC.firstViewController = self;
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(didPressDoneAndDismissController)
                                                     name:@"doneWasPressedInSecondView"
                                                   object:nil];

    }
}

-(void)didPressDoneAndDismissController {
    MACoreDataStack *coreDataStack = [MACoreDataStack defaultStack];
    Task *task = [NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:coreDataStack.managedObjectContext];
    task.title = self.taskTitleString;
    [self.project addTaskObject:task];
    [coreDataStack saveContext];
    [self performFetchAgain];
}

-(void)performFetchAgain {
    [self.fetchedResultsController performFetch:nil];
    _project = [self.fetchedResultsController objectAtIndexPath:_passedPath];
    _tasksArray = [_project.task allObjects];
    [self.tableView reloadData];
}

@end

AddTaskViewController.h

#import <UIKit/UIKit.h>
#import "Project.h"
#import "MATasksTableViewController.h"


@interface MAAddTaskViewController : UIViewController {
    Project *project;
    MATasksTableViewController *firstViewController;
}


@property(nonatomic,assign)id delegate;

@property (strong, nonatomic)  MATasksTableViewController *firstViewController;

@property (strong, nonatomic) IBOutlet UITextField *textField;
@property (strong, nonatomic) Project *project;
@property (nonatomic, strong) NSMutableSet *tasks;

@end

AddTaskViewController.m

#import "MAAddTaskViewController.h"
#import "Project.h"
#import "Task.h"
#import "MACoreDataStack.h"

@interface MAAddTaskViewController ()

@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;

@end

@implementation MAAddTaskViewController
@synthesize project;
@synthesize tasks;
@synthesize firstViewController;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)createNewTask {

    NSString* taskTitle = self.textField.text;
    self.firstViewController.taskTitleString = taskTitle;
}

-(void)dismissSelf {
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];

}

- (IBAction)doneWasPressed:(id)sender {
    [self createNewTask];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"doneWasPressedInSecondView"
                                                        object:nil
                                                      userInfo:nil];
    [self dismissSelf];
}
- (IBAction)cancelWasPressed:(id)sender {
    [self dismissSelf];
}

@end

【问题讨论】:

  • 欢迎来到 SOF。你不应该转储整个类的代码。这里的习惯是您只需发布您认为相关的代码并对其进行评论。

标签: ios objective-c core-data xcode5


【解决方案1】:

我意识到:第一次添加任务,添加1个任务,第二次添加任务,添加2个任务,第3个任务,添加3个任务等等。

当你prepareForSegue 你这样做:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(didPressDoneAndDismissController)
                                                 name:@"doneWasPressedInSecondView"
                                               object:nil];

你每次为 segue 做准备时都会这样做,但你永远不会删除 self 作为观察者。如果您多次注册但从未删除注册,您可能会收到多次通知。

每次收到通知时,都会创建一个新的托管对象。这是上述的副作用。您至少需要执行以下一项操作,但实际上您应该同时执行以下操作:

  • 注册该通知一次,而不是每次prepareForSegue
  • 当您不再关心接收此通知时,将 self 删除为该通知的观察者。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多