Is this a valid way of debugging CoreData concurrency issues?

随声附和 提交于 2021-02-19 03:43:10

问题


Like many iOS developers, I use CoreData, and like many iOS developers that use CoreData, I have hard-to-track-down thread violation errors. I'm trying to implement a debugging strategy for throwing exceptions when the CoreData concurrency rules are broken. My attempt is below - my question is, is this valid? Will it produce false positives?

Summary: when an NSManagedObject is created, note the thread. Whenever a value is accessed later on, check if the current thread is the same as the creation thread, and throw an exception if not.

#import "NSManagedObject+DebugTracking.h"
#import "NSObject+DTRuntime.h"
#import <objc/runtime.h>
#import "NSManagedObjectContext+DebugThreadTracking.h"

@implementation NSManagedObject (DebugTracking)

+(void)load {

    [NSManagedObject swizzleMethod:@selector(willAccessValueForKey:) withMethod:@selector(swizzled_willAccessValueForKey:)];
    [NSManagedObject swizzleMethod:@selector(initWithEntity:insertIntoManagedObjectContext:) withMethod:@selector(swizzled_initWithEntity:insertIntoManagedObjectContext:)];

}

- (__kindof NSManagedObject *)swizzled_initWithEntity:(NSEntityDescription *)entity
              insertIntoManagedObjectContext:(NSManagedObjectContext *)context
{
    NSManagedObject *object = [self swizzled_initWithEntity:entity insertIntoManagedObjectContext:context];
    NSLog(@"Initialising an object of type: %@", NSStringFromClass([self class]));

    object.debugThread = [NSThread currentThread];
    return object;
}

-(void)swizzled_willAccessValueForKey:(NSString *)key {

    NSThread *thread = self.debugThread;

    if (!thread) {
        NSLog(@"No Thread set");
    } else if (thread != [NSThread currentThread]) {
        [NSException raise:@"CoreData thread violation exception" format:@"Property accessed from a different thread than the object's creation thread. Type: %@", NSStringFromClass([self class])];
    } else {
        NSLog(@"All is well");
    }

    [self swizzled_willAccessValueForKey: key];
}

-(NSThread *)debugThread {
    return objc_getAssociatedObject(self, @selector(debugThread));
}

-(void)setDebugThread:(NSThread *)debugThread {
    objc_setAssociatedObject(self, @selector(debugThread), debugThread, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

回答1:


No, that's not a good idea. You're going to a fair amount of trouble to partially replicate something that Apple builds in to the framework.

If you edit the scheme for the target, you can add -com.apple.CoreData.ConcurrencyDebug 1 to the arguments passed on launch:

Once you've done that, all concurrency violations will cause an immediate crash. You'll know it's a concurrency violation because of the "all that is left to us is honor" message in the stack trace:

You'll see the exact line of code that caused the concurrency violation.

You may want to add a couple of other Core Data debug arguments, com.apple.CoreData.SQLDebug and com.apple.CoreData.Logging.stderr as well. They won't change the concurrency debugging but they will make Xcode print a message reading CoreData: annotation: Core Data multi-threading assertions enabled so that you'll know it's on.




回答2:


No, it is not valid. Your code supposes that a context always execute blocks on the same thread. But in fact it always run on the same QUEUE, queue and thread are not the same thing.

For example, try to use performBlockAndWait: to check if it uses the same thread performBlock: runs on. FWIK performBlockAndWait: uses the thread where it is invoked.




回答3:


You can add a debug flag that displays a lot of information about the operations performed by Core Data, including, but not limited to, the underlying SQL operations. See this answer. Mind that you can change the debug level from 1 to 2 or 3 to get even more debug info.

I'm not sure whether it will help in your specific case, without knowing the exact problem and context, however, it should help. Also, you can check the stack trace, which improved a lot for multi-threading debugging in Xcode 7 and 8.



来源:https://stackoverflow.com/questions/41176098/is-this-a-valid-way-of-debugging-coredata-concurrency-issues

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!