这是调试CoreData并发问题的有效方法吗?

Nic*_*ing 3 core-data objective-c ios

像许多iOS开发人员一样,我使用CoreData,就像许多使用CoreData的iOS开发人员一样,我有很难跟踪线程违规错误.我正在尝试实现一个调试策略,以便在CoreData并发规则被破坏时抛出异常.我的尝试在下面 - 我的问题是,这有效吗?它会产生误报吗?

简介:创建NSManagedObject时,请记下该线程.每当稍后访问某个值时,检查当前线程是否与创建线程相同,如果没有,则抛出异常.

#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
Run Code Online (Sandbox Code Playgroud)

Tom*_*ton 10

不,那不是个好主意.您将部分复制Apple构建到框架中的内容会遇到相当大的麻烦.

如果编辑目标的方案,则可以添加-com.apple.CoreData.ConcurrencyDebug 1到启动时传递的参数:

并发调试标志

完成后,所有并发冲突都会导致立即崩溃.您会知道这是一个并发冲突,因为堆栈跟踪中的"留给我们的一切都是荣誉"消息:

留给我们的只是荣誉

您将看到导致并发冲突的确切代码行.

您可能需要添加一些其他核心数据的调试参数,com.apple.CoreData.SQLDebugcom.apple.CoreData.Logging.stderr为好.它们不会改变并发调试,但它们会使Xcode打印一条消息读取,CoreData: annotation: Core Data multi-threading assertions enabled这样你就可以知道它了.

额外的调试标志

  • 我注意到如果你使用NSAsynchronousFetchRequest,这个标志仍然会崩溃应用程序,即使它正确使用. (2认同)