Forked from jverkoey/NSManagedObjectContext+DebugSwizzling.m
Last active
August 29, 2015 14:00
-
-
Save tonyarnold/11081601 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if DEBUG | |
/** | |
Toggles assertion of Core Data managed object contexts. Only available when DEBUG is defined. | |
When enabled, your application will throw an exception when accessing or modifying entities in a context other than their own. | |
*/ | |
void TCBToggleAssertingContextQueues(); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "NSManagedObjectContext+DebugSwizzling.h" | |
#if DEBUG | |
#import <CoreData/CoreData.h> | |
#import <objc/runtime.h> | |
#import "TCBRuntimeHelpers.h" | |
static NSUInteger TCBManagedObjectContextDisableChecksCount = 0; | |
@implementation NSManagedObjectContext (DebugSwizzling) | |
- (BOOL)tcb_shouldPerformContextQueueCheck | |
{ | |
return (TCBManagedObjectContextDisableChecksCount == 0); | |
} | |
- (void)tcb_stopContextQueueCheck | |
{ | |
TCBManagedObjectContextDisableChecksCount++; | |
} | |
- (void)tcb_startContextQueueCheck | |
{ | |
TCBManagedObjectContextDisableChecksCount--; | |
} | |
- (id)tcb_dispatchQueue | |
{ | |
id dispatchQueue = object_getIvar(self, class_getInstanceVariable([NSManagedObjectContext class], "_dispatchQueue")); | |
NSParameterAssert(dispatchQueue); | |
return dispatchQueue; | |
} | |
- (void)tcb_validateCurrentQueue | |
{ | |
if (NO == [self tcb_shouldPerformContextQueueCheck]) { | |
return; | |
} | |
#pragma clang diagnostic push | |
#pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
NSAssert(dispatch_get_current_queue() == self.tcb_dispatchQueue, @"Accessing managed object from a different queue than its context uses: %@", self); | |
#pragma clang diagnostic pop | |
} | |
- (void)tcb_mergeChangesFromContextDidSaveNotification:(NSNotification *)notification | |
{ | |
// Temporarily disable thread checks when merging changes from a did save notification — they are not always performed on the expected queue (although it's your responsibility to ensure that they are started on the correct queue for the context you are merging into! | |
[self tcb_stopContextQueueCheck]; | |
[self tcb_mergeChangesFromContextDidSaveNotification:notification]; | |
[self tcb_startContextQueueCheck]; | |
} | |
@end | |
@implementation NSManagedObject (DebugSwizzling) | |
- (id)tcb_initWithEntity:(NSEntityDescription*)entity insertIntoManagedObjectContext:(NSManagedObjectContext*)context | |
{ | |
[context tcb_validateCurrentQueue]; | |
return [self tcb_initWithEntity:entity insertIntoManagedObjectContext:context]; | |
} | |
- (void)tcb_willAccessValueForKey:(NSString*)key | |
{ | |
[[self managedObjectContext] tcb_validateCurrentQueue]; | |
[self tcb_willAccessValueForKey:key]; | |
} | |
- (void)tcb_willChangeValueForKey:(NSString*)key | |
{ | |
[[self managedObjectContext] tcb_validateCurrentQueue]; | |
[self tcb_willChangeValueForKey:key]; | |
} | |
- (void)tcb_willChangeValueForKey:(NSString*)inKey withSetMutation:(NSKeyValueSetMutationKind)inMutationKind usingObjects:(NSSet*)inObjects | |
{ | |
[[self managedObjectContext] tcb_validateCurrentQueue]; | |
[self tcb_willChangeValueForKey:inKey withSetMutation:inMutationKind usingObjects:inObjects]; | |
} | |
@end | |
@implementation NSEntityDescription (DebugSwizzling) | |
+ (id)tcb_insertNewObjectForEntityForName:(NSString*)entityName inManagedObjectContext:(NSManagedObjectContext*)context | |
{ | |
[context tcb_validateCurrentQueue]; | |
return [self tcb_insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; | |
} | |
+ (NSEntityDescription*)tcb_entityForName:(NSString*)entityName inManagedObjectContext:(NSManagedObjectContext*)context | |
{ | |
[context tcb_validateCurrentQueue]; | |
return [self tcb_entityForName:entityName inManagedObjectContext:context]; | |
} | |
@end | |
void TCBToggleAssertingContextQueues() | |
{ | |
// NSManagedObjectContext | |
TCBSwapInstanceMethods([NSManagedObjectContext class], @selector(mergeChangesFromContextDidSaveNotification:), @selector(tcb_mergeChangesFromContextDidSaveNotification:)); | |
// NSEntityDescription | |
TCBSwapClassMethods([NSEntityDescription class], @selector(insertNewObjectForEntityForName:inManagedObjectContext:), @selector(tcb_insertNewObjectForEntityForName:inManagedObjectContext:)); | |
TCBSwapClassMethods([NSEntityDescription class], @selector(entityForName:inManagedObjectContext:), @selector(tcb_entityForName:inManagedObjectContext:)); | |
// NSManagedObject | |
TCBSwapInstanceMethods([NSManagedObject class], @selector(initWithEntity:insertIntoManagedObjectContext:), @selector(tcb_initWithEntity:insertIntoManagedObjectContext:)); | |
TCBSwapInstanceMethods([NSManagedObject class], @selector(willAccessValueForKey:), @selector(tcb_willAccessValueForKey:)); | |
TCBSwapInstanceMethods([NSManagedObject class], @selector(willChangeValueForKey:), @selector(tcb_willChangeValueForKey:)); | |
TCBSwapInstanceMethods([NSManagedObject class], @selector(willChangeValueForKey:withSetMutation:usingObjects:), @selector(tcb_willChangeValueForKey:withSetMutation:usingObjects:)); | |
} | |
#endif /* if DEBUG */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by Tony Arnold on 19/05/2014. | |
// Copyright (c) 2014 The CocoaBots. All rights reserved. | |
// | |
#import <Cocoa/Cocoa.h> | |
void TCBSwapInstanceMethods(Class cls, SEL originalSel, SEL newSel); | |
void TCBSwapClassMethods(Class cls, SEL originalSel, SEL newSel); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Created by Tony Arnold on 19/05/2014. | |
// Copyright (c) 2014 The CocoaBots. All rights reserved. | |
// | |
#import "TCBRuntimeHelpers.h" | |
#import <objc/runtime.h> | |
void TCBSwapInstanceMethods(Class cls, SEL originalSel, SEL newSel) | |
{ | |
Method originalMethod = class_getInstanceMethod(cls, originalSel); | |
Method newMethod = class_getInstanceMethod(cls, newSel); | |
NSCAssert(originalMethod != NULL, @"Method cannot be NULL"); | |
NSCAssert(newMethod != NULL, @"Method cannot be NULL"); | |
method_exchangeImplementations(originalMethod, newMethod); | |
} | |
void TCBSwapClassMethods(Class cls, SEL originalSel, SEL newSel) | |
{ | |
Method originalMethod = class_getClassMethod(cls, originalSel); | |
Method newMethod = class_getClassMethod(cls, newSel); | |
NSCAssert(originalMethod != NULL, @"Method cannot be NULL"); | |
NSCAssert(newMethod != NULL, @"Method cannot be NULL"); | |
method_exchangeImplementations(originalMethod, newMethod); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment