Core Data locks in background threads

后端 未结 2 1274
我在风中等你
我在风中等你 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条回答
  •  梦毁少年i
    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 
    
    @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
    

提交回复
热议问题