与许多iOS开发人员一样,我使用CoreData,并且像许多使用CoreData的iOS开发人员一样,我有难以追踪的线程违规错误。我试图在CoreData并发规则被破坏时实现一个抛出异常的调试策略。我的尝试在下面 - 我的问题是,这是否有效?它会产生误报吗?这是调试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
我会假设'performBlockAndWait:''使用dispatch_sync',其中,根据经验,_often_有你提到的,但可能不依赖于你的操作系统版本,设备,等等,等等。但是,不管行为。你是完全正确的:作者有不恰当的线程和队列。 – Tommy
绝对正确 –