mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-24 04:46:01 +08:00
Overhauled the object seeder API. It's much cleaner. Added example code to the RKTwitterCoreDataExample
This commit is contained in:
@@ -10,5 +10,5 @@
|
||||
#import "../ObjectMapping/ObjectMapping.h"
|
||||
#import "RKManagedObject.h"
|
||||
#import "RKManagedObjectStore.h"
|
||||
#import "RKObjectSeeder.h"
|
||||
#import "RKManagedObjectSeeder.h"
|
||||
#import "RKManagedObjectCache.h"
|
||||
65
Code/CoreData/RKManagedObjectSeeder.h
Normal file
65
Code/CoreData/RKManagedObjectSeeder.h
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// RKManagedObjectSeeder.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 3/4/10.
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "../ObjectMapping/ObjectMapping.h"
|
||||
|
||||
@protocol RKManagedObjectSeederDelegate
|
||||
@required
|
||||
|
||||
// Invoked when the seeder creates a new object
|
||||
- (void)didSeedObject:(NSObject<RKObjectMappable>*)object fromFile:(NSString*)fileName;
|
||||
@end
|
||||
|
||||
/**
|
||||
* Provides an interface for generating a seed database suitable for initializing
|
||||
* a Core Data backed RestKit application. The object seeder loads files from the
|
||||
* application's main bundle and processes them with the Object Mapper to produce
|
||||
* a database on disk. This file can then be copied into the main bundle of an application
|
||||
* and provided to RKManagedObjectStore at initialization to start the app with a set of
|
||||
* data immediately available for use within Core Data.
|
||||
*/
|
||||
@interface RKManagedObjectSeeder : NSObject {
|
||||
RKObjectManager* _manager;
|
||||
NSObject<RKManagedObjectSeederDelegate>* _delegate;
|
||||
}
|
||||
|
||||
// Delegate for seeding operations
|
||||
@property (nonatomic, assign) NSObject<RKManagedObjectSeederDelegate>* delegate;
|
||||
|
||||
// Path to the generated seed database on disk
|
||||
@property (nonatomic, readonly) NSString* pathToSeedDatabase;
|
||||
|
||||
/**
|
||||
* Generates a seed database using an object manager and a null terminated list of files. Exits
|
||||
* the seeding process and outputs an informational message
|
||||
*/
|
||||
+ (void)generateSeedDatabaseWithObjectManager:(RKObjectManager*)objectManager fromFiles:(NSString*)fileName, ...;
|
||||
|
||||
/**
|
||||
* Returns an object seeder ready to begin seeding. Requires a fully configured instance of an object manager.
|
||||
*/
|
||||
+ (RKManagedObjectSeeder*)objectSeederWithObjectManager:(RKObjectManager*)objectManager;
|
||||
|
||||
/**
|
||||
* Seed the database with objects from the specified file(s). The list must be terminated by nil
|
||||
*/
|
||||
- (void)seedObjectsFromFiles:(NSString*)fileName, ...;
|
||||
|
||||
/**
|
||||
* Seed the database with objects from the specified file. Optionally use the specified mappable class and
|
||||
* keyPath to traverse the object graph before seeding
|
||||
*/
|
||||
- (void)seedObjectsFromFile:(NSString*)fileName toClass:(Class<RKObjectMappable>)nilOrMppableClass keyPath:(NSString*)nilOrKeyPath;
|
||||
|
||||
/**
|
||||
* Completes a seeding session by persisting the store, outputing an informational message
|
||||
* and exiting the process
|
||||
*/
|
||||
- (void)finalizeSeedingAndExit;
|
||||
|
||||
@end
|
||||
132
Code/CoreData/RKManagedObjectSeeder.m
Normal file
132
Code/CoreData/RKManagedObjectSeeder.m
Normal file
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// RKObjectSeeder.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 3/4/10.
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKManagedObjectSeeder.h"
|
||||
#import "RKManagedObjectStore.h"
|
||||
|
||||
@interface RKManagedObjectSeeder (Private)
|
||||
- (id)initWithObjectManager:(RKObjectManager*)manager;
|
||||
- (void)seedObjectsFromFileNames:(NSArray*)fileNames;
|
||||
@end
|
||||
|
||||
@implementation RKManagedObjectSeeder
|
||||
|
||||
@synthesize delegate = _delegate;
|
||||
|
||||
+ (void)generateSeedDatabaseWithObjectManager:(RKObjectManager*)objectManager fromFiles:(NSString*)firstFileName, ... {
|
||||
RKManagedObjectSeeder* seeder = [RKManagedObjectSeeder objectSeederWithObjectManager:objectManager];
|
||||
|
||||
va_list args;
|
||||
va_start(args, firstFileName);
|
||||
NSMutableArray* fileNames = [NSMutableArray array];
|
||||
for (NSString* fileName = firstFileName; fileName != nil; fileName = va_arg(args, id)) {
|
||||
[fileNames addObject:fileName];
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
// Seed the files
|
||||
for (NSString* fileName in fileNames) {
|
||||
[seeder seedObjectsFromFile:fileName toClass:nil keyPath:nil];
|
||||
}
|
||||
|
||||
[seeder finalizeSeedingAndExit];
|
||||
}
|
||||
|
||||
+ (RKManagedObjectSeeder*)objectSeederWithObjectManager:(RKObjectManager*)objectManager {
|
||||
return [[[RKManagedObjectSeeder alloc] initWithObjectManager:objectManager] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithObjectManager:(RKObjectManager*)manager {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
_manager = [manager retain];
|
||||
|
||||
// Delete any existing persistent store
|
||||
[_manager.objectStore deletePersistantStore];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_manager release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString*)pathToSeedDatabase {
|
||||
return _manager.objectStore.pathToStoreFile;
|
||||
}
|
||||
|
||||
- (void)seedObjectsFromFiles:(NSString*)firstFileName, ... {
|
||||
va_list args;
|
||||
va_start(args, firstFileName);
|
||||
NSMutableArray* fileNames = [NSMutableArray array];
|
||||
for (NSString* fileName = firstFileName; fileName != nil; fileName = va_arg(args, id)) {
|
||||
[fileNames addObject:fileName];
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
for (NSString* fileName in fileNames) {
|
||||
[self seedObjectsFromFile:fileName toClass:nil keyPath:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)seedObjectsFromFile:(NSString*)fileName toClass:(Class<RKObjectMappable>)nilOrMppableClass keyPath:(NSString*)nilOrKeyPath {
|
||||
NSError* error = nil;
|
||||
NSArray* mappedObjects;
|
||||
NSString* filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
|
||||
NSString* payload = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
|
||||
|
||||
if (nil == error) {
|
||||
// TODO: When we support multiple parsers, we should auto-detect the MIME Type from the file extension
|
||||
// and pass it through to the mapper
|
||||
id objects = [_manager.mapper parseString:payload];
|
||||
NSAssert1(objects != nil, @"Unable to parse data from file %@", filePath);
|
||||
if (nilOrKeyPath) {
|
||||
objects = [objects valueForKeyPath:nilOrKeyPath];
|
||||
}
|
||||
NSAssert1([objects isKindOfClass:[NSArray class]], @"Expected an NSArray of objects, got %@", objects);
|
||||
NSAssert1([[objects objectAtIndex:0] isKindOfClass:[NSDictionary class]], @"Expected an array of NSDictionaries, got %@", [objects objectAtIndex:0]);
|
||||
|
||||
if (nilOrMppableClass) {
|
||||
mappedObjects = [_manager.mapper mapObjectsFromArrayOfDictionaries:objects toClass:nilOrMppableClass];
|
||||
} else {
|
||||
mappedObjects = [_manager.mapper mapObjectsFromArrayOfDictionaries:objects];
|
||||
}
|
||||
|
||||
// Inform the delegate
|
||||
if (self.delegate) {
|
||||
for (NSObject<RKObjectMappable>* object in mappedObjects) {
|
||||
[self.delegate didSeedObject:object fromFile:fileName];
|
||||
}
|
||||
}
|
||||
|
||||
NSLog(@"[RestKit] RKManagedObjectSeeder: Seeded %d objects from %@...", [mappedObjects count], [NSString stringWithFormat:@"%@", fileName]);
|
||||
} else {
|
||||
NSLog(@"Unable to read file %@: %@", fileName, [error localizedDescription]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)finalizeSeedingAndExit {
|
||||
NSError* error = [[_manager objectStore] save];
|
||||
if (error != nil) {
|
||||
NSLog(@"[RestKit] RKManagedObjectSeeder: Error saving object context: %@", [error localizedDescription]);
|
||||
}
|
||||
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString* basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
|
||||
NSString* storeFileName = [[_manager objectStore] storeFilename];
|
||||
NSString* destinationPath = [basePath stringByAppendingPathComponent:storeFileName];
|
||||
NSLog(@"[RestKit] RKManagedObjectSeeder: A seeded database has been generated at '%@'. "
|
||||
@"Please execute `open %@` in your Terminal and copy %@ to your app. Be sure to add the seed database to your \"Copy Resources\" build phase.",
|
||||
destinationPath, basePath, storeFileName);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -152,7 +152,9 @@ static NSString* const kRKManagedObjectContextKey = @"RKManagedObjectContext";
|
||||
|
||||
// Clear the current managed object context. Will be re-created next time it is accessed.
|
||||
NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary];
|
||||
[threadDictionary setObject:nil forKey:kRKManagedObjectContextKey];
|
||||
if ([threadDictionary objectForKey:kRKManagedObjectContextKey]) {
|
||||
[threadDictionary setNilValueForKey:kRKManagedObjectContextKey];
|
||||
}
|
||||
|
||||
[self createPersistentStoreCoordinator];
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
//
|
||||
// RKObjectSeeder.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 3/4/10.
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "../ObjectMapping/ObjectMapping.h"
|
||||
|
||||
// TODO: This class needs an API scrubbing
|
||||
// TODO: Should be updated with ability to auto-detect MIME type
|
||||
// from the file extension. Does this need a delegate property?
|
||||
@interface RKObjectSeeder : NSObject {
|
||||
RKObjectManager* _manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a new object seeder
|
||||
*/
|
||||
- (id)initWithObjectManager:(RKObjectManager*)manager;
|
||||
|
||||
/**
|
||||
* Read a file from the main bundle and seed the database with its contents.
|
||||
* Returns the array of model objects built from the file.
|
||||
*/
|
||||
- (NSArray*)seedDatabaseWithBundledFile:(NSString*)fileName ofType:(NSString*)type;
|
||||
|
||||
/**
|
||||
* Seeds the database with an array of files of the specified type
|
||||
*/
|
||||
- (void)seedDatabaseWithBundledFiles:(NSArray*)fileNames ofType:(NSString*)type;
|
||||
|
||||
/**
|
||||
* Seed a specific object class with data from a file
|
||||
*/
|
||||
- (void)seedObjectsFromFile:(NSString*)fileName ofType:(NSString*)type toClass:(Class)theClass keyPath:(NSString*)keyPath;
|
||||
|
||||
/**
|
||||
* Completes a seeding session by persisting the store, outputing an informational message
|
||||
* and exiting the process
|
||||
*/
|
||||
- (void)finalizeSeedingAndExit;
|
||||
|
||||
@end
|
||||
@@ -1,82 +0,0 @@
|
||||
//
|
||||
// RKObjectSeeder.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 3/4/10.
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKObjectSeeder.h"
|
||||
#import "RKManagedObjectStore.h"
|
||||
|
||||
@implementation RKObjectSeeder
|
||||
|
||||
- (id)initWithObjectManager:(RKObjectManager*)manager {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
_manager = [manager retain];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_manager release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSArray*)seedDatabaseWithBundledFile:(NSString*)fileName ofType:(NSString*)type {
|
||||
NSError* error = nil;
|
||||
NSString* filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:type];
|
||||
NSString* payload = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
|
||||
if (nil == error) {
|
||||
return [[_manager mapper] mapFromString:payload];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)seedDatabaseWithBundledFiles:(NSArray*)fileNames ofType:(NSString*)type {
|
||||
NSLog(@"[RestKit] RKModelSeeder: Seeding database with contents of %d %@ files...", [fileNames count], [type uppercaseString]);
|
||||
for (NSString* fileName in fileNames) {
|
||||
NSArray* objects = [self seedDatabaseWithBundledFile:fileName ofType:type];
|
||||
NSLog(@"[RestKit] RKModelSeeder: Seeded %d objects from %@...", [objects count], [NSString stringWithFormat:@"%@.%@", fileName, type]);
|
||||
}
|
||||
|
||||
[self finalizeSeedingAndExit];
|
||||
}
|
||||
|
||||
- (void)seedObjectsFromFile:(NSString*)fileName ofType:(NSString*)type toClass:(Class)theClass keyPath:(NSString*)keyPath {
|
||||
NSError* error = nil;
|
||||
NSString* filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:type];
|
||||
NSString* payload = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
|
||||
if (nil == error) {
|
||||
id objects = [_manager.mapper parseString:payload];
|
||||
NSAssert1(objects != nil, @"Unable to parse data from file %@", filePath);
|
||||
id parseableObjects = [objects valueForKeyPath:keyPath];
|
||||
NSAssert1([parseableObjects isKindOfClass:[NSArray class]], @"Expected an NSArray of objects, got %@", objects);
|
||||
NSAssert1([[parseableObjects objectAtIndex:0] isKindOfClass:[NSDictionary class]], @"Expected an array of NSDictionaries, got %@", [objects objectAtIndex:0]);
|
||||
|
||||
NSArray* mappedObjects = [_manager.mapper mapObjectsFromArrayOfDictionaries:parseableObjects toClass:theClass];
|
||||
NSLog(@"[RestKit] RKModelSeeder: Seeded %d objects from %@...", [mappedObjects count], [NSString stringWithFormat:@"%@.%@", fileName, type]);
|
||||
} else {
|
||||
NSLog(@"Unable to read file %@ with type %@: %@", fileName, type, [error localizedDescription]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)finalizeSeedingAndExit {
|
||||
NSError* error = [[_manager objectStore] save];
|
||||
if (error != nil) {
|
||||
NSLog(@"[RestKit] RKModelSeeder: Error saving object context: %@", [error localizedDescription]);
|
||||
}
|
||||
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString* basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
|
||||
NSString* storeFileName = [[_manager objectStore] storeFilename];
|
||||
NSString* destinationPath = [basePath stringByAppendingPathComponent:storeFileName];
|
||||
NSLog(@"[RestKit] RKModelSeeder: A Pre-loaded database has been generated at %@. Please copy into Resources/", destinationPath);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user