Update examples projects to reflect Core Data API changes

This commit is contained in:
Blake Watters
2012-08-07 10:01:05 -04:00
parent c041c3dde6
commit 99738db1cc
10 changed files with 140 additions and 91 deletions

View File

@@ -8,9 +8,5 @@
#import "RKCatalog.h"
@interface RKCoreDataExample : UITableViewController {
NSArray *_articles;
UISegmentedControl *_segmentedControl;
}
@interface RKCoreDataExample : UITableViewController
@end

View File

@@ -26,38 +26,63 @@
@end
@interface RKCoreDataExample ()
@property (nonatomic, readwrite, retain) NSArray *articles;
@property (nonatomic, readwrite, retain) UISegmentedControl *segmentedControl;
@end
////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
@implementation RKCoreDataExample
@synthesize articles = _articles;
@synthesize segmentedControl = _segmentedControl;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
RKObjectManager *manager = [RKObjectManager managerWithBaseURLString:@"http://restkit.org"];
manager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"RKCoreDataExample.sqlite"];
NSURL *baseURL = [NSURL URLWithString:@"http://restkit.org"];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:baseURL];
// Create the managed object store and add a SQLite persistent store
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSString *storePath = [[RKDirectory applicationDataDirectory] stringByAppendingPathComponent:@"RKCoreDataExample.sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil error:&error];
NSAssert(persistentStore, @"Failed to create SQLite store at path %@ due to error: %@", storePath, error);
manager.managedObjectStore = managedObjectStore;
[managedObjectStore release];
// Once we are done with configuration, ask the store to create the primary and main queue contexts
[managedObjectStore createManagedObjectContexts];
[RKManagedObjectStore setDefaultStore:managedObjectStore];
[RKObjectManager setSharedManager:manager];
// Create some starter objects if the database is empty
if ([Article count:nil] == 0) {
NSUInteger count = [managedObjectStore.mainQueueManagedObjectContext countForEntityForName:@"Article" predicate:nil error:&error];
if (count == 0) {
for (int i = 1; i <= 5; i++) {
Article *article = [Article object];
Article *article = [managedObjectStore.mainQueueManagedObjectContext insertNewObjectForEntityForName:@"Article"];
article.articleID = [NSNumber numberWithInt:i];
article.title = [NSString stringWithFormat:@"Article %d", i];
article.body = @"This is the body";
// Persist the object store
[manager.objectStore save:nil];
}
// Persist the new objects
BOOL success = [managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:&error];
NSAssert(success, @"Failed to persist manged object context due to error: %@", error);
}
NSArray *items = [NSArray arrayWithObjects:@"All", @"Sorted", @"By Predicate", @"By ID", nil];
_segmentedControl = [[UISegmentedControl alloc] initWithItems:items];
_segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
_segmentedControl.momentary = NO;
[_segmentedControl addTarget:self action:@selector(updateTableView) forControlEvents:UIControlEventValueChanged];
_segmentedControl.selectedSegmentIndex = 0;
self.segmentedControl = [[[UISegmentedControl alloc] initWithItems:items] autorelease];
self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
self.segmentedControl.momentary = NO;
[self.segmentedControl addTarget:self action:@selector(updateTableView) forControlEvents:UIControlEventValueChanged];
self.segmentedControl.selectedSegmentIndex = 0;
}
return self;
@@ -82,14 +107,13 @@
- (NSFetchRequest *)fetchRequestForSelectedSegment
{
NSFetchRequest *fetchRequest = [Article fetchRequest];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
NSPredicate *predicate = nil;
switch (_segmentedControl.selectedSegmentIndex) {
// All objects
case 0:
// An empty fetch request will return all objects
// Duplicates the functionality of [Article allObjects]
break;
// Sorted
@@ -100,14 +124,12 @@
// By Predicate
case 2:
// Duplicates functionality of calling [Article objectsWithPredicate:predicate];
predicate = [NSPredicate predicateWithFormat:@"title CONTAINS[c] %@", @"2"];
[fetchRequest setPredicate:predicate];
break;
// By ID
case 3:
// Duplicates functionality of [Article findByAttribute:@"articleID" withValue:[NSNumber numberWithInt:3]];
predicate = [NSPredicate predicateWithFormat:@"%K = %d", @"articleID", 3];
[fetchRequest setPredicate:predicate];
break;
@@ -121,9 +143,9 @@
- (void)updateTableView
{
[_articles release];
NSError *error;
NSFetchRequest *fetchRequest = [self fetchRequestForSelectedSegment];
_articles = [[Article objectsWithFetchRequest:fetchRequest] retain];
self.articles = [[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext executeFetchRequest:fetchRequest error:&error];
[self.tableView reloadData];
}

View File

@@ -20,17 +20,18 @@
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:gRKCatalogBaseURL];
RKManagedObjectStore *objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"RKRelationshipMappingExample.sqlite"];
objectManager.objectStore = objectStore;
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
RKManagedObjectMapping *taskMapping = [RKManagedObjectMapping mappingForClass:[Task class] inManagedObjectStore:objectStore];
RKEntityMapping *taskMapping = [RKEntityMapping mappingForEntityForName:@"Task" inManagedObjectStore:managedObjectStore];
taskMapping.primaryKeyAttribute = @"taskID";
[taskMapping mapKeyPath:@"id" toAttribute:@"taskID"];
[taskMapping mapKeyPath:@"name" toAttribute:@"name"];
[taskMapping mapKeyPath:@"assigned_user_id" toAttribute:@"assignedUserID"];
[objectManager.mappingProvider setMapping:taskMapping forKeyPath:@"task"];
RKManagedObjectMapping *userMapping = [RKManagedObjectMapping mappingForClass:[User class] inManagedObjectStore:objectStore];
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:@"User" inManagedObjectStore:managedObjectStore];
userMapping.primaryKeyAttribute = @"userID";
[userMapping mapAttributes:@"name", @"email", nil];
[userMapping mapKeyPath:@"id" toAttribute:@"userID"];
@@ -38,8 +39,7 @@
[objectManager.mappingProvider setMapping:userMapping forKeyPath:@"user"];
// Hydrate the assignedUser association via primary key
[taskMapping hasOne:@"assignedUser" withMapping:userMapping];
[taskMapping connectRelationship:@"assignedUser" withObjectForPrimaryKeyAttribute:@"assignedUserID"];
[taskMapping connectRelationship:@"assignedUser" withMapping:userMapping fromKeyPath:@"assignedUserID" toKeyPath:@"userID"];
// NOTE - Project is not backed by Core Data
RKObjectMapping *projectMapping = [RKObjectMapping mappingForClass:[Project class]];
@@ -48,6 +48,20 @@
[projectMapping mapRelationship:@"user" withMapping:userMapping];
[projectMapping mapRelationship:@"tasks" withMapping:taskMapping];
[objectManager.mappingProvider setMapping:projectMapping forKeyPath:@"project"];
// Complete Core Data initialization
NSError *error;
NSString *storePath = [[RKDirectory applicationDataDirectory] stringByAppendingPathComponent:@"RKRelationshipMappingExample.sqlite"];
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil error:&error];
NSAssert(persistentStore, @"Failed to create persistent store with error: %@", error);
[managedObjectStore createManagedObjectContexts];
// Create a managed object cache. To use the In Memory Cache, you must configure it after context creation
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.primaryManagedObjectContext];
// TODO: Need to update setPrimaryKeyAttributeName to use info dictionary...
objectManager.managedObjectStore = managedObjectStore;
[managedObjectStore release];
}
return self;
@@ -76,7 +90,10 @@
- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error!" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"Rats!" otherButtonTitles:nil];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error!"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:@"Rats!" otherButtonTitles:nil];
[alert show];
[alert release];
}
@@ -151,13 +168,11 @@
}
if (indexPath.section == 0) {
Project *project = (Project *)[_objects objectAtIndex:indexPath.row];
Project *project = [_objects objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.textLabel.text = project.name;
} else if (indexPath.section == 1) {
// NOTE: We refetch the object here because Project is not Core Data backed
NSManagedObject *objectReference = [_selectedProject.tasks objectAtIndex:indexPath.row];
Task *task = (Task *)[[RKObjectManager sharedManager].objectStore objectWithID:[objectReference objectID]];
Task *task = [_selectedProject.tasks objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"%@", task.name];
cell.detailTextLabel.text = [NSString stringWithFormat:@"Assigned to: %@", task.assignedUser.name];
}

View File

@@ -371,7 +371,7 @@
2501DE4F13607B67003DE9E4 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0420;
LastUpgradeCheck = 0450;
ORGANIZATIONNAME = "Two Toasters";
};
buildConfigurationList = 2501DE5213607B67003DE9E4 /* Build configuration list for PBXProject "RKCatalog" */;
@@ -569,6 +569,7 @@
GCC_DYNAMIC_NO_PIC = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "App/RKCatalog-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/../../Headers\"";
INFOPLIST_FILE = "App/RKCatalog-Info.plist";
LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)\"";
@@ -585,6 +586,7 @@
COPY_PHASE_STRIP = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "App/RKCatalog-Prefix.pch";
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/../../Headers\"";
INFOPLIST_FILE = "App/RKCatalog-Info.plist";
LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)\"";

View File

@@ -210,7 +210,7 @@
25D6390B135184CE000879B1 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0430;
LastUpgradeCheck = 0450;
};
buildConfigurationList = 25D6390E135184CE000879B1 /* Build configuration list for PBXProject "RKMacOSX" */;
compatibilityVersion = "Xcode 3.2";
@@ -372,6 +372,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -393,6 +394,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_ENABLE_OBJC_EXCEPTIONS = YES;

View File

@@ -23,7 +23,8 @@
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
// Initialize RestKit
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURLString:@"http://twitter.com"];
NSURL *baseURL = [NSURL URLWithString:@"http://twitter.com"];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL];
// Enable automatic network activity indicator management
objectManager.client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;

View File

@@ -20,21 +20,17 @@
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Initialize RestKit
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURLString:@"http://twitter.com"];
NSURL *baseURL = [NSURL URLWithString:@"http://twitter.com"];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL];
// Enable automatic network activity indicator management
objectManager.client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
// Initialize object store
#ifdef RESTKIT_GENERATE_SEED_DB
NSString *seedDatabaseName = nil;
NSString *databaseName = RKDefaultSeedDatabaseFileName;
#else
NSString *seedDatabaseName = RKDefaultSeedDatabaseFileName;
NSString *databaseName = @"RKTwitterData.sqlite";
#endif
objectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:databaseName usingSeedDatabaseName:seedDatabaseName managedObjectModel:nil delegate:self];
// Initialize managed object store
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
objectManager.managedObjectStore = managedObjectStore;
[managedObjectStore release];
// Setup our object mappings
/*!
@@ -42,18 +38,13 @@
name. This allows us to map back Twitter user objects directly onto NSManagedObject instances --
there is no backing model class!
*/
RKManagedObjectMapping *userMapping = [RKManagedObjectMapping mappingForEntityWithName:@"RKTUser" inManagedObjectStore:objectManager.objectStore];
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:@"RKTUser" inManagedObjectStore:managedObjectStore];
userMapping.primaryKeyAttribute = @"userID";
[userMapping mapKeyPath:@"id" toAttribute:@"userID"];
[userMapping mapKeyPath:@"screen_name" toAttribute:@"screenName"];
[userMapping mapAttributes:@"name", nil];
/*!
Map to a target object class -- just as you would for a non-persistent class. The entity is resolved
for you using the Active Record pattern where the class name corresponds to the entity name within Core Data.
Twitter status objects will be mapped onto RKTStatus instances.
*/
RKManagedObjectMapping *statusMapping = [RKManagedObjectMapping mappingForClass:[RKTStatus class] inManagedObjectStore:objectManager.objectStore];
RKEntityMapping *statusMapping = [RKEntityMapping mappingForEntityForName:@"RKTStatus" inManagedObjectStore:managedObjectStore];
statusMapping.primaryKeyAttribute = @"statusID";
[statusMapping mapKeyPathsToAttributes:@"id", @"statusID",
@"created_at", @"createdAt",
@@ -62,7 +53,7 @@
@"in_reply_to_screen_name", @"inReplyToScreenName",
@"favorited", @"isFavorited",
nil];
[statusMapping mapRelationship:@"user" withMapping:userMapping];
[statusMapping mapRelationship:@"user" withMapping:userMapping];
// Update date format so that we can parse Twitter dates properly
// Wed Sep 29 15:31:08 +0000 2010
@@ -74,29 +65,50 @@
// Uncomment this to use XML, comment it to use JSON
// objectManager.acceptMIMEType = RKMIMETypeXML;
// [objectManager.mappingProvider setMapping:statusMapping forKeyPath:@"statuses.status"];
// Database seeding is configured as a copied target of the main application. There are only two differences
// between the main application target and the 'Generate Seed Database' target:
// 1) RESTKIT_GENERATE_SEED_DB is defined in the 'Preprocessor Macros' section of the build setting for the target
// This is what triggers the conditional compilation to cause the seed database to be built
// 2) Source JSON files are added to the 'Generate Seed Database' target to be copied into the bundle. This is required
// so that the object seeder can find the files when run in the simulator.
// so that the object seeder can find the files when run in the simulator.
#ifdef RESTKIT_GENERATE_SEED_DB
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelInfo);
RKLogConfigureByName("RestKit/CoreData", RKLogLevelTrace);
RKManagedObjectSeeder *seeder = [RKManagedObjectSeeder objectSeederWithObjectManager:objectManager];
// Seed the database with instances of RKTStatus from a snapshot of the RestKit Twitter timeline
[seeder seedObjectsFromFile:@"restkit.json" withObjectMapping:statusMapping];
// Seed the database with RKTUser objects. The class will be inferred via element registration
[seeder seedObjectsFromFiles:@"users.json", nil];
// Finalize the seeding operation and output a helpful informational message
[seeder finalizeSeedingAndExit];
// NOTE: If all of your mapped objects use keyPath -> objectMapping registration, you can perform seeding in one line of code:
// [RKManagedObjectSeeder generateSeedDatabaseWithObjectManager:objectManager fromFiles:@"users.json", nil];
NSError *error;
NSString *seedStorePath = [[RKDirectory applicationDataDirectory] stringByAppendingPathComponent:@"RKSeedDatabase.sqlite"];
RKManagedObjectImporter *importer = [[RKManagedObjectImporter alloc] initWithManagedObjectModel:managedObjectModel storePath:seedStorePath];
[importer importObjectsFromItemAtPath:[[NSBundle mainBundle] pathForResource:@"restkit" ofType:@"json"]
withMapping:statusMapping
keyPath:nil
error:&error];
[importer importObjectsFromItemAtPath:[[NSBundle mainBundle] pathForResource:@"users" ofType:@"json"]
withMapping:userMapping
keyPath:@"user"
error:&error];
BOOL success = [importer finishImporting:&error];
if (success) {
[importer logSeedingInfo];
} else {
RKLogError(@"Failed to finish import and save seed database due to error: %@", error);
}
#else
/**
Complete Core Data stack initialization
*/
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [[RKDirectory applicationDataDirectory] stringByAppendingPathComponent:@"RKTwitter.sqlite"];
NSString *seedPath = [[NSBundle mainBundle] pathForResource:@"RKSeedDatabase" ofType:@"sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath error:&error];
NSAssert(persistentStore, @"Failed to add persistent store with error: %@", error);
// Create the managed object contexts
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.primaryManagedObjectContext];
#endif
// Create Window and View Controllers
@@ -109,10 +121,4 @@
return YES;
}
- (void)dealloc
{
[super dealloc];
}
@end

