Permalink
Browse files

interoperability with CoreDataStack for CDHRepo

  • Loading branch information...
1 parent 57271e9 commit 469876730c5fe4cbc5284cf824acec7290c89f35 @drewcrawford committed Feb 21, 2013
@@ -76,6 +76,9 @@
3A803D821520057B007D0B62 /* NSManagedObject+DCAAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A803D801520057B007D0B62 /* NSManagedObject+DCAAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
3A803D831520057B007D0B62 /* NSManagedObject+DCAAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A803D811520057B007D0B62 /* NSManagedObject+DCAAdditions.m */; };
3A803D8415201D0E007D0B62 /* DCACacheFirstIncrementalStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A803D50151FC7A3007D0B62 /* DCACacheFirstIncrementalStore.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 3A84839316D61E4B00927A33 /* NSManagedObject+CDHRepo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A84839116D61E4B00927A33 /* NSManagedObject+CDHRepo.h */; };
+ 3A84839416D61E4B00927A33 /* NSManagedObject+CDHRepo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A84839216D61E4B00927A33 /* NSManagedObject+CDHRepo.m */; };
+ 3A84839B16D620A900927A33 /* NSManagedObject+CDHRepo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A84839116D61E4B00927A33 /* NSManagedObject+CDHRepo.h */; settings = {ATTRIBUTES = (Public, ); }; };
3ACBFA391568C1A700CCD332 /* NSThreadWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3ACBFA371568C1A700CCD332 /* NSThreadWrapper.h */; };
3ACBFA3A1568C1A700CCD332 /* NSThreadWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBFA381568C1A700CCD332 /* NSThreadWrapper.m */; };
BE38A4EE1521340A005AE1E8 /* CoreDataStack+Singleton.h in Headers */ = {isa = PBXBuildFile; fileRef = BE38A4EC1521340A005AE1E8 /* CoreDataStack+Singleton.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -150,6 +153,8 @@
3A803D7D152004F1007D0B62 /* DCAFetchRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DCAFetchRequest.m; sourceTree = "<group>"; };
3A803D801520057B007D0B62 /* NSManagedObject+DCAAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSManagedObject+DCAAdditions.h"; sourceTree = "<group>"; };
3A803D811520057B007D0B62 /* NSManagedObject+DCAAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObject+DCAAdditions.m"; sourceTree = "<group>"; };
+ 3A84839116D61E4B00927A33 /* NSManagedObject+CDHRepo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSManagedObject+CDHRepo.h"; sourceTree = "<group>"; };
+ 3A84839216D61E4B00927A33 /* NSManagedObject+CDHRepo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObject+CDHRepo.m"; sourceTree = "<group>"; };
3ACBFA371568C1A700CCD332 /* NSThreadWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSThreadWrapper.h; sourceTree = "<group>"; };
3ACBFA381568C1A700CCD332 /* NSThreadWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSThreadWrapper.m; sourceTree = "<group>"; };
BE38A4EC1521340A005AE1E8 /* CoreDataStack+Singleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CoreDataStack+Singleton.h"; sourceTree = "<group>"; };
@@ -300,6 +305,8 @@
3A49EF8E16CC8E2500B4B147 /* RegistryObserverProtocol.h */,
3A49EF9F16CCD89000B4B147 /* FutureRegistry.h */,
3A49EFA016CCD89000B4B147 /* FutureRegistry.m */,
+ 3A84839116D61E4B00927A33 /* NSManagedObject+CDHRepo.h */,
+ 3A84839216D61E4B00927A33 /* NSManagedObject+CDHRepo.m */,
);
name = AdrenalineLite;
sourceTree = "<group>";
@@ -333,6 +340,7 @@
3A49EF9516CC8F8800B4B147 /* NSFetchRequest+CDH.h in Headers */,
3A49EF9A16CCCE8100B4B147 /* NSManagedObject+ExternalStorage.h in Headers */,
3A49EFA216CCD89000B4B147 /* FutureRegistry.h in Headers */,
+ 3A84839B16D620A900927A33 /* NSManagedObject+CDHRepo.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -362,6 +370,7 @@
3A49EF9316CC8F6B00B4B147 /* NSFetchRequest+CDH.h in Headers */,
3A49EF9916CCCE8100B4B147 /* NSManagedObject+ExternalStorage.h in Headers */,
3A49EFA116CCD89000B4B147 /* FutureRegistry.h in Headers */,
+ 3A84839316D61E4B00927A33 /* NSManagedObject+CDHRepo.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -520,6 +529,7 @@
3A49EF9416CC8F6B00B4B147 /* NSFetchRequest+CDH.m in Sources */,
3A49EF9B16CCCE8100B4B147 /* NSManagedObject+ExternalStorage.m in Sources */,
3A49EFA316CCD89000B4B147 /* FutureRegistry.m in Sources */,
+ 3A84839416D61E4B00927A33 /* NSManagedObject+CDHRepo.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
@@ -8,6 +8,7 @@
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
+@class CoreDataStack;
typedef void(^operationBlock)();
@interface CDHRepo : NSObject
@@ -18,6 +19,37 @@ typedef void(^operationBlock)();
/**Initializes the repository with documents storage. Provide a file name (no path) in which the repository should be saved. This type of store should not be used to store sensitive data. */
- (CDHRepo*) initWithDocumentsStorage:(NSString*) fileName;
+/**Initializes the repository with incremental store storage. */
+
+- (CDHRepo *)initWithIncrementalStoreClass:(Class)incrementalStore configuration:(NSString*)configuration URL:(NSURL*) url options:(NSDictionary*) options;
+
+/**This creates a (new) CoreDataStack for backwards compatability interop with CDHRepo. This allows you to do a staggered migration of your code.
+
+ "Under the hood", this stack is a sibling of the receiver. Changes in one are not reflected in the other without explicit fault semantics. If this bothers you, I recommend you migrate more code.
+
+ 1. You probably want to hang onto this pointer in some capacity rather than create new ones all the time.
+ 2. CDHRepo and CoreDataStack objects can't interact. For one thing, the confinement pattern is totally different, so it is difficult to work out when objects under two sets of rules are both legal. For another thing, it just plain isn't supported. You can get some small amount of interop with backwardsCompatabilityVersion:inStack: so that you can stagger your migration.
+
+ @warning this isn't supported for non-root repos. I have no idea what it will do.
+
+ */
+
+-(CoreDataStack*) newBackwardsCompatabilityStack;
+
+/**This allows very limited migration for an object between the Stack and Repo worlds.
+
+ @param object a repo-based object. The object must be valid at the time this is called according to the CDHRepo confinement rules.
+ @param stack the stack to which you want to port the object
+ @return An object that is valid on the MAIN THREAD in the CoreDataStack. It is okay to call this function from not-the-main-thread, but the return value cannot be used for any purpose until you arrive on the main thread.
+
+ Consider using performBlockAndReturnOnMain to call this function.
+
+ @warning this function is provided only for backwards compatability reasons. It is very slow as it aquires a large number of locks.
+
+ */
+
+-(id) backwardsCompatabilityVersion:(NSManagedObject*) object inStack:(CoreDataStack*) stack;
+-(NSArray*) backwardsCompatabilityVersions:(NSArray*) objects inStack:(CoreDataStack*) stack;
/**
ALL CDH OBJECTS MUST BE ACCESSED INSIDE A BLOCK! IF YOU ACCESS OBJECTS OUTSIDE THEIR BLOCK THIS PRODUCES **UNDEFINED** BEHAVIOR. **UNDEFINED** MEANS **UNDEFINED**. WE COULD PLAY PONG.
@@ -28,7 +60,7 @@ typedef void(^operationBlock)();
You *may* **copy** fundamental types (strings, NSNumbers, and collections containing only these) which are then "ordinary" objects that are usable from any thread. This strategy might make sense if you are going to do something that takes a long time (like read in a large file that is specified by the CoreData object) and don't want other queries to be stopped in their tracks in the meantime. (You can also run long operations against a separate CDHRepo that's been forked off the main repo; this is probably faster in some situations.)
- Note that BY DESIGN THESE BLOCKS ARE ASYNCHRONOUS, and there is NO WAY to make them syncronous. Attempts to do so by lock, mutex, semaphore, hook, crook, or even my own guide for making things synchronous (http://sealedabstract.com/uncategorized/roll-your-own-dispatch_sync/) are NOT SUPPORTED and WILL CAUSE DEADLOCKS EVEN IF IT WORKS SOMETIMES ON THE SIMULATOR.
+ Note that BY DESIGN THESE BLOCKS ARE ASYNCHRONOUS, and there is NO WAY to make them syncronous. Attempts to do so by lock, mutex, semaphore, hook, crook, or even my own guide for making things synchronous (http://sealedabstract.com/uncategorized/roll-your-own-dispatch_sync/) are NOT SUPPORTED and WILL CAUSE DEADLOCKS EVEN IF IT WORKS SOMETIMES ON THE SIMULATOR. If you want a synchronous version, check out performBlockAndWait__DISPATCH_SYNC_TO_MAIN_IS_NOW_FORBIDDEN__.
*/
-(void) performBlock:(operationBlock) b;
@@ -47,8 +79,8 @@ typedef void(^operationBlock)();
*/
-(void) performBlockAndReturnOnMain:(operationBlock) b;
-/**Okay, I lied. There is a way to make it synchronous. The thing is, you can't touch the main thread with this. Ever. */
--(void) performOnBlockAndWait__MAIN__IS__FORBIDDEN__:(operationBlock) b;
+/**This is like performBlock, but it waits for the operation to complete. You **MAY NOT** dispatch_sync onto the main thread inside this block. It's recommdended that you not use this method unless absolutely necessary. */
+-(void) performBlockAndWait__DISPATCH_SYNC_TO_MAIN_IS_NOW_FORBIDDEN__:(operationBlock) b;
/**This function must be run from a block. */
- (NSArray *)executeFetchRequest:(NSFetchRequest *)fetchRequest err:(NSError**) err;
@@ -60,6 +92,10 @@ typedef void(^operationBlock)();
-(id) objectWithObjectID:(NSManagedObjectID*) obj;
+#ifdef CAFFEINE_IOS_IS_AVAILABLE
+- (NSArray*) arrayWithOpaqueResult:(CaffeineOpaqueResult*) opaqueResult;
+#endif
+
/**This drops the object from ram.
@warning it's a bug to call this on an object with unsaved changes. */
@@ -70,5 +106,9 @@ typedef void(^operationBlock)();
+/**@section private*/
+
+//these methods are not to be used
++(CDHRepo*) repoLookupWithMoc:(NSManagedObjectContext*) moc;
@end
View
@@ -7,8 +7,18 @@
//
#import "CDHRepo.h"
-#import <DCAKit/NSError+LessTerrible.h>
+#import <DCAKit/DCAKit.h>
+#import "CoreDataStack.h"
static CDHRepo *rootRepo;
+static NSMapTable *reposByMoc;
+
+
+#ifdef CAFFEINE_IOS_IS_AVAILABLE
+@protocol DontCoupleWithCaffeineProtocol
+- (NSArray*) arrayWithOpaqueResult:(CaffeineOpaqueResult*) opaqueResult;
+@end
+#endif
+
@interface CDHRepo() {
NSManagedObjectContext *_moc;
NSPersistentStoreCoordinator *_psc;
@@ -18,19 +28,30 @@ @interface CDHRepo() {
@implementation CDHRepo
#pragma mark initializers
-- (CDHRepo *)initWithBlackholeStorage {
+
+- (id)init {
if (self = [super init]) {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ reposByMoc = [NSMapTable weakToWeakObjectsMapTable];
+ });
+ }
+ return self;
+}
+- (CDHRepo *)initWithBlackholeStorage {
+ if (self = [self init]) {
_psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]]];
NSError *err = nil;
[_psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:&err];
if (err) [err present];
_moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
+ reposByMoc[_moc] = self;
}
return self;
}
- (CDHRepo*) initWithDocumentsStorage:(NSString*) fileName {
- if (self = [super init]) {
+ if (self = [self init]) {
_psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]]];
NSString *documentsdirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSURL *url = [NSURL fileURLWithPath:[documentsdirectory stringByAppendingPathComponent:fileName]];
@@ -39,10 +60,32 @@ - (CDHRepo*) initWithDocumentsStorage:(NSString*) fileName {
if (err) [err present];
_moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_moc setPersistentStoreCoordinator:_psc];
+ reposByMoc[_moc] = self;
+
+ }
+ return self;
+}
+
+- (CDHRepo *)initWithIncrementalStoreClass:(Class)incrementalStore configuration:(NSString*)configuration URL:(NSURL*) url options:(NSDictionary*) options {
+ if (self = [self init]) {
+ _psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]]];
+ [NSPersistentStoreCoordinator registerStoreClass:incrementalStore forStoreType:NSStringFromClass(incrementalStore)];
+ NSError *err = nil;
+ [_psc addPersistentStoreWithType:NSStringFromClass(incrementalStore) configuration:configuration URL:url options:options error:&err];
+ if (err) [err present];
+ _moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
+ [_moc setPersistentStoreCoordinator:_psc];
+ reposByMoc[_moc] = self;
}
return self;
}
+-(CoreDataStack*) newBackwardsCompatabilityStack {
+ return [CoreDataStack stackWithPersistentStoreCoordinator:_psc];
+
+}
+
+
#pragma mark threading
-(void) internalReallyPerformBlock:(operationBlock) b {
@@ -57,7 +100,7 @@ -(void) internalPerformBlock:(operationBlock) b {
}];
}
--(void) performOnBlockAndWait__MAIN__IS__FORBIDDEN__:(operationBlock)b {
+-(void) performBlockAndWait__DISPATCH_SYNC_TO_MAIN_IS_NOW_FORBIDDEN__:(operationBlock)b {
[_moc performBlockAndWait:^{
[self internalReallyPerformBlock:b];
}];
@@ -103,6 +146,32 @@ - (id)insertInstanceOfClass:(Class)c {
return [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(c) inManagedObjectContext:_moc];
}
+#ifdef CAFFEINE_IOS_IS_AVAILABLE
+- (NSArray*) arrayWithOpaqueResult:(CaffeineOpaqueResult*) opaqueResult {
+ NSAssert(threading_looks_okay, @"Try doing this inside a block.");
+ id<DontCoupleWithCaffeineProtocol> caffeinableContext = (id<DontCoupleWithCaffeineProtocol>) _moc;
+ return [caffeinableContext arrayWithOpaqueResult:opaqueResult];
+}
+#endif
+
+- (NSManagedObject *)backwardsCompatabilityVersion:(NSManagedObject *)object inStack:(CoreDataStack *)stack {
+ __block NSManagedObject *mainThreadObj = nil;
+ [stack backgroundOperationSync:^{
+ NSManagedObject *obj = [stack objectOnCurrentThreadFromID:object.objectID];
+ mainThreadObj = [stack objectOnMainThread:obj];
+ }];
+ return mainThreadObj;
+
+}
+
+- (NSArray *)backwardsCompatabilityVersions:(NSArray *)objects inStack:(CoreDataStack *)stack {
+ NSMutableArray *newVersions = [[NSMutableArray alloc] initWithCapacity:objects.count];
+ for(NSManagedObject *obj in objects) {
+ [newVersions addObject:[self backwardsCompatabilityVersion:obj inStack:stack]];
+ }
+ return newVersions;
+}
+
- (void)fault:(NSManagedObject *)obj {
NSAssert(!obj.hasChanges, @"Bug. Don't fault things with changes.");
[_moc refreshObject:obj mergeChanges:NO];
@@ -118,5 +187,11 @@ + (void) setRootRepo:(CDHRepo*) root {
rootRepo = root;
}
+#pragma mark private
+
+
++ (CDHRepo *)repoLookupWithMoc:(NSManagedObjectContext *)moc {
+ return reposByMoc[moc];
+}
@end
@@ -22,6 +22,7 @@
#import <CoreDataHelp/RegistryObserverProtocol.h>
#import <CoreDataHelp/NSFetchRequest+CDH.h>
#import <CoreDataHelp/NSManagedObject+ExternalStorage.h>
+#import <CoreDataHelp/NSManagedObject+CDHRepo.h>
void objc_retain(id x);
#define WORK_AROUND_RDAR_10732696(X) objc_retain(X)
@@ -20,6 +20,7 @@
+ (CoreDataStack*) onDiskStack;
+ (CoreDataStack*) incrementalStoreStack:(Class) autoInstallableIncrementalStore;
+ (CoreDataStack*) incrementalStoreStackWithClass:(Class) nsIncrementalStoreClass model:(NSManagedObjectModel*) model configuration:(NSString*) configuration url:(NSURL*) url options:(NSDictionary*) options caching:(BOOL) caching;
++ (CoreDataStack*) stackWithPersistentStoreCoordinator:(NSPersistentStoreCoordinator*) coordinator;
- (id) executeFetchRequest:(NSFetchRequest*) fetchRequest err:(NSError * __autoreleasing *) err;
- (id) insertNewObjectOfClass:(Class) c;
@@ -153,6 +153,14 @@ + (CoreDataStack*) incrementalStoreStack:(Class) autoInstallableIncrementalStore
return stack;
}
++ (CoreDataStack*) stackWithPersistentStoreCoordinator:(NSPersistentStoreCoordinator*) coordinator {
+ CoreDataStack *stack = [[CoreDataStack alloc] init];
+ stack->managedObjectModel = coordinator.managedObjectModel;
+ stack->persistentStoreCoordinator = coordinator;
+ [stack installManagedObjectContexts];
+ return stack;
+}
+
+ (CoreDataStack*) incrementalStoreStackWithClass:(Class) nsIncrementalStoreClass model:(NSManagedObjectModel*) model configuration:(NSString*) configuration url:(NSURL*) url options:(NSDictionary*) options caching:(BOOL) caching{
CoreDataStack *stack = [[CoreDataStack alloc] init];
stack->managedObjectModel = model;
@@ -0,0 +1,13 @@
+//
+// NSManagedObject+CDHRepo.h
+// CoreDataHelp
+//
+// Created by Drew Crawford on 2/21/13.
+//
+//
+
+#import <CoreData/CoreData.h>
+@class CDHRepo;
+@interface NSManagedObject (CDHRepo)
+-(CDHRepo*) repo;
+@end
@@ -0,0 +1,15 @@
+//
+// NSManagedObject+CDHRepo.m
+// CoreDataHelp
+//
+// Created by Drew Crawford on 2/21/13.
+//
+//
+
+#import "NSManagedObject+CDHRepo.h"
+#import "CDHRepo.h"
+@implementation NSManagedObject (CDHRepo)
+- (CDHRepo *)repo {
+ return [CDHRepo repoLookupWithMoc:self.managedObjectContext];
+}
+@end

0 comments on commit 4698767

Please sign in to comment.