Files
RestKit/Examples/RKDiscussionBoardExample/DiscussionBoard/Code/Other/DiscussionBoardAppDelegate.m
Blake Watters f3c0995d5e Implementation of Object Mapping 2.0 design:
* Removed RestKit from inheritance hierarchy
  * Mappings are implemented as concrete classes
  * Mapper is much more flexible & powerful
  * Much more robust error handling
  * Serialization is reimplemented as an object mapping operation
  * Added ability to serialize to JSON natively
  * Reworked Core Data integration
  * Simplified the codebase substantially
2011-06-11 19:26:56 -04:00

175 lines
8.2 KiB
Objective-C

//
// DiscussionBoardAppDelegate.m
// DiscussionBoard
//
// Created by Daniel Hammond on 1/7/11.
// Copyright 2011 Two Toasters. All rights reserved.
//
#import "DiscussionBoardAppDelegate.h"
// RestKit
#import <RestKit/RestKit.h>
#import <RestKit/CoreData/CoreData.h>
// Three20
#import <Three20/Three20.h>
#import <Three20/Three20+Additions.h>
// Discussion Board
#import "DBManagedObjectCache.h"
#import "../Controllers/DBTopicViewController.h"
#import "../Controllers/DBTopicsTableViewController.h"
#import "../Controllers/DBPostsTableViewController.h"
#import "../Controllers/DBPostTableViewController.h"
#import "../Controllers/DBLoginOrSignUpViewController.h"
#import "../Models/DBTopic.h"
#import "../Models/DBPost.h"
#import "../Models/DBUser.h"
/**
* The HTTP Header Field we transmit the authentication token obtained
* during login/sign-up back to the server. This token is verified server
* side to establish an authenticated session
*/
static NSString* const kDBAccessTokenHTTPHeaderField = @"X-USER-ACCESS-TOKEN";
@implementation DiscussionBoardAppDelegate
@synthesize window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize the RestKit Object Manager
RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:DBRestKitBaseURL];
// Set the default refresh rate to 1. This means we should always hit the web if we can.
// If the server is unavailable, we will load from the Core Data cache.
[RKRequestTTModel setDefaultRefreshRate:1];
// Set nil for any attributes we expect to appear in the payload, but do not
// TODO: Fix this. Now settable on a per-object basis
// objectManager.mapper.missingElementMappingPolicy = RKSetNilForMissingElementMappingPolicy;
// Initialize object store
// We are using the Core Data support, so we have initialized a managed object store backed
// with a SQLite database. We are also utilizing the managed object cache support to provide
// offline access to locally cached content.
objectManager.objectStore = [[[RKManagedObjectStore alloc] initWithStoreFilename:@"DiscussionBoard.sqlite"] autorelease];
objectManager.objectStore.managedObjectCache = [[DBManagedObjectCache new] autorelease];
// Set Up the Object Mapper
// The object mapper is responsible for mapping JSON encoded representations of objects
// back to local object representations. Here we instruct RestKit how to connect
// sub-dictionaries of attributes to local classes.
RKManagedObjectMapping* userMapping = [RKManagedObjectMapping mappingForClass:[DBUser class]];
userMapping.primaryKeyAttribute = @"userID";
[userMapping mapKeyPathsToAttributes:
@"id", @"userID",
@"email", @"email",
@"username", @"username",
@"single_access_token", @"singleAccessToken",
@"password", @"password",
@"password_confirmation", @"passwordConfirmation",
nil];
RKManagedObjectMapping* topicMapping = [RKManagedObjectMapping mappingForClass:[DBTopic class]];
topicMapping.primaryKeyAttribute = @"topicID";
[topicMapping mapKeyPathsToAttributes:
@"id", @"topicID",
@"name", @"name",
@"user_id", @"userID",
@"created_at", @"createdAt",
@"updated_at", @"updatedAt",
nil];
[topicMapping mapRelationship:@"user" withObjectMapping:userMapping];
RKManagedObjectMapping* postMapping = [RKManagedObjectMapping mappingForClass:[DBPost class]];
postMapping.primaryKeyAttribute = @"postID";
[postMapping mapKeyPathsToAttributes:
@"id",@"postID",
@"topic_id",@"topicID",
@"user_id",@"userID",
@"created_at",@"createdAt",
@"updated_at",@"updatedAt",
@"attachment_content_type", @"attachmentContentType",
@"attachment_file_name", @"attachmentFileName",
@"attachment_file_size", @"attachmentFileSize",
@"attachment_path", @"attachmentPath",
@"attachment_updated_at", @"attachmentUpdatedAt",
@"body", @"body",
nil];
[postMapping mapRelationship:@"user" withObjectMapping:userMapping];
// Register the mappings with the mapping provider. Use of registerMapping:withRootKeyPath:
// configures the mapping provider with both object and serialization mappings for the specified
// keyPath.
[objectManager.mappingProvider registerMapping:userMapping withRootKeyPath:@"user"];
[objectManager.mappingProvider registerMapping:topicMapping withRootKeyPath:@"topic"];
[objectManager.mappingProvider registerMapping:postMapping withRootKeyPath:@"post"];
// Set Up Router
// The router is responsible for generating the appropriate resource path to
// GET/POST/PUT/DELETE an object representation. This prevents your code from
// becoming littered with identical resource paths as you manipulate common
// objects across your application. Note that a single object representation
// can be loaded from any number of resource paths. You can also PUT/POST
// an object to arbitrary paths by configuring the object loader yourself. The
// router is just for configuring the default 'home address' for an object.
[objectManager.router routeClass:[DBUser class] toResourcePath:@"/signup" forMethod:RKRequestMethodPOST];
[objectManager.router routeClass:[DBUser class] toResourcePath:@"/login" forMethod:RKRequestMethodPUT];
[objectManager.router routeClass:[DBTopic class] toResourcePath:@"/topics" forMethod:RKRequestMethodPOST];
[objectManager.router routeClass:[DBTopic class] toResourcePath:@"/topics/(topicID)" forMethod:RKRequestMethodPUT];
[objectManager.router routeClass:[DBTopic class] toResourcePath:@"/topics/(topicID)" forMethod:RKRequestMethodDELETE];
[objectManager.router routeClass:[DBPost class] toResourcePath:@"/topics/(topicID)/posts" forMethod:RKRequestMethodPOST];
[objectManager.router routeClass:[DBPost class] toResourcePath:@"/topics/(topicID)/posts/(postID)" forMethod:RKRequestMethodPUT];
[objectManager.router routeClass:[DBPost class] toResourcePath:@"/topics/(topicID)/posts/(postID)" forMethod:RKRequestMethodDELETE];
// Initialize Three20
TTURLMap* map = [[TTNavigator navigator] URLMap];
[map from:@"db://topics" toViewController:[DBTopicsTableViewController class]];
[map from:@"db://topics/(initWithTopicID:)/posts" toViewController:[DBPostsTableViewController class]];
[map from:@"db://topics/(initWithTopicID:)/edit" toViewController:[DBTopicViewController class]];
[map from:@"db://topics/new" toViewController:[DBTopicViewController class]];
[map from:@"db://posts/(initWithPostID:)" toViewController:[DBPostTableViewController class]];
[map from:@"db://topics/(initWithTopicID:)/posts/new" toViewController:[DBPostTableViewController class]];
[map from:@"db://login" toModalViewController:[DBLoginOrSignUpViewController class]];
[map from:@"*" toViewController:[TTWebController class]];
[[TTURLRequestQueue mainQueue] setMaxContentLength:0]; // Don't limit content length.
// Register for authentication notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setAccessTokenHeaderFromAuthenticationNotification:) name:DBUserDidLoginNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setAccessTokenHeaderFromAuthenticationNotification:) name:DBUserDidLogoutNotification object:nil];
// Initialize authenticated access if we have a logged in current User reference
DBUser* user = [DBUser currentUser];
if ([user isLoggedIn]) {
NSLog(@"Found logged in User record for username '%@' [Access Token: %@]", user.username, user.singleAccessToken);
[objectManager.client setValue:user.singleAccessToken forHTTPHeaderField:kDBAccessTokenHTTPHeaderField];
}
// Fire up the UI!
TTOpenURL(@"db://topics");
[[TTNavigator navigator].window makeKeyAndVisible];
return YES;
}
// Watch for login/logout events and set the Access Token HTTP Header
- (void)setAccessTokenHeaderFromAuthenticationNotification:(NSNotification*)notification {
DBUser* user = (DBUser*) [notification object];
RKObjectManager* objectManager = [RKObjectManager sharedManager];
[objectManager.client setValue:user.singleAccessToken forHTTPHeaderField:kDBAccessTokenHTTPHeaderField];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[window release];
[super dealloc];
}
@end