2014-09-12 155 views
16

我一直有这个问题现在几天,这真的令人沮丧..我一直在审查我的代码反复尝试不同的事情,并继续有同样的问题..只有50%的时间不会总是这样。这使得它更难..核心数据:错误:异常被发现在核心数据更改处理

的问题,

我解析从3个CSV文件中的数据,以我的核心数据,它总是解析文件的2顺利,但中间的/第二个文件是哪里崩溃总是发生,所以这将是该文件的文件和managedObjectContext类的地址。

错误消息

CoreData: error: Serious application error. 
Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. 
-[__NSCFSet addObject:]: attempt to insert nil with userInfo (null) 
2014-09-12 11:27:06.115 AppName[210:3907] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil' 

所以,在我FetchData类我尝试用不同的方式来解决这个问题。

  • 首先,我更改了我的.csv文件,并将N/A插入到空的所有字段/单元格中。
  • 其次,我正在检查我的FetchData类,如果它没有任何值,则保存N/A。
  • 第三,在我开始解析数据的视图控制器中,我现在已经在我的核心数据中为这3个实体分隔了三个不同的属性。

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContextGI;

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContextVA;

这可能是一个有点疯狂或什么,但我真的需要解决这个问题的话,尝试任何可能的解决方案或接近这一点,总是好的,我想。

视图控制器来调用函数来完成解析..

//at the beginning of my model 
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

-(IBAction)myLoadingTask:(id)sender{ 

     dispatch_async(kBgQueue, ^{ 

      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 

      NSString *savedValue = @""; 

      if([[userDefaults stringForKey:@"dataFetched"] length] > 0){        
       savedValue = [userDefaults stringForKey:@"dataFetched"]; 
      } 

      // if the csv files data hasn't been fetch it, then fetch it 
      if([savedValue length] == 0){ 

       FetchData *fd = [[FetchData alloc] initWithManagedContext:self.managedObjectContext]; 

       // fetching benefits data 
       [fd beginParser]; 

       FetchGIBillData *fdGI = [[FetchGIBillData alloc] initWithManagedContext:self.managedObjectContextGI]; 

       // fetching gi bill data 
       [fdGI beginParser]; 

       FetchVAPhones *fdVA = [[FetchVAPhones alloc] initWithManagedContext:self.managedObjectContextVA]; 

       // fetching va phones 
       [fdVA beginParser]; 

       NSString *valueToSave = @"saved"; 
       [[NSUserDefaults standardUserDefaults] setObject:valueToSave forKey:@"dataFetched"]; 
       [[NSUserDefaults standardUserDefaults] synchronize]; 

      } 

     }); 
} 

这是我核心数据模型等功能..我已经进行了检查,如果它是空保存N /一个等等..我所有的性能,这是在我的实体是

#define GIBILL_FILENAME @"gi_bill_data" 

int numOfEntries; 
- (id)initWithManagedContext:(NSManagedObjectContext*)managedObjectContext 
{ 
    self.managedObjectContext = managedObjectContext; 
    arrayOfRecords = [[NSMutableArray alloc] init]; 
    numOfEntries=0; 
    return self; 
} 


- (void) beginParser 
{ 
    if (self.managedObjectContext == nil){ 
     // Error: Must pass in NSManagedObjectContext 
     return; 
    } 

    NSString *filePath = [[NSBundle mainBundle] pathForResource:GIBILL_FILENAME ofType:@"csv"]; 
    NSInputStream *stream = [NSInputStream inputStreamWithFileAtPath:filePath]; 
    NSStringEncoding encoding = NSUTF8StringEncoding;//NSWindowsCP1250StringEncoding; 

    CHCSVParser *parser = [[CHCSVParser alloc] initWithInputStream:stream usedEncoding:&encoding delimiter:',']; 
    parser.delegate = self; 

    [parser parse]; 

    // uncomment to update data x amount of dates 
    //[self checkDateForRefreshCSV:parser]; 

} 

* *这是节省的地方! *

#pragma mark - Data Add 
/** 
* addRows 
* @param parser: the CHCSV parser that will parse if required refresh 
* @brief: add the row to ths managedObjectContent DB. All values saved. 
*/ 
- (void) addRows:(CHCSVParser *)parser 
{ 
    int i = -1; 
    if ([arrayOfRecords count] == 0) return; 
    GIBill *data = [NSEntityDescription 
         insertNewObjectForEntityForName:@"GIBill" 
         inManagedObjectContext:self.managedObjectContext]; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.facility_code = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.facility_code = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.institution = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.institution = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.city = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.city = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.state = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.state = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.country = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.country = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.bah = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.bah = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.poe = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.poe = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.yr = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.yr = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.gibill = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.gibill = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 0) 
     data.cross = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.cross = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.grad_rate = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.grad_rate = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.grad_rate_rank = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.grad_rate_rank = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.default_rate = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.default_rate = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.avg_stu_loan_debt = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.avg_stu_loan_debt = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.avg_stu_loan_debt_rank = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.avg_stu_loan_debt_rank = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.indicator_group = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.indicator_group = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.salary = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.salary = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.zip = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.zip = @"N/A"; 

    if([[arrayOfRecords objectAtIndex:++i] length] > 2) 
     data.ope = [arrayOfRecords objectAtIndex:i]; 
    else 
     data.ope = @"N/A"; 

    NSError *error; 

    [self.managedObjectContext save:&error]; 

} 

