GithubHelp home page GithubHelp logo

restkit / restkit Goto Github PK

View Code? Open in Web Editor NEW
10.2K 414.0 2.1K 42.47 MB

RestKit is a framework for consuming and modeling RESTful web resources on iOS and OS X

License: Apache License 2.0

Objective-C 98.88% C 0.22% Ruby 0.85% Objective-C++ 0.04% Shell 0.01%

restkit's Introduction

RestKit

Build Status Pod Version Pod Platform Pod License Visit our IRC channel

RestKit is a modern Objective-C framework for implementing RESTful web services clients on iOS and Mac OS X. It provides a powerful object mapping engine that seamlessly integrates with Core Data and a simple set of networking primitives for mapping HTTP requests and responses built on top of AFNetworking. It has an elegant, carefully designed set of APIs that make accessing and modeling RESTful resources feel almost magical. For example, here's how to access the Twitter public timeline and turn the JSON contents into an array of Tweet objects:

@interface RKTweet : NSObject
@property (nonatomic, copy) NSNumber *userID;
@property (nonatomic, copy) NSString *username;
@property (nonatomic, copy) NSString *text;
@end

RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTweet class]];
[mapping addAttributeMappingsFromDictionary:@{
    @"user.name":   @"username",
    @"user.id":     @"userID",
    @"text":        @"text"
}];

RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:nil];
NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/public_timeline.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
    NSLog(@"The public timeline Tweets: %@", [result array]);
} failure:nil];
[operation start];

Getting Started

Overview

RestKit is designed to be modular and each module strives to maintain a minimal set of dependencies across the framework and with the host platform. At the core of library sits the object mapping engine, which is responsible for transforming objects between representations (such as JSON/XML <-> local domain objects).

Object Mapping Fundamentals

The object mapping engine is built on top of the Key-Value Coding (KVC) informal protocol that is foundational to numerous Cocoa technologies such as key-value observing, bindings, and Core Data. Object mappings are expressed as pairs of KVC key paths that specify the source and destination attributes or relationships that are to be transformed.

RestKit leverages the highly dynamic Objective-C runtime to infer the developers desired intent by examining the type of the source and destination properties and performing appropriate type transformations. For example, given a source key path of created_at that identifies a string within a parsed JSON document and a destination key path of creationDate that identifies an NSDate property on a target object, RestKit will transform the date from a string into an NSDate using an NSDateFormatter. Numerous other transformations are provided out of the box and the engine is pluggable to allow the developer to define new transformations or replace an existing transformation with a new implementation.

The mapper fully supports both simple attribute as well as relationship mappings in which nested to-one or to-many child objects are mapped recursively. Through relationship mappings, one object mapping can be added to another to compose aggregate mappings that are capable of processing arbitrarily complex source documents.

Object mapping is a deep topic and is explored in exhaustive detail in the Object Mapping Guide on the wiki.

API Quickstart

RestKit is broken into several modules that cleanly separate the mapping engine from the HTTP and Core Data integrations to provide maximum flexibility. Key classes in each module are highlighted below and each module is hyperlinked to the README.md contained within the source code.

Object Mapping
RKObjectMapping Encapsulates configuration for transforming object representations as expressed by key-value coding keypaths.
RKAttributeMapping Specifies a desired transformation between attributes within an object or entity mapping in terms of a source and destination key path.
RKRelationshipMapping Specifies a desired mapping of a nested to-one or to-many child objects in terms of a source and destination key path and an RKObjectMapping with which to map the attributes of the child object.
RKDynamicMapping Specifies a flexible mapping in which the decision about which RKObjectMapping is to be used to process a given document is deferred to run time.
RKMapperOperation Provides an interface for mapping a deserialized document into a set of local domain objects.
RKMappingOperation An NSOperation that performs a mapping between object representations using an RKObjectMapping.
Networking
RKRequestDescriptor Describes a request that can be sent from the application to a remote web application for a given object type.
RKResponseDescriptor Describes an object mappable response that may be returned from a remote web application in terms of an object mapping, a key path, a SOCKit pattern for matching the URL, and a set of status codes that define the circumstances in which the mapping is appropriate for a given response.
RKObjectParameterization Performs mapping of a given object into an NSDictionary representation suitable for use as the parameters of an HTTP request.
RKObjectRequestOperation An NSOperation that sends an HTTP request and performs object mapping on the parsed response body using the configurations expressed in a set of RKResponseDescriptor objects.
RKResponseMapperOperation An NSOperation that provides support for object mapping an NSHTTPURLResponse using a set of RKResponseDescriptor objects.
RKObjectManager Captures the common patterns for communicating with a RESTful web application over HTTP using object mapping including:
  • Centralizing RKRequestDescriptor and RKResponseDescriptor configurations
  • Describing URL configuration with an RKRouter
  • Serializing objects and sending requests with the serialized representations
  • Sending requests to load remote resources and object mapping the response bodies
  • Building multi-part form requests for objects
RKRouter Generates NSURL objects from a base URL and a set of RKRoute objects describing relative paths used by the application.
RKRoute Describes a single relative path for a given object type and HTTP method, the relationship of an object, or a symbolic name.
Core Data
RKManagedObjectStore Encapsulates Core Data configuration including an NSManagedObjectModel, a NSPersistentStoreCoordinator, and a pair of NSManagedObjectContext objects.
RKEntityMapping Models a mapping for transforming an object representation into a NSManagedObject instance for a given NSEntityDescription.
RKConnectionDescription Describes a mapping for establishing a relationship between Core Data entities using foreign key attributes.
RKManagedObjectRequestOperation An NSOperation subclass that sends an HTTP request and performs object mapping on the parsed response body to create NSManagedObject instances, establishes relationships between objects using RKConnectionDescription objects, and cleans up orphaned objects that no longer exist in the remote backend system.
RKManagedObjectImporter Provides support for bulk mapping of managed objects using RKEntityMapping objects for two use cases:
  1. Bulk importing of parsed documents into an NSPersistentStore.
  2. Generating a seed database for initializing an application's Core Data store with an initial data set upon installation.
Search
RKSearchIndexer Provides support for generating a full-text searchable index within Core Data for string attributes of entities within an application.
RKSearchPredicate Generates an NSCompoundPredicate given a string of text that will search an index built with an RKSearchIndexer across any indexed entity.
Testing
RKMappingTest Provides support for unit testing object mapping configurations given a parsed document and an object or entity mapping. Expectations are configured in terms of expected key path mappings and/or expected transformation results.
RKTestFixture Provides an interface for easily generating test fixture data for unit testing.
RKTestFactory Provides support for creating objects for use in testing.

Examples

Object Request

// GET a single Article from /articles/1234.json and map it into an object
// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}}
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/articles/:articleID" keyPath:@"article" statusCodes:statusCodes];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/1234.json"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
    Article *article = [result firstObject];
	NSLog(@"Mapped the article: %@", article);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
	NSLog(@"Failed with error: %@", [error localizedDescription]);
}];
[operation start];

Managed Object Request

// GET an Article and its Categories from /articles/888.json and map into Core Data entities
// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!", "categories": [{"id": 1, "name": "Core Data"]}
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSError *error = nil;
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (! success) {
    RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
}
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"];
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore) {
    RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
}
[managedObjectStore createManagedObjectContexts];

RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:@"Category" inManagedObjectStore:managedObjectStore];
[categoryMapping addAttributeMappingsFromDictionary:@{ "id": "categoryID", @"name": "name" }];
RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:managedObjectStore];
[articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
[articleMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"categories" toKeyPath:@"categories" withMapping:categoryMapping]];

NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping method:RKRequestMethodAny pathPattern:@"/articles/:articleID" keyPath:@"article" statusCodes:statusCodes];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/888.json"]];
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
operation.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext;
operation.managedObjectCache = managedObjectStore.managedObjectCache;
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
  Article *article = [result firstObject];
	NSLog(@"Mapped the article: %@", article);
	NSLog(@"Mapped the category: %@", [article.categories anyObject]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
	NSLog(@"Failed with error: %@", [error localizedDescription]);
}];
NSOperationQueue *operationQueue = [NSOperationQueue new];
[operationQueue addOperation:operation];

Map a Client Error Response to an NSError

// GET /articles/error.json returns a 422 (Unprocessable Entity)
// JSON looks like {"errors": "Some Error Has Occurred"}

// You can map errors to any class, but `RKErrorMessage` is included for free
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
// The entire value at the source key path containing the errors maps to the message
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]];

NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError);
// Any response in the 4xx status code range with an "errors" key path uses this mapping
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:statusCodes];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/error.json"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[errorDescriptor]];
[operation setCompletionBlockWithSuccess:nil failure:^(RKObjectRequestOperation *operation, NSError *error) {
    // The `description` method of the class the error is mapped to is used to construct the value of the localizedDescription
	NSLog(@"Loaded this error: %@", [error localizedDescription]);

    // You can access the model object used to construct the `NSError` via the `userInfo`
    RKErrorMessage *errorMessage =  [[error.userInfo objectForKey:RKObjectMapperErrorObjectsKey] firstObject];
}];

Centralize Configuration in an Object Manager

// Set up Article and Error Response Descriptors
// Successful JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}}
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/articles" keyPath:@"article" statusCodes:statusCodes];

// Error JSON looks like {"errors": "Some Error Has Occurred"}
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
// The entire value at the source key path containing the errors maps to the message
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError);
// Any response in the 4xx status code range with an "errors" key path uses this mapping
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:statusCodes];

// Add our descriptors to the manager
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
[manager addResponseDescriptorsFromArray:@[ articleDescriptor, errorDescriptor ]];

[manager getObjectsAtPath:@"/articles/555.json" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
	// Handled with articleDescriptor
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
	// Transport error or server error handled by errorDescriptor
}];

Configure Core Data Integration with the Object Manager

NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (! success) {
    RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
}
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"];
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore) {
    RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
}
[managedObjectStore createManagedObjectContexts];

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
manager.managedObjectStore = managedObjectStore;

Load a Collection of Objects at a Path

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
[manager getObjectsAtPath:@"/articles" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];

Manage a Queue of Object Request Operations

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/1234.json"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];

[manager enqueueObjectRequestOperation:operation];
[manager cancelAllObjectRequestOperationsWithMethod:RKRequestMethodANY matchingPathPattern:@"/articles/:articleID\\.json"];

POST, PATCH, and DELETE an Object

RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[Article class]];
[responseMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodAny pathPattern:@"/articles" keyPath:@"article" statusCodes:statusCodes];

RKObjectMapping *requestMapping = [RKObjectMapping requestMapping]; // objectClass == NSMutableDictionary
[requestMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];

// For any object of class Article, serialize into an NSMutableDictionary using the given mapping and nest
// under the 'article' key path
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[Article class] rootKeyPath:@"article" method:RKRequestMethodAny];

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];
[manager addRequestDescriptor:requestDescriptor];
[manager addResponseDescriptor:articleDescriptor];

Article *article = [Article new];
article.title = @"Introduction to RestKit";
article.body = @"This is some text.";
article.author = @"Blake";

// POST to create
[manager postObject:article path:@"/articles" parameters:nil success:nil failure:nil];

// PATCH to update
article.body = @"New Body";
[manager patchObject:article path:@"/articles/1234" parameters:nil success:nil failure:nil];

// DELETE to destroy
[manager deleteObject:article path:@"/articles/1234" parameters:nil success:nil failure:nil];

Configure Logging

// Log all HTTP traffic with request and response bodies
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);

// Log debugging info about Core Data
RKLogConfigureByName("RestKit/CoreData", RKLogLevelDebug);

// Raise logging for a block
RKLogWithLevelWhileExecutingBlock(RKLogLevelTrace, ^{
    // Do something that generates logs
});

Configure Routing

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];

// Class Routing
[manager.router.routeSet addRoute:[RKRoute routeWithClass:[GGSegment class] pathPattern:@"/segments/:segmentID\\.json" method:RKRequestMethodGET]];

// Relationship Routing
[manager.router.routeSet addRoute:[RKRoute routeWithRelationshipName:@"amenities" objectClass:[GGAirport class] pathPattern:@"/airports/:airportID/amenities.json" method:RKRequestMethodGET]];

// Named Routes
[manager.router.routeSet addRoute:[RKRoute routeWithName:@"thumbs_down_review" resourcePathPattern:@"/reviews/:reviewID/thumbs_down" method:RKRequestMethodPOST]];

POST an Object with a File Attachment

Article *article = [Article new];
UIImage *image = [UIImage imageNamed:@"some_image.png"];

// Serialize the Article attributes then attach a file
NSMutableURLRequest *request = [[RKObjectManager sharedManager] multipartFormRequestWithObject:article method:RKRequestMethodPOST path:nil parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    [formData appendPartWithFileData:UIImagePNGRepresentation(image)
                                name:@"article[image]"
                            fileName:@"photo.png"
                            mimeType:@"image/png"];
}];

RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] objectRequestOperationWithRequest:request success:nil failure:nil];
[[RKObjectManager sharedManager] enqueueObjectRequestOperation:operation]; // NOTE: Must be enqueued rather than started

Enqueue a Batch of Object Request Operations

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]];

Airport *jfk = [Airport new];
jfk.code = @"jfk";
Airport *lga = [Airport new];
lga.code = @"lga";
Airport *rdu = [Airport new];
rdu.code = @"rdu";

// Enqueue a GET for '/airports/jfk/weather', '/airports/lga/weather', '/airports/rdu/weather'
RKRoute *route = [RKRoute routeWithName:@"airport_weather" resourcePathPattern:@"/airports/:code/weather" method:RKRequestMethodGET];

[manager enqueueBatchOfObjectRequestOperationsWithRoute:route
                                                objects:@[ jfk, lga, rdu]
                                               progress:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
                                                   NSLog(@"Finished %d operations", numberOfFinishedOperations);
                                               } completion:^ (NSArray *operations) {
                                                   NSLog(@"All Weather Reports Loaded!");
                                               }];

Generate a Seed Database

NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSError *error = nil;
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (! success) {
    RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
}
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"];
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore) {
    RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
}
[managedObjectStore createManagedObjectContexts];

RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:managedObjectStore];
[articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];

NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"MySeedDatabase.sqlite"];
RKManagedObjectImporter *importer = [[RKManagedObjectImporter alloc] initWithManagedObjectModel:managedObjectStore.managedObjectModel storePath:seedPath];

// Import the files "articles.json" from the Main Bundle using our RKEntityMapping
// JSON looks like {"articles": [ {"title": "Article 1", "body": "Text", "author": "Blake" ]}
NSError *error;
NSBundle *mainBundle = [NSBundle mainBundle];
[importer importObjectsFromItemAtPath:[mainBundle pathForResource:@"articles" ofType:@"json"]
                          withMapping:articleMapping
                              keyPath:@"articles"
                                error:&error];

BOOL success = [importer finishImporting:&error];
if (success) {
	[importer logSeedingInfo];
}

Index and Search an Entity

NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSError *error = nil;
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (! success) {
    RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error);
}
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"];
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
if (! persistentStore) {
    RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);
}
[managedObjectStore createManagedObjectContexts];
[managedObjectStore addSearchIndexingToEntityForName:@"Article" onAttributes:@[ @"title", @"body" ]];
[managedObjectStore addInMemoryPersistentStore:nil];
[managedObjectStore createManagedObjectContexts];
[managedObjectStore startIndexingPersistentStoreManagedObjectContext];

Article *article1 = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
article1.title = @"First Article";
article1.body = "This should match search";

Article *article2 = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
article2.title = @"Second Article";
article2.body = "Does not";

BOOL success = [managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:nil];

RKSearchPredicate *predicate = [RKSearchPredicate searchPredicateWithText:@"Match" type:NSAndPredicateType];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"];
fetchRequest.predicate = predicate;

// Contains article1 due to body text containing 'match'
NSArray *matches = [managedObjectStore.mainQueueManagedObjectContext executeFetchRequest:fetchRequest error:nil];
NSLog(@"Found the matching articles: %@", matches);

Unit Test a Mapping

// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}}
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]];
[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]];

NSDictionary *article = @{ @"article": @{ @"title": @"My Title", @"body": @"The article body", @"author": @"Blake" } };
RKMappingTest *mappingTest = [[RKMappingTest alloc] initWithMapping:mapping sourceObject:article destinationObject:nil];

[mappingTest expectMappingFromKeyPath:@"title" toKeyPath:@"title" value:@"My Title"];
[mappingTest performMapping];
[mappingTest verify];

Requirements

RestKit requires iOS 8.0 and above or Mac OS X 10.9 and above.

Several third-party open source libraries are used within RestKit, including:

  1. AFNetworking - Networking Support
  2. LibComponentLogging - Logging Support
  3. SOCKit - String <-> Object Coding
  4. iso8601parser - Support for parsing and generating ISO-8601 dates

The following Cocoa frameworks must be linked into the application target for proper compilation:

  1. CFNetwork.framework on iOS
  2. CoreData.framework
  3. Security.framework
  4. MobileCoreServices.framework on iOS or CoreServices.framework on OS X

And the following linker flags must be set:

  1. -ObjC
  2. -all_load

ARC

As of version 0.20.0, RestKit has migrated the entire codebase to ARC.

If you are including the RestKit sources directly into a project that does not yet use Automatic Reference Counting, you will need to set the -fobjc-arc compiler flag on all of the RestKit source files. To do this in Xcode, go to your active target and select the "Build Phases" tab. Now select all RestKit source files, press Enter, insert -fobjc-arc and then "Done" to enable ARC for RestKit.

Serialization Formats

RestKit provides a pluggable interface for handling arbitrary serialization formats via the RKSerialization protocol and the RKMIMETypeSerialization class. Out of the box, RestKit supports handling the JSON format for serializing and deserializing object representations via the NSJSONSerialization class.

Additional Serializations

Support for additional formats and alternate serialization backends is provided via external modules that can be added to the project. Currently the following serialization implementations are available for use:

  • JSONKit
  • SBJSON
  • YAJL
  • NextiveJson
  • XMLReader + XMLWriter

Installation

The recommended approach for installing RestKit is via the CocoaPods package manager, as it provides flexible dependency management and dead simple installation. For best results, it is recommended that you install via CocoaPods >= 0.19.1 using Git >= 1.8.0 installed via Homebrew.

via CocoaPods

Install CocoaPods if not already available:

$ [sudo] gem install cocoapods
$ pod setup

Change to the directory of your Xcode project, and Create and Edit your Podfile and add RestKit:

$ cd /path/to/MyProject
$ touch Podfile
$ edit Podfile
target "YOUR PROJECT" do
	platform :ios, '7.0'
	# Or platform :osx, '10.7'
	pod 'RestKit', '~> 0.24.0'
end
# Testing and Search are optional components
pod 'RestKit/Testing', '~> 0.24.0'
pod 'RestKit/Search',  '~> 0.24.0'

Install into your project:

$ pod install

Open your project in Xcode from the .xcworkspace file (not the usual project file)

$ open MyProject.xcworkspace

Please note that if your installation fails, it may be because you are installing with a version of Git lower than CocoaPods is expecting. Please ensure that you are running Git >= 1.8.0 by executing git --version. You can get a full picture of the installation details by executing pod install --verbose.

From a Release Package or as a Git submodule

Detailed installation instructions are available in the Visual Install Guide on the Wiki.

Using RestKit in a Swift Project

Install RestKit using one of the above methods. Then add @import RestKit; (if RestKit is built as a dynamic framework) or #import <RestKit/RestKit.h> (if RestKit is built as a static library) into the bridging header for your Swift project. To enable the Core Data functionality in RestKit, add @import CoreData; into your bridging header before you import RestKit.

License

RestKit is licensed under the terms of the Apache License, version 2.0. Please see the LICENSE file for full details.

Credits

RestKit is brought to you by Blake Watters and the RestKit team.

Support is provided by the following organizations:

restkit's People

Contributors

0xced avatar adlai-holler avatar aharren avatar alexdenisov avatar bimusiek avatar blakewatters avatar br-tyler-milner avatar cammm avatar carllindberg avatar cryptojuice avatar dfowj avatar diederich avatar dmishe avatar dulacp avatar grgcombs avatar jawwad avatar kurry avatar maarek avatar mcfedr avatar parkerboundy avatar pashields avatar rayfix avatar segiddins avatar seletz avatar sixten avatar spenrose avatar timbodeit avatar valeriomazzeo avatar vilinskiy-playdayteam avatar vkryukov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

restkit's Issues

Nested object types must be explicitly registered

Example JSON:


{
  "field1" : "value1",
  "object_field1" : {
   "field2": "value2"
  },
  "object_array" : [
  {"field3":"value3"}
  ]
}

In this case the type of "object_field1" and the type of the objects in "object_array" need to be explicitly registered with registerClass:forElementNamed:, otherwise these types won't be resolved and the instance variables won't be set.

RestKit version: 0.9.1.1
Xcode version: 4.0.1/4A1006

deletePersistentStoreReseedUsingSeedDatabaseName:(NSString*)seedFile

I'd like to propose an addition to RKManagedObjectStore that would allow for a deletion and also reseeding of the store. Right now when you delete, it automatically assumes you don't have a seed. Basically the new function has only one change beyond the normal store deletion.

if (seedFile)
    [self createStoreIfNecessaryUsingSeedDatabase:seedFile];
[self createPersistentStoreCoordinator];

Mapping to Registered Types Fails when Object Class Supplied to Object Loader

From the mailing list:

On Sat, Apr 23, 2011 at 10:05 AM, Jon Phillips [email protected] wrote:
OK, final email ... sorry for the bother, but if it's helpful to anyone else.

I thought I was doing good things in my loadObjectsAtResourcePath call
by including the class to map it to. But I didn't need it because my
json includes the key that is the class. Because I included the class,
the elements dictionary included the class name key, which messed
stuff up.

Upshot = if you're outputting standard JSON from Rails, RestKit is
smart enough to figure out the class you're mapping and you don't have
to tell it. In fact, apparently, you shouldn't tell it?

RKObjectLoader sends RKRequestDidLoadResponseNotification twice

The call to [super didFinishLoad:response] in the (void)didFinishLoad:(RKResponse*)response implementation on RKObjectLoader results in the RKRequestDidLoadResponseNotification being sent twice for a single RKObjectLoader. This has a side effect of reducing _totalLoading in RKRequestQueue twice for a single request, and thus messing up the enforcement of the RKRequestQueue's max loading count.

It seems that removing to call to super in RKObjectLoader's void)didFinishLoad:(RKResponse*)response method addresses the issue, although I've only tested this fix in a limited number of cases.

App build with RestKit and Three20 fails on clean Build directory

When building an app with RestKit and the optional RestKit Three20 library, the build fails when building from a clean RestKit Build/ directory. Build failures in the app cite the absence of <RestKit/Three20/Three20.h>, presumably because the Copy Headers build task(s) on the RestKit target execute(s) prior to the Three20 component being built via inclusion in the app directly. This can likely be solved by adding the Copy Headers build task(s) as part of the RestKit Three20 library.

RKRequestTTModel does not use core data as authoritative data source

If a programmer is using core data then it should be the authoritative data store for the application.

RKRequestTTModel modelsDidLoad:(NSArray*)models sets the underlying model to the array of objects that has just been received. Instead it should check to see if there is a core data backing and use it if it is available.

This allows the programmer to include their own rules for updating local objects (ie locally created objects or other synchronization strategies)

Something like the following should work:

- (void)modelsDidLoad:(NSArray*)models {
    RKManagedObjectStore* store = [RKObjectManager sharedManager].objectStore;
    NSArray* fetchRequests = nil;
    NSArray* allKnownObjects = nil;
    if (store.managedObjectCache) {
        fetchRequests = [store.managedObjectCache fetchRequestsForResourcePath:self.resourcePath];
        allKnownObjects = [RKManagedObject objectsWithFetchRequests:fetchRequests];
    } else {
        allKnownObjects = models;
    }


    [_objects release];
    _objects = nil;

    _objects = [allKnownObjects retain];
    _isLoaded = YES;

    [self didFinishLoad];
 }

Has Many Mapping

Just wondering how the has many relationship works. Looking through the source I see this
@"[email protected]_many", @"hasMany",

Lets say my managed object models are:
Photo
User

Photo can be "liked" by many users. So liked is the JSON element which contains many users.

Delete Request Passing Paramaters

When using deleteObject the object manager sends paramaters with the request. I believe this causes rails to raise an InvalidAuthenticityToken error - at least on my development server running Rails 3.0.3.

Are there situations where you would want to pass paramaters with a DELETE request?

Crash in RKObjectMapper element comparison (more error handling)

When some objects in JSON have a null property and other objects have a string for that property, they complexify the mapping and our comparison here breaks trying to compare an NSNumber to an NSString ([NSNumber isEqualToString:] unrecognized selector). This addition will evaluate the class and force a property setting if its' different.

diff ./RKObjectMapper.m ../0.9/RKObjectMapper.m
316,323d315
<       if (![currentValue isKindOfClass:[propertyValue class]])
<       {
<           if (![currentValue isEqual:propertyValue] || ![[currentValue description] isEqualToString:[propertyValue description]]) {
<               [model setValue:propertyValue forKey:propertyName];
<               return;
<           }
<           
<       }
389c381
<         if (!modelClass || [modelClass isKindOfClass: [NSNull class]]) {

---
>         if ([modelClass isKindOfClass: [NSNull class]]) {

Ensure no nil values are mapped by specifying the object class

From the mailing list:


My object properties were also all (null) when I provided an
objectClass to loadObjectsAtResourcePath, but worked fine without it.
This is when I registered the class with the RKObjectMapper. If I
didn't register the class with the ObjectMapper and passed in the
class for objectClass, it still gave me nil values.

On Apr 23, 3:28 pm, Blake Watters <[email protected]> wrote:
> Hi Jon -
>
> Glad that you got things sorted out. The mapping really shouldn't fail out
> if you supply the target class for a registered object. I've opened an issue
> in Github to cover that edge.
>
> On Sat, Apr 23, 2011 at 10:05 AM, Jon Phillips
> <[email protected]>wrote:
>
> > OK, final email ... sorry for the bother, but if it's helpful to
> > anyone else.
>
> > I thought I was doing good things in my loadObjectsAtResourcePath call
> > by including the class to map it to. But I didn't need it because my
> > json includes the key that is the class. Because I included the class,
> > the elements dictionary included the class name key, which messed
> > stuff up.
>
> > Upshot = if you're outputting standard JSON from Rails, RestKit is
> > smart enough to figure out the class you're mapping and you don't have
> > to tell it.  In fact, apparently, you shouldn't tell it?
>
>  *Blake Watters*
> Two Toasters | CTO
> [email protected]
> (919) 926-8537

Implement support for the HATEOAS constraint

According to Roy Fielding:

"REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state." [1]

The first three are incorporated by RestKit (although it seems to couple REST to HTTP), but the latter one is missing. Namely, there is no built-in support for links representing possible state transitions or resource relationships, but rather the related entities need to be embedded or to be asked for with isolated queries based on id's.

"...if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period. " [2]

I think most people entirely miss the HATEOAS constraint, because most frameworks neither enforce, nor support the usage of them. Changing this for RestKit could improve the quality of and finally enable REST for wannabe-rest-systems.

Examples Don't Work

Running both example projects I receive the following error:

2010-12-28 10:37:05.404 RKTwitter[20942:207] Hit error: Error
Domain=com.twotoasters.RestKit.ErrorDomain Code=2 "The client is
unable to contact the resource at http://twitter.com/status/user_timeline/twotoasters.json"
UserInfo=0x9218d90 {NSLocalizedDescription=The client is unable to
contact the resource at http://twitter.com/status/user_timeline/twotoasters.json}

This crashes the app. The json is available via web browser so it isn't a connection issue. Any ideas?

Also the examples use globalManager rather than sharedManager.

Merge RKRequestQueue

Picking up Jeff Arena's work from #41. This implements a cache that is capable of responding with previously loaded payloads and headers.

Create RKCatalog Example

Create an integrated example application pulling together the code samples from the Advanced MobileTuts article:

  • RKParamsExample
  • RKRequestQueueExample
  • RKReachabilityExample
  • RKBackgroundRequestExample
  • RKAdvancedMappingExample (Better Name??) KeyValueMappingExample???
  • RKRelationshipMappingExample
  • RKCoreDataExample
  • RKRailsExample

Exception in RKManagedObjectStore's deletePersistantStore

Hi,

In deletePersistantStore you are doing this:

NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary];
[threadDictionary setObject:nil forKey:kRKManagedObjectContextKey];

However dictionaries don't allow you to set nil for a key. You should change this to:

NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary];
[threadDictionary removeObjectForKey:kRKManagedObjectContextKey];

From the NSMutableDictionary documentation:

Raises an NSInvalidArgumentException if aKey or anObject is nil. If you need to represent a nil value in the dictionary, use NSNull.

RKObjectMapper does not support NSURL

Problem

If the model object has a NSURL property that is mapped with RestKit, the RKObjectMapper will not attempt to turn the JSON string into an NSURL object.

Workaround

To work around this problem, we had to create a KVC compliant NSString property that does the NSURL conversion for us. RestKit will set the string property, and our custom setter creates and sets the actual URL property. This is less than ideal

Suggested Fixes

  • Factor out the type conversion in RKObjectMapper into a method that subclasses can easily override. We could have made a custom subclass of the object mapper and included our URL logic there.
  • Make the type conversion more object-oriented and allow third-party code to register new "converters." This is more complicated but may be more correct.

RKSpecResponseLoader Returns Control Too Soon

When testing using the RKSpecResponseLoader, if you are using an object loader control is returned to the test case when didLoadResponse: or didFailLoadWithError: is invoked by the framework.

We need to inspect the type of the request and defer returning control if this is an object loader.

Support Automatic Submission Tracking

A lot of people would like to be able to automatically track object status (i.e. does it exist local only or on the server). We should architect this into the framework:

Hi there,

Thus far I've got my application working more or less correctly using
Restkit. I've followed some of the examples provided.

In the example given by the discussion app the following occurs. An
instance of a post object is created, assigned some data and then
eventually posted. I.e. Something to the effect of:

       DBPost *post = [DBPost object];
       post.topicID = topic.topicID;
       post.body = bodyTextEditor.text;
       [[RKObjectManager sharedManager] postObject:post delegate:self];

Now should an error occur during transmission we end up with a post
that is stored locally in sqlite but not on the server.

What is the best approach to handle this?

Should all models that get transmitted require some sort of flag to
indicate whether or not they have been sent?  (This could then be
combined with some routine to pick up "unsent" data and resubmit it.)

I've also read some mention of using temporary managedObjectContexts.
Is this a better alternative?

What do you suggest to solve these kinds of problems?

Any help on this would be fantastic.

Thanks in advance,
Matt

Add Support for Encoding resourcePaths to Avoid Crashes with UTF-8 Characters

Hey guys,

Today I was working with "/places.json?category=Automóviles" as
resourcePath and got EXEC_BAD_ACCESS at RKURL.m

    - (id)initWithBaseURLString:(NSString*)baseURLString resourcePath:
    (NSString*)resourcePath

    and found out that NSURL cannot be initialized with non-ASCII
    characters, so I fixed this using NSUTF8StringEncoding to get a URL
    like this "/places.json?category=Autom%C3%B3viles"

    Here is my code:

    - (id)initWithBaseURLString:(NSString*)baseURLString resourcePath:
    (NSString*)resourcePath {
       NSString *completeURL = [NSString stringWithFormat:@"%@%@",
    baseURLString, resourcePath];

       // If some condition
       completeURL = [completeURL
    stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

           if ((self = [self initWithString:completeURL])) {
                   _baseURLString = [baseURLString copy];
                   _resourcePath = [resourcePath copy];
           }

           return self;
    }

Do you think we should merge this?

JSONKit Serialization Fails when NSDate Objects are Present

Ok. So I have narrowed it down to the following:

I have subclassed RKDynamicRouter so that I can send my POST requests
as JSON and not URL parameters. This is the method I have overridden
in the router subclass:

  • (NSObject)serializationForObject:
    (NSObject
    )object method:(RKRequestMethod)method {
    return [RKJSONSerialization JSONSerializationWithObject:[object
    propertiesForSerialization]];
    }

[object propertiesForSerializiation] had the dictionary with all the
correct properties, but the JSONSerializationWithObject: method
returns an empty HTTPBody object. So I did a bit more digging and
discovered the culprit is in this bit of code:

  • (NSString*)stringFromObject:(id)object {
    return [object JSONString];
    }

It appears JSONKit is just returning a nil string when we call
JSONString on it. I've used JSONKit a bit for a project before, and I
know it freaks out if it receives objects like NSDate. So I nilled out
the NSDate objects on my object, and bingo, the request body had data
in it.

So my question now is, what is the best way around the date problem.
My app is a scheduling app, so dates are pretty critical. I could
possibly put methods on the managed object that return a formatted
string for a date and map those rather than the dates themselves. The
other solution would be to use a different JSON library to JSONKit
that supports date objects, if this is the best solution, which should
I use? I am leaning towards the former solution rather than the latter
as it gives me the added benefit of having control over how my dates
are formatted in the request and being able to deal with different
date formats in responses.

Clarify setup documentation XCode 4

Just setup RestKit in my XCode 4 project. Have a few gotchas that I think you need to add to the documentation;

  1. I had to add CoreData.framework even if it said it was optional. Yes I had libRestKitCoreData.a in there also. My suggestion is to put those to next to each other so it is very clear that if you add one, you need to add the other.
  2. I had to restart XCode in order for the RestKit.xcodeproj to show up as it should with an indented list.

Other than that - thanks for a great lib. Excited to try it out.

Martin

Support Supplying Temporary Object Contexts

I have a UI that lets a user create a new object. They can hit Save to
upload the object or Cancel to abandon it. I'm used to the pattern
where you create a temporary managed object context for this purpose.
If the user cancels, you simply get rid of the temporary context and
the object is forgotten. However, I can't seem to do this in RestKit.
If I create a temporary context, RestKit is unaware of that context
and doesn't save my object. The offending code is in
RKManagedObjectLoader handleTargetObject. It performs a save, but on
the default context, not my temporary one. My object actually gets
uploaded, but processLoadModelsInBackground doesn't catch the changes
because my object still has a temporary object ID (since its context
didn't get saved).

I use the same logic for editing an existing object. However, that
path seems to work OK. I guess because even though my temporary
context doesn't get saved, the existing object has a permanent object
ID and hence processLoadModelsInBackground is able to find the object
and update it.

Is there a better pattern for doing this?


Mark -

In most of my UI's we've just had the state set on controls in the UI rather than heading back to the model, save causes the state to be read from the controls, set on the object, and then the put/postObject call is dispatched. Cancel button just pops the view so no write-through occurs. I suspect that what you are doing could be easily supported if we provide a mechanism for supplying the object loader with a managed object context from the main application. It may be enough just to expose a read/write property for the object context and initialize it to a thread-local one if its nil.

  • Blake

RKObjectLoader in ObjectMapping depends on Core Data

Readme says that Core Data framework is optional and only required if you use the Core Data related part of RestKit, but RKObjectLoader class in ObjectMapping module imports RKManagedObjectStore from the CoreData module and Core Data framework itself.

RKObjectMapper removes relationship objects if no relationship property sent in JSON

In the 0.9 branch around line 390, RKObjectMapper attempts to update or create the modelClass from a dictionary of childElements in relationshipElements.

In the case that relationshipElements does not exist, i.e that relationship property wasn't passed in the JSON yet it still exists, relationshipElements will be nil, children will be an empty NSSet or NSArray, and [object setValue:children forKey:propertyName] on line 406 will destroy any currently associated objects.

I believe this is fixed on the core-data-cleanup branch but has not been merged in, but please let me know if my assumptions are incorrect.

RKJSONSerialization depends on JSON framework

The readme says that it should be possible to choose either YAJL or SBJSON (JSON Framework). However, RKJSONSerialization explicitly includes "NSObject+SBJSON.h" and calls a method "JSONRepresentation" declared there, so it's not possible to compile this class against YAJL only.

Remote Services Expect a File Name to be Set

RKParamsAttachment does not currently initialize a filename for attached parameters. This causes issues as remote services expect one to be set. Initialize it to an empty string instead of nil.

Make it Easier to Specify Request Body

Simplify this:

NSString* JSON = @"whatever";
RKRequest* request = [[RKRequest alloc] initWithURL:URL];
request.method = RKRequestMethodPOST;
[request.URLRequest setHTTPBody:[JSON dataUsingEncoding: NSASCIIStringEncoding]];
[request send];

RKManagedObjectStore should allow for user-supplied NSManagedObjectModel

My project can't have a store that originates with a "mergedModelFromBundles" ... I've actually got two different active models that have to remain separate. So, to accommodate this, I wind up using something like this to retain a passed-in model instead of whipping up one inside the framework.

  • (id)initWithStoreFilename:(NSString*)storeFilename model:(NSManagedObjectModel *)storeModel;

Object Mapper 2.0

Epic story ticket for the object mapper 2.0 work. This update will simplify and expand the capabilities of the object mapping layer.

Mapping Fails when Given a Target Object Class and Array of Registered Element Subdictionaries

From the mailing list:

    OK here is the setup:

    Item model object (IIContentObject.h is a RKManagedObject subclass
    that deals with the update dates etc)
    ==============
    #import "IIContentObject.h"

    @interface Item : IIContentObject {
    @private
    }
    @property (nonatomic, retain) NSNumber * parentID;
    @property (nonatomic, retain) NSNumber * categoryID;
    @property (nonatomic, retain) NSNumber * itemID;
    @property (nonatomic, retain) NSString * itemName;
    @property (nonatomic, retain) NSString * imageBaseDir;
    @property (nonatomic, retain) NSString * imageName;

    @end

    #import "Item.h"


    @implementation Item
    @dynamic parentID;
    @dynamic categoryID;
    @dynamic itemID;
    @dynamic itemName;
    @dynamic imageBaseDir;
    @dynamic imageName;

    + (NSDictionary*)elementToPropertyMappings {
           return [NSDictionary dictionaryWithKeysAndObjects:
               @"id", @"itemID",
               @"name", @"itemName",
               @"parent_id", @"parentID",
               @"category_id", @"categoryID",
               @"imageBaseDir", @"imageBaseDir",
               @"imageName", @"imageName",
               @"created_at", @"createdAt",
               @"updated_at", @"updatedAt",
               nil];
    }

    + (NSString*)primaryKeyProperty {
           return @"itemID";
    }
    @end

    App delegate
    ==========
    // Initialize RestKit
    RKObjectManager* objectManager = [RKObjectManager
    objectManagerWithBaseURL:@"http://localhost:3000"];
    RKObjectMapper* mapper = objectManager.mapper;

    // Add our element to object mappings
    [mapper registerClass:[Item class] forElementNamed:@"item"];


    RKRailsRouter* router = [[[RKRailsRouter alloc] init] autorelease];

    [router setModelName:@"item" forClass:[Item class]];
    [router routeClass:[Item class] toResourcePath:@"/items"
    forMethod:RKRequestMethodPOST];
    [router routeClass:[Item class] toResourcePath:@"/items/(itemID)"
    forMethod:RKRequestMethodPUT];
    [router routeClass:[Item class] toResourcePath:@"/items/(itemID)"
    forMethod:RKRequestMethodDELETE];

    objectManager.router = router;

    In my view I call
    ============

    - (void)loadItemData {
           RKObjectManager* objectManager = [RKObjectManager sharedManager];
           [[objectManager loadObjectsAtResourcePath:@"/items.json" objectClass:
    [Item class] delegate:self] retain];
    }

    =======================
    I am probably missing something here and not using the routing
    correctly!
    Every time I call the load item data I end up with blank rows inserted
    into core data. JSON is as follows:

    [{"item":{"category_id":null,"created_at":"2011-04-11T09:32:25Z","id":
    1,"imageBaseDir":"","imageName":"","name":"Inspiration","parent_id":null,"updated_at":"2011-04-11T09:32:25Z"}}]

    Can someone push me in the right direction please.

    Thanks

    David

Setup instructions not correct?

I had to check the libRestKitCoreData.a file to get things to compile successfully. That is, it is apparently not optional. The error is:

"_OBJC_CLASS_$_RKManagedObject", referenced from:
objc-class-ref-to-RKManagedObject in libRestKitObjectMapping.a(RKObjectLoader.o)
objc-class-ref-to-RKManagedObject in libRestKitObjectMapping.a(RKObjectMapper.o)
ld: symbol(s) not found

Enable Support for Changing resourcePath for object loaders with a target object

Use case is that you want to support multiple target resource paths with the same HTTP verb:

In my application, I have a User model that contains both information
about the user and his or her login information. I'm using Authlogic
(Rails backend) for user signup and login (done pretty much the same
way as the DiscussionBoard example). I want to allow the user to
update his or her information on the service as well (e.g. contact
information, credentials), which is tied to the User model. Therefore,
it needs to handle two different PUT requests to two different
resource paths on a Rails server (one for /login and one for /users/
<id>). The RKRailsRouter allows for only one resource path for each
method (makes sense), so I'm just wondering, is there a way around
this in RestKit? Is there a way I can have the RKObjectManager
"putObject" to a specific resource path?

Basically, imagine my scenario is the DiscussionBoard example, but you
want to give the user the ability to update their username, email,
password, or any other information.

RKTTRequestModel does not properly handle bad responses

When a service responds with bad data (or a bad response code) RestKit properly handles the error until it invokes "didFailLoadWithError:" on the RKTTRequestModel in -[RKRequestModel objectLoaderDidLoadUnexpectedResponse:]. RestKit passes a nil error which ultimately is ignored by the Three20 Framework (improperly or not) which means the application is kept in a indeterminate "loading state"

The fix for this would be to provide an error to didFailLoadWirhError:.

Improperly converts time sent in UTC

RestKit currently has special handling (even though the date is ISO 8601) for converting serialized UTC dates from rails. A rails serialized date is interpolated as a date in the local timezone. E.g., if "2010-11-16T21:11:33Z" is sent it will be parsed as "2010-11-16 21:11:33 -0500" for those in the eastern timezone. RestKit copes with this by explicitly subtracting the offset (-18000 seconds in eastern) to get the correct time.

This does not work when a date is serialized as a string in which the nsdateformatter can recognize the timezone offset. "2010-11-16 21:11:33 -0000" (y-M-d HH:mm:ss Z), for instance, would be properly handled by NSDateFormatter. However, RestKit still converts this time even though it properly interpolated which will automatically offset your time incorrectly.

The best solution may be to explicitly check for that permutation of the ISO 8601 format and switch on it. Otherwise it should only support the rails serialization format so that people do not falsely assume it can handle other date formats.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.