與許多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
絕對正確 –