View File

@@ -9,9 +9,6 @@
#import <UIKit/UIKit.h>
#import <RestKit/RestKit.h>
@interface RKTwitterViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, RKObjectLoaderDelegate> {
UITableView *_tableView;
NSArray *_statuses;
}
@interface RKTwitterViewController : UIViewController
- (void)loadObjectsFromDataStore;
@end

View File

@@ -9,8 +9,16 @@
#import "RKTwitterViewController.h"
#import "RKTStatus.h"
@interface RKTwitterViewController () <UITableViewDelegate, UITableViewDataSource, RKObjectLoaderDelegate>
@property (nonatomic, retain) UITableView *tableView;
@property (nonatomic, retain) NSArray *statuses;
@end
@implementation RKTwitterViewController
@synthesize tableView = _tableView;
@synthesize statuses = _statuses;
- (void)loadView
{
[super loadView];
@@ -26,12 +34,12 @@
[self.view insertSubview:imageView atIndex:0];
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480-64) style:UITableViewStylePlain];
_tableView.dataSource = self;
_tableView.delegate = self;
_tableView.backgroundColor = [UIColor clearColor];
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:_tableView];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480-64) style:UITableViewStylePlain];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:self.tableView];
// Load statuses from core data
[self loadObjectsFromDataStore];
@@ -46,11 +54,11 @@
- (void)loadObjectsFromDataStore
{
[_statuses release];
NSFetchRequest *request = [RKTStatus fetchRequest];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"RKTStatus"];
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"createdAt" ascending:NO];
[request setSortDescriptors:[NSArray arrayWithObject:descriptor]];
_statuses = [[RKTStatus objectsWithFetchRequest:request] retain];
fetchRequest.sortDescriptors = @[descriptor];
NSError *error;
self.statuses = [[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext executeFetchRequest:fetchRequest error:&error];
}
- (void)loadData