好吧,我贴了最相关的代码,我认为这个问题的。请如果需要的东西或更多的细节问题让我知道,我会提供它..

在此先感谢!

+0

添加例外破发点,并检查它是将空。 – 2014-09-12 16:06:46

+0

您正在使用较旧的Core Data并发模型访问跨线程的上下文,这会导致很多问题。 – quellish 2014-09-12 16:07:20

+0

您对旧版核心数据并发模型有何意义? @quellish – NorthBlast 2014-09-12 16:13:48

回答

20

嗯,整个问题是创建NSManagedObjectContextMain Thread中的所有内容,然后访问它或在Background Thread中使用它。

所以,我只是跟着this post现在一切工作完美流畅:)

非常感谢它真的把我在正确的方向上的评论,这是我需要什么完全能够发现问题..

谢谢!

在AppDelegate.h

+ (NSManagedObjectContext *)mainQueueContext; 
+ (NSManagedObjectContext *)privateQueueContext; 

然后,在我的AppDelegate.m

#pragma mark - Singleton Access 

+ (NSManagedObjectContext *)mainQueueContext 
{ 
    return [self mainQueueContext]; 
} 

+ (NSManagedObjectContext *)privateQueueContext 
{ 
    return [self privateQueueContext]; 
} 

#pragma mark - Getters 

- (NSManagedObjectContext *)mainQueueContext 
{ 
    if (!_mainQueueContext) { 
     _mainQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
     _mainQueueContext.persistentStoreCoordinator = self.persistentStoreCoordinator; 
    } 

    return _mainQueueContext; 
} 

- (NSManagedObjectContext *)privateQueueContext 
{ 
    if (!_privateQueueContext) { 
     _privateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     _privateQueueContext.persistentStoreCoordinator = self.persistentStoreCoordinator; 
    } 

    return _privateQueueContext; 
} 

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     [[NSNotificationCenter defaultCenter] addObserver:self 
               selector:@selector(contextDidSavePrivateQueueContext:) 
                name:NSManagedObjectContextDidSaveNotification 
                object:[self privateQueueContext]]; 
     [[NSNotificationCenter defaultCenter] addObserver:self 
               selector:@selector(contextDidSaveMainQueueContext:) 
                name:NSManagedObjectContextDidSaveNotification 
                object:[self mainQueueContext]]; 
    } 
    return self; 
} 

#pragma mark - Notifications 

- (void)contextDidSavePrivateQueueContext:(NSNotification *)notification 
{ 
    @synchronized(self) { 
     [self.mainQueueContext performBlock:^{ 
      [self.mainQueueContext mergeChangesFromContextDidSaveNotification:notification]; 
     }]; 
    } 
} 

- (void)contextDidSaveMainQueueContext:(NSNotification *)notification 
{ 
    @synchronized(self) { 
     [self.privateQueueContext performBlock:^{ 
      [self.privateQueueContext mergeChangesFromContextDidSaveNotification:notification]; 
     }]; 
    } 
} 

- (void)dealloc 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 

而且,最后在我的的ViewController我在哪里发送工作到背景..

// dont forget the macro 
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

dispatch_async(kBgQueue, ^{ 

    id delegate = [[UIApplication sharedApplication] delegate]; 
    self.managedObjectContext = [delegate privateQueueContext]; 

    // do something in the background with your managedObjectContext!!!! 

}); 
下面
+0

为什么你创建了公共方法? '+(的NSManagedObjectContext *)privateQueueContext'如使用的是实例方法'ID代表= [[UIApplication的sharedApplication]委托];'' self.managedObjectContext = [委派privateQueueContext];' – TheMall 2015-12-14 07:03:17

+0

如何在迅速3? – Taprolano 2017-04-03 00:13:23

+0

@Taprolano你有没有想过快速3? – 2017-07-31 09:59:50

21

线救了我的一天:

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 

你只需要设置并发类型为私营。这样它可以在专用队列上同时对数据库执行多个操作。

+1

这可以在你的appDelegate中找到所有其他核心数据函数。用于SWIFT它是这一行: VAR managedObjectContext =的NSManagedObjectContext(concurrencyType:.PrivateQueueConcurrencyType)。所有功劳归于这位职位作者。灿烂的捕获和节省一天。 – 2016-09-17 19:20:31

+0

体积大,效果很好+30 – Claudio 2017-04-10 14:30:07

1

对于谁是这样做的雨燕3人:

var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)