I have been having this problem now for a few days and it's really frustrating.. I have been reviewing my code over and over again tried different thing and keeps having the same issue.. Which happens only 50% of the times not always. This makes it harder..
我现在已经有这个问题了几天而且真的很令人沮丧。我一直在重复审查我的代码尝试了不同的事情并且一直有同样的问题。这种情况只有50%的时间并不总是如此。这让它变得更难..
The Problem,
问题,
I am parsing the data from 3 csv files to my Core Data, which 2 of the files parsing always goes well but the middle/second file is where the crash always happens so, this will be address to that file and managedObjectContext class for this file.
我正在将3个csv文件中的数据解析为我的Core Data,其中2个文件解析总是顺利但中间/第二个文件是崩溃总是发生的地方,这将是该文件的地址和此文件的managedObjectContext类。
Error Message
错误信息
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'
So, in my FetchData class I try to address the problem in different ways.
因此,在我的FetchData类中,我尝试以不同的方式解决问题。
- First, I changed my .csv file and insert N/A to all the fields/cells that were empty.
- 首先,我更改了我的.csv文件并将N / A插入到所有空的字段/单元格中。
- Second, I'm doing a check in my FetchData class if this doesn't has any value, save N/A.
- 其次,我正在检查我的FetchData类,如果它没有任何值,保存N / A.
- Third, In my view controller where I'm firing the parsing the data, I have now separated three different properties for these 3 entities in my Core Data.
- 第三,在我的视图控制器中,我正在解析数据,我现在已经在我的核心数据中为这3个实体分离了三个不同的属性。
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property(非原子,强)NSManagedObjectContext * managedObjectContext;
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContextGI;
@property(非原子,强)NSManagedObjectContext * managedObjectContextGI;
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContextVA;
@property(非原子,强)NSManagedObjectContext * managedObjectContextVA;
It might be a bit crazy or whatever but I really need to fix this so, trying any possible solution or approach to this it's always good, I think.
它可能有点疯狂或其他但我真的需要解决这个问题,尝试任何可能的解决方案或方法,这总是好的,我想。
ViewController to calling the functions to perform the parsing..
ViewController调用函数来执行解析..
//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];
}
});
}
This is my Core Data model functions and so on.. Which I have performed the check if it was empty save N/A and so on.. all my properties which are in my entity are strings
这是我的核心数据模型函数等等。我已经执行了检查它是否为空保存N / A等等..我实体中的所有属性都是字符串
#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];
}
** This is where the saving happens!! *
**这是节约发生的地方! *
#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];
}
Well, I posted the most relevant code that I think of the issue. Please if something else is needed or more details about the problem let me know and I will provide it..
好吧,我发布了最相关的代码,我想到了这个问题。如果需要其他东西或有关问题的更多细节,请告诉我,我会提供..
Thanks in advance!
提前致谢!
3 个解决方案
#1
25
The line below saved my day:
下面的一行节省了我的一天:
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
You just have to set the concurrency type as Private. This way it can perform multiple operations on database concurrently on private queue's.
您只需将并发类型设置为Private。这样它就可以在私有队列上同时对数据库执行多个操作。
#2
21
Well, the whole problem was creating the NSManagedObjectContext
and everything in the Main Thread
and then accessing it or using it in the Background Thread
.
好吧,整个问题是创建NSManagedObjectContext和主线程中的所有内容,然后访问它或在后台线程中使用它。
So, I have just followed this post and now everything is working perfectly and smooth :)
所以,我刚刚关注这篇文章,现在一切都工作得非常顺利:)
Thanks a lot for the comments it really put me in the right direction and it was totally what I needed to be able to find the problem..
非常感谢您的评论,它确实让我朝着正确的方向前进,这完全是我需要能够找到问题的方法。
Thanks!
谢谢!
In the AppDelegate.h
在AppDelegate.h中
+ (NSManagedObjectContext *)mainQueueContext;
+ (NSManagedObjectContext *)privateQueueContext;
Then, in my AppDelegate.m
然后,在我的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];
}
And, finally in my ViewController where I am sending the work to the background..
最后,在我的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!!!!
});
#3
1
For people who are doing it in Swift 3:
对于在Swift 3中执行此操作的人:
var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
var managedObjectContext = NSManagedObjectContext(concurrencyType:.privateQueueConcurrencyType)
#1
25
The line below saved my day:
下面的一行节省了我的一天:
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
You just have to set the concurrency type as Private. This way it can perform multiple operations on database concurrently on private queue's.
您只需将并发类型设置为Private。这样它就可以在私有队列上同时对数据库执行多个操作。
#2
21
Well, the whole problem was creating the NSManagedObjectContext
and everything in the Main Thread
and then accessing it or using it in the Background Thread
.
好吧,整个问题是创建NSManagedObjectContext和主线程中的所有内容,然后访问它或在后台线程中使用它。
So, I have just followed this post and now everything is working perfectly and smooth :)
所以,我刚刚关注这篇文章,现在一切都工作得非常顺利:)
Thanks a lot for the comments it really put me in the right direction and it was totally what I needed to be able to find the problem..
非常感谢您的评论,它确实让我朝着正确的方向前进,这完全是我需要能够找到问题的方法。
Thanks!
谢谢!
In the AppDelegate.h
在AppDelegate.h中
+ (NSManagedObjectContext *)mainQueueContext;
+ (NSManagedObjectContext *)privateQueueContext;
Then, in my AppDelegate.m
然后,在我的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];
}
And, finally in my ViewController where I am sending the work to the background..
最后,在我的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!!!!
});
#3
1
For people who are doing it in Swift 3:
对于在Swift 3中执行此操作的人:
var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
var managedObjectContext = NSManagedObjectContext(concurrencyType:.privateQueueConcurrencyType)