I\'m getting locks in Core Data. I really don\'t understand the reason. Because I\'m creating a background MOC when I\'m processing in a background thread. Below you can see wha
Not totally sure if this applies to you but I was getting similar errors. I solved them by
Using NSPrivateQueueConcurrencyType
not NSConfinementConcurrencyType
to take processing off the main thread.
Putting executeFetchRequest
inside MOC's performBlockAndWait
.
So in CoreDataHelper.m's fetchEntity method you would have something like this:
[context performBlockAndWait:^{
NSError *error = nil;
NSArray *entities = [context executeFetchRequest:request error:&error];
}];
this may not give the full picture but this is the approach I took
Every managed object requires its own thread. On the same thread you can use the same managed object over and over. But not on the same queue. (this was a misconception I leaned about) the background queue can have many different threads and the MOC needs to be unique for each thread.
here is the method I used.
ManagedObjectContextHolder.h
#import <Foundation/Foundation.h>
@interface ManagedObjectContextHolder : NSObject
+ (ManagedObjectContextHolder*) threadContextHolder;
@property (nonatomic, strong) NSManagedObjectContext *context;
@property (nonatomic, strong) NSString *contextThreadMocGuid;
@property (nonatomic, weak) NSThread *contextThread;
@end
ManagedObjectContextHolder.m
#import "ManagedObjectContextHolder.h"
@interface HSContextSaveHandler : NSObject
@property (nonatomic, strong) NSArray *mocArray;
- (void) saveHappened:(NSNotification*) saveNotification;
@end
@implementation HSContextSaveHandler
@synthesize mocArray = _mocArray;
int saveFinished = 0;
- (MyAppDelegate*) appDelegete{
return (MyAppDelegate*) [UIApplication sharedApplication].delegate;
}
- (void) saveHappened:(NSNotification *)saveNotification{
if (saveNotification && saveNotification.userInfo){
NSArray *staticArray = [NSArray arrayWithArray:self.mocArray];
for (id item in staticArray) {
if ([item isKindOfClass:[ManagedObjectContextHolder class]]) {
ManagedObjectContextHolder *holder = item;
if ([saveNotification object] != holder.context){
@try {
[holder.context mergeChangesFromContextDidSaveNotification:saveNotification];
}
@catch (NSException *exception) {
HSLogBrute(@"<<<<<<<< MERGE CHANGES FROM CONTEXT DID SAVE NOTIFICATION >>>>>>>>\n%@",saveNotification);
}
}
}
}
saveFinished = 3;
}
}
@end
@interface NSThread (mocGuid)
- (NSString*) mocGuid;
- (void) setMocGuid:(NSString*) mocGuid;
@end
@implementation NSThread (mocGuid)
- (NSString *)mocGuid{
return [self.threadDictionary valueForKey:@"mocGuid"];
}
- (void)setMocGuid:(NSString *)mocGuid{
[self.threadDictionary setValue:mocGuid forKey:@"mocGuid"];
}
@end
@implementation ManagedObjectContextHolder
static NSMutableArray *_mocHolders;
static HSContextSaveHandler *_mocSaveHandler;
+ (NSMutableArray*) mocHolders{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_mocHolders = [NSMutableArray arrayWithCapacity:5];
_mocSaveHandler = [[HSContextSaveHandler alloc] init];
_mocSaveHandler.mocArray = _mocHolders;
[[NSNotificationCenter defaultCenter] addObserver:_mocSaveHandler selector:@selector(saveHappened:) name:NSManagedObjectContextDidSaveNotification object:nil];
});
return _mocHolders;
}
+ (ManagedObjectContextHolder *)threadContextHolder{
NSThread *currentThread = [NSThread currentThread];
NSString *mocGuid = currentThread.mocGuid;
ManagedObjectContextHolder *result = nil;
NSMutableArray *removeList = [[NSMutableArray alloc] initWithCapacity:[self mocHolders].count];
NSLog(@"Context Holders Count %d",[self mocHolders].count);
for (ManagedObjectContextHolder *item in [self mocHolders]) {
if (mocGuid != nil && item.contextThread == currentThread && item.contextThreadMocGuid == currentThread.mocGuid){
result = item;
}
if (item.contextThread == nil) {
[removeList addObject:item];
}
}
if (removeList.count > 0){
NSLog(@"Removing %d Context Holders for Nil Threads",removeList.count);
[[self mocHolders] removeObjectsInArray:removeList];
}
if (result == nil){
result = [[ManagedObjectContextHolder alloc] init];
result.contextThread = currentThread;
if (mocGuid == nil){
mocGuid = [HSStaticContainer uuidAsShortString];
currentThread.mocGuid = mocGuid;
}
result.contextThreadMocGuid = mocGuid;
result.context = [[NSManagedObjectContext alloc] init];
[result.contextcontext setPersistentStoreCoordinator:[self appDelegate].persistentStoreCoordinator];
[result.context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[[self mocHolders] addObject:result];
}
return result;
}
@synthesize context = _context;
@synthesize contextThreadMocGuid = _contextThreadMocGuid;
@synthesize contextThread = _contextThread;
- (id)init{
self = [super init];
if (self) {
NSLog(@"Creating a Managed Object Context Holder. Here is the Stack Trace.\r\r%@",[NSThread callStackSymbols]);
}
return self;
}
@end