Core Data locks in background threads

后端 未结 2 1273
我在风中等你
我在风中等你 2021-01-30 22:19

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

相关标签:
2条回答
  • 2021-01-30 23:02

    Not totally sure if this applies to you but I was getting similar errors. I solved them by

    1. Using NSPrivateQueueConcurrencyType not NSConfinementConcurrencyType to take processing off the main thread.

    2. 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];
    }];
    
    0 讨论(0)
  • 2021-01-30 23:10

    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
    
    0 讨论(0)
提交回复
热议问题