IOS (XCode) Programming Homework help
IT4781-U02A1-AlexBenavides/.DS_Store
__MACOSX/IT4781-U02A1-AlexBenavides/._.DS_Store
IT4781-U02A1-AlexBenavides/Default.png
__MACOSX/IT4781-U02A1-AlexBenavides/._Default.png
IT4781-U02A1-AlexBenavides/[email protected]
__MACOSX/IT4781-U02A1-AlexBenavides/[email protected]
IT4781-U02A1-AlexBenavides/Icon_57x57.png
__MACOSX/IT4781-U02A1-AlexBenavides/._Icon_57x57.png
IT4781-U02A1-AlexBenavides/StoreLocator/.DS_Store
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/._.DS_Store
IT4781-U02A1-AlexBenavides/StoreLocator/AppDelegate/.DS_Store
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/AppDelegate/._.DS_Store
IT4781-U02A1-AlexBenavides/StoreLocator/AppDelegate/SHAppDelegate.h
// // SHAppDelegate.h // StoreLocator // // Created by Fredrick Gabelmann on 8/17/12. // Copyright (c) 2012 Smart Homes. All rights reserved. // #import <UIKit/UIKit.h> @interface SHAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/AppDelegate/._SHAppDelegate.h
IT4781-U02A1-AlexBenavides/StoreLocator/AppDelegate/SHAppDelegate.m
// // SHAppDelegate.m // StoreLocator // // Created by Fredrick Gabelmann on 8/17/12. // Copyright (c) 2012 Smart Homes. All rights reserved. // #import "SHAppDelegate.h" #import "SHNetworkDelegate.h" @implementation SHAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Configure Network Layer [[SHNetworkDelegate sharedDelegate] configureNetworkLayer]; // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/AppDelegate/._SHAppDelegate.m
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/._AppDelegate
IT4781-U02A1-AlexBenavides/StoreLocator/Controllers/.DS_Store
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Controllers/._.DS_Store
IT4781-U02A1-AlexBenavides/StoreLocator/Controllers/SHViewController.h
// // SHViewController.h // StoreLocator // // Created by Fredrick Gabelmann on 8/17/12. // Copyright (c) 2012 Smart Homes. All rights reserved. // #import <UIKit/UIKit.h> @interface SHViewController : UIViewController @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Controllers/._SHViewController.h
IT4781-U02A1-AlexBenavides/StoreLocator/Controllers/SHViewController.m
// // SHViewController.m // StoreLocator // // Created by Fredrick Gabelmann on 8/17/12. // Copyright (c) 2012 Smart Homes. All rights reserved. // #import "SHViewController.h" @interface SHViewController () @end @implementation SHViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); } else { return YES; } } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Controllers/._SHViewController.m
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/._Controllers
IT4781-U02A1-AlexBenavides/StoreLocator/Data Model/Store.h
// // Profile.h // sartorii // // Created by Gabelmann Fredrick on 5/4/12. // Copyright (c) 2012 Reticent Media, Inc. All rights reserved. // #import <UIKit/UIKit.h> @interface Store : NSObject #pragma mark - Properites @property (strong, nonatomic) NSString *region; @property (strong, nonatomic) NSString *city; @property (strong, nonatomic) NSString *address; @property (strong, nonatomic) NSString *longName; @property (strong, nonatomic) NSString *name; @property (strong, nonatomic) NSString *country; @property (assign) float lng; @property (strong, nonatomic) NSString *postalCode; @property (strong, nonatomic) NSString *phone; @property (strong, nonatomic) NSString *hours; @property (assign) NSInteger storeId; @property (assign) float lat; @property (strong, nonatomic) NSString *fullPostalCode; @property (assign) float distance; #pragma mark - Initializers - (id)initForStores:(RKObjectManager *)objectManager; #pragma mark - Requests - (void)getStoresWithZipcode:(NSString *)aZipcode distance:(NSString *)aDistance andDelegate:(id)delegate; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Data Model/._Store.h
IT4781-U02A1-AlexBenavides/StoreLocator/Data Model/Store.m
// // Profile.m // sartorii // // Created by Gabelmann Fredrick on 5/4/12. // Copyright (c) 2012 Reticent Media, Inc. All rights reserved. // #import "Store.h" @interface Store () @property (nonatomic, strong) RKObjectManager *manager; @end @implementation Store #pragma mark - Properties @synthesize region; @synthesize city; @synthesize address; @synthesize longName; @synthesize name; @synthesize country; @synthesize lng; @synthesize postalCode; @synthesize phone; @synthesize hours; @synthesize storeId; @synthesize lat; @synthesize fullPostalCode; @synthesize distance; @synthesize manager; #pragma mark - Initializers - (id)initForStores:(RKObjectManager *)objectManager { self = [super init]; if (self) { self.manager = objectManager; RKObjectMapping *successResponseMapping = [RKObjectMapping mappingForClass:[Store class]]; [successResponseMapping mapAttributes:@"region", @"city", @"address", @"longName", @"name", @"country", @"lng", @"postalCode", @"phone", @"hours", @"storeId", @"lat", @"fullPostalCode", @"distance", nil]; [self.manager.mappingProvider setMapping:successResponseMapping forKeyPath:@"stores"]; } return self; } #pragma mark - Requests - (void)getStoresWithZipcode:(NSString *)aZipcode distance:(NSString *)aDistance andDelegate:(id)delegate { [self.manager loadObjectsAtResourcePath:[NSString stringWithFormat:@"/stores(area(%@,%@))?apiKey=%@&format=json", aZipcode, aDistance, kBbyopenApiKey] delegate:delegate]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Data Model/._Store.m
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/._Data Model
IT4781-U02A1-AlexBenavides/StoreLocator/en.lproj/InfoPlist.strings
/* Localized versions of Info.plist keys */
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/en.lproj/._InfoPlist.strings
IT4781-U02A1-AlexBenavides/StoreLocator/en.lproj/MainStoryboard_iPad.storyboard
IT4781-U02A1-AlexBenavides/StoreLocator/en.lproj/MainStoryboard_iPhone.storyboard
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/._en.lproj
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/.DS_Store
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/._.DS_Store
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/.gitignore
# the build Build build # DerivedData Docs/API # temp nibs and swap files *~.nib *.swp *.orig # OS X folder attributes .DS_Store # user-specific XCode stuff *.mode1v3 *.mode2v3 *.pbxuser *.perspectivev3 *.xcuserdatad Examples/RKDiscussionBoardExample/discussion_board_backend/public/system/attachments/* test-reports/
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/._.gitignore
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/.gitmodules
[submodule "Examples/RKCatalog/Server"] path = Examples/RKCatalog/Server url = git://github.com/RestKit/RKCatalog-Server.git
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/._.gitmodules
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/.rvmrc
rvm use 1.9.2@RestKit
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/._.rvmrc
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/CoreData.h
// // CoreData.h // RestKit // // Created by Blake Watters on 9/30/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <CoreData/CoreData.h> #import "ObjectMapping.h" #import "NSManagedObject+ActiveRecord.h" #import "RKManagedObjectStore.h" #import "RKManagedObjectSeeder.h" #import "RKManagedObjectMapping.h" #import "RKManagedObjectMappingOperation.h" #import "RKManagedObjectCaching.h" #import "RKInMemoryManagedObjectCache.h" #import "RKFetchRequestManagedObjectCache.h" #import "RKSearchableManagedObject.h" #import "RKSearchWord.h" #import "RKObjectPropertyInspector+CoreData.h" #import "RKObjectMappingProvider+CoreData.h" #import "NSManagedObjectContext+RKAdditions.h" #import "NSManagedObject+RKAdditions.h" #import "NSEntityDescription+RKAdditions.h"
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._CoreData.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/NSEntityDescription+RKAdditions.h
// // NSEntityDescription+RKAdditions.h // RestKit // // Created by Blake Watters on 3/22/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <CoreData/CoreData.h> /** The key for retrieving the name of the attribute that acts as the primary key from the user info dictionary of the receiving NSEntityDescription. **Value**: @"primaryKeyAttribute" */ extern NSString * const RKEntityDescriptionPrimaryKeyAttributeUserInfoKey; /** The substitution variable used in predicateForPrimaryKeyAttribute. **Value**: @"PRIMARY_KEY_VALUE" @see predicateForPrimaryKeyAttribute */ extern NSString * const RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubstitutionVariable; /** Provides extensions to NSEntityDescription for various common tasks. */ @interface NSEntityDescription (RKAdditions) /** The name of the attribute that acts as the primary key for the receiver. The primary key attribute can be configured in two ways: 1. From within the Xcode Core Data editing view by adding the desired attribute's name as the value for the key `primaryKeyAttribute` to the user info dictionary. 1. Programmatically, by retrieving the NSEntityDescription instance and setting the property's value. Programmatically configured values take precedence over the user info dictionary. */ @property (nonatomic, retain) NSString *primaryKeyAttributeName; /** The attribute description object for the attribute designated as the primary key for the receiver. */ @property (nonatomic, readonly) NSAttributeDescription *primaryKeyAttribute; /** The class representing the value of the attribute designated as the primary key for the receiver. */ @property (nonatomic, readonly) Class primaryKeyAttributeClass; /** Returns a cached predicate specifying that the primary key attribute is equal to the $PRIMARY_KEY_VALUE substitution variable. This predicate is cached to avoid parsing overhead during object mapping operations and must be evaluated using [NSPredicate predicateWithSubstitutionVariables:] @return A cached predicate specifying the value of the primary key attribute is equal to the $PRIMARY_KEY_VALUE substitution variable. */ - (NSPredicate *)predicateForPrimaryKeyAttribute; /** Returns a predicate specifying that the value of the primary key attribute is equal to a given value. This predicate is constructed by evaluating the cached predicate returned by the predicateForPrimaryKeyAttribute with a dictionary of substitution variables specifying that $PRIMARY_KEY_VALUE is equal to the given value. **NOTE**: This method considers the type of the receiver's primary key attribute when constructing the predicate. It will coerce the given value into either an NSString or an NSNumber as appropriate. This behavior is a convenience to avoid annoying issues related to Core Data's handling of predicates for NSString and NSNumber types that were not appropriately casted. @return A predicate speciying that the value of the primary key attribute is equal to a given value. */ - (NSPredicate *)predicateForPrimaryKeyAttributeWithValue:(id)value; /** Coerces the given value into the class representing the primary key. Currently support NSString and NSNumber coercsions. @bug **NOTE** This API is temporary and will be deprecated and replaced. @since 0.10.1 */ - (id)coerceValueForPrimaryKey:(id)primaryKeyValue; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._NSEntityDescription+RKAdditions.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/NSEntityDescription+RKAdditions.m
// // NSEntityDescription+RKAdditions.m // RestKit // // Created by Blake Watters on 3/22/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <objc/runtime.h> #import "NSEntityDescription+RKAdditions.h" NSString * const RKEntityDescriptionPrimaryKeyAttributeUserInfoKey = @"primaryKeyAttribute"; NSString * const RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubstitutionVariable = @"PRIMARY_KEY_VALUE"; static char primaryKeyAttributeNameKey, primaryKeyPredicateKey; @implementation NSEntityDescription (RKAdditions) - (void)setPredicateForPrimaryKeyAttribute:(NSString *)primaryKeyAttribute { NSPredicate *predicate = (primaryKeyAttribute) ? [NSPredicate predicateWithFormat:@"%K == $PRIMARY_KEY_VALUE", primaryKeyAttribute] : nil; objc_setAssociatedObject(self, &primaryKeyPredicateKey, predicate, OBJC_ASSOCIATION_RETAIN); } #pragma mark - Public - (NSAttributeDescription *)primaryKeyAttribute { return [[self attributesByName] valueForKey:[self primaryKeyAttributeName]]; } - (Class)primaryKeyAttributeClass { NSAttributeDescription *attributeDescription = [self primaryKeyAttribute]; if (attributeDescription) { return NSClassFromString(attributeDescription.attributeValueClassName); } return nil; } - (NSString *)primaryKeyAttributeName { // Check for an associative object reference NSString *primaryKeyAttribute = (NSString *) objc_getAssociatedObject(self, &primaryKeyAttributeNameKey); // Fall back to the userInfo dictionary if (! primaryKeyAttribute) { primaryKeyAttribute = [self.userInfo valueForKey:RKEntityDescriptionPrimaryKeyAttributeUserInfoKey]; // If we have loaded from the user info, ensure we have a predicate if (! [self predicateForPrimaryKeyAttribute]) { [self setPredicateForPrimaryKeyAttribute:primaryKeyAttribute]; } } return primaryKeyAttribute; } - (void)setPrimaryKeyAttributeName:(NSString *)primaryKeyAttributeName { objc_setAssociatedObject(self, &primaryKeyAttributeNameKey, primaryKeyAttributeName, OBJC_ASSOCIATION_RETAIN); [self setPredicateForPrimaryKeyAttribute:primaryKeyAttributeName]; } - (NSPredicate *)predicateForPrimaryKeyAttribute { return (NSPredicate *) objc_getAssociatedObject(self, &primaryKeyPredicateKey); } - (id)coerceValueForPrimaryKey:(id)primaryKeyValue { id searchValue = primaryKeyValue; Class theClass = [self primaryKeyAttributeClass]; if (theClass) { // TODO: This coercsion behavior should be pluggable and reused from the mapper if ([theClass isSubclassOfClass:[NSNumber class]] && ![searchValue isKindOfClass:[NSNumber class]]) { // Handle NSString -> NSNumber if ([searchValue isKindOfClass:[NSString class]]) { searchValue = [NSNumber numberWithDouble:[searchValue doubleValue]]; } } else if ([theClass isSubclassOfClass:[NSString class]] && ![searchValue isKindOfClass:[NSString class]]) { // Coerce to string if ([searchValue respondsToSelector:@selector(stringValue)]) { searchValue = [searchValue stringValue]; } } } return searchValue; } - (NSPredicate *)predicateForPrimaryKeyAttributeWithValue:(id)value { id substitutionValue = [self coerceValueForPrimaryKey:value]; NSDictionary *variables = [NSDictionary dictionaryWithObject:substitutionValue forKey:RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubstitutionVariable]; return [[self predicateForPrimaryKeyAttribute] predicateWithSubstitutionVariables:variables]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._NSEntityDescription+RKAdditions.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/NSManagedObject+ActiveRecord.h
// // NSManagedObject+ActiveRecord.h // // Adapted from https://github.com/magicalpanda/MagicalRecord // Created by Saul Mora on 11/15/09. // Copyright 2010 Magical Panda Software, LLC All rights reserved. // // Created by Chad Podoski on 3/18/11. // #import <CoreData/CoreData.h> /** Extensions to NSManagedObjectContext for RestKit's Active Record pattern implementation */ @interface NSManagedObjectContext (ActiveRecord) + (NSManagedObjectContext *)defaultContext; + (void)setDefaultContext:(NSManagedObjectContext *)context; + (NSManagedObjectContext *)contextForCurrentThread; @end /** Provides extensions to NSManagedObject implementing a low-ceremony querying interface. */ @interface NSManagedObject (ActiveRecord) /** * The NSEntityDescription for the Subclass * defaults to the subclass className, may be overridden */ + (NSEntityDescription*)entity; /** * Returns an initialized NSFetchRequest for the entity, with no predicate */ + (NSFetchRequest*)fetchRequest; /** * Fetches all objects from the persistent store identified by the fetchRequest */ + (NSArray*)objectsWithFetchRequest:(NSFetchRequest*)fetchRequest; /** * Retrieves the number of objects that would be retrieved by the fetchRequest, * if executed */ + (NSUInteger)countOfObjectsWithFetchRequest:(NSFetchRequest*)fetchRequest; /** * Fetches all objects from the persistent store via a set of fetch requests and * returns all results in a single array. */ + (NSArray*)objectsWithFetchRequests:(NSArray*)fetchRequests; /** * Fetches the first object identified by the fetch request. A limit of one will be * applied to the fetch request before dispatching. */ + (id)objectWithFetchRequest:(NSFetchRequest*)fetchRequest; /** * Fetches all objects from the persistent store by constructing a fetch request and * applying the predicate supplied. A short-cut for doing filtered searches on the objects * of this class under management. */ + (NSArray*)objectsWithPredicate:(NSPredicate*)predicate; /** * Fetches the first object matching a predicate from the persistent store. A fetch request * will be constructed for you and a fetch limit of 1 will be applied. */ + (id)objectWithPredicate:(NSPredicate*)predicate; /** * Fetches all managed objects of this class from the persistent store as an array */ + (NSArray*)allObjects; /** * Returns a count of all managed objects of this class in the persistent store. On * error, will populate the error argument */ + (NSUInteger)count:(NSError**)error; /** * Returns a count of all managed objects of this class in the persistent store. Deprecated * use the error form above * * @deprecated */ + (NSUInteger)count DEPRECATED_ATTRIBUTE; /** * Creates a new managed object and inserts it into the managedObjectContext. */ + (id)object; /** * Returns YES when an object has not been saved to the managed object context yet */ - (BOOL)isNew; /** Finds the instance of the receiver's entity with the given value for the primary key attribute in the managed object context for the current thread. @param primaryKeyValue The value for the receiving entity's primary key attribute. @return The object with the primary key attribute equal to the given value or nil. */ + (id)findByPrimaryKey:(id)primaryKeyValue; /** Finds the instance of the receiver's entity with the given value for the primary key attribute in the given managed object context. @param primaryKeyValue The value for the receiving entity's primary key attribute. @param context The managed object context to find the instance in. @return The object with the primary key attribute equal to the given value or nil. */ + (id)findByPrimaryKey:(id)primaryKeyValue inContext:(NSManagedObjectContext *)context; //////////////////////////////////////////////////////////////////////////////////////////////////// + (NSManagedObjectContext*)currentContext; + (void)handleErrors:(NSError *)error; + (NSArray *)executeFetchRequest:(NSFetchRequest *)request; + (NSArray *)executeFetchRequest:(NSFetchRequest *)request inContext:(NSManagedObjectContext *)context; + (NSFetchRequest *)createFetchRequest; + (NSFetchRequest *)createFetchRequestInContext:(NSManagedObjectContext *)context; + (NSEntityDescription *)entityDescription; + (NSEntityDescription *)entityDescriptionInContext:(NSManagedObjectContext *)context; + (NSArray *)propertiesNamed:(NSArray *)properties; + (id)createEntity; + (id)createInContext:(NSManagedObjectContext *)context; - (BOOL)deleteEntity; - (BOOL)deleteInContext:(NSManagedObjectContext *)context; + (BOOL)truncateAll; + (BOOL)truncateAllInContext:(NSManagedObjectContext *)context; + (NSArray *)ascendingSortDescriptors:(id)attributesToSortBy, ...; + (NSArray *)descendingSortDescriptors:(id)attributesToSortyBy, ...; + (NSNumber *)numberOfEntities; + (NSNumber *)numberOfEntitiesWithContext:(NSManagedObjectContext *)context; + (NSNumber *)numberOfEntitiesWithPredicate:(NSPredicate *)searchTerm; + (NSNumber *)numberOfEntitiesWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context; + (BOOL) hasAtLeastOneEntity; + (BOOL) hasAtLeastOneEntityInContext:(NSManagedObjectContext *)context; + (NSFetchRequest *)requestAll; + (NSFetchRequest *)requestAllInContext:(NSManagedObjectContext *)context; + (NSFetchRequest *)requestAllWhere:(NSString *)property isEqualTo:(id)value; + (NSFetchRequest *)requestAllWhere:(NSString *)property isEqualTo:(id)value inContext:(NSManagedObjectContext *)context; + (NSFetchRequest *)requestFirstWithPredicate:(NSPredicate *)searchTerm; + (NSFetchRequest *)requestFirstWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context; + (NSFetchRequest *)requestFirstByAttribute:(NSString *)attribute withValue:(id)searchValue; + (NSFetchRequest *)requestFirstByAttribute:(NSString *)attribute withValue:(id)searchValue inContext:(NSManagedObjectContext *)context; + (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending; + (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context; + (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm; + (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context; + (NSArray *)findAll; + (NSArray *)findAllInContext:(NSManagedObjectContext *)context; + (NSArray *)findAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending; + (NSArray *)findAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context; + (NSArray *)findAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm; + (NSArray *)findAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context; /*+ (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context;*/ + (NSArray *)findAllWithPredicate:(NSPredicate *)searchTerm; + (NSArray *)findAllWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context; + (NSNumber *)maxValueFor:(NSString *)property; + (id) objectWithMinValueFor:(NSString *)property; + (id) objectWithMinValueFor:(NSString *)property inContext:(NSManagedObjectContext *)context; + (id)findFirst; + (id)findFirstInContext:(NSManagedObjectContext *)context; + (id)findFirstWithPredicate:(NSPredicate *)searchTerm; + (id)findFirstWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context; + (id)findFirstWithPredicate:(NSPredicate *)searchterm sortedBy:(NSString *)property ascending:(BOOL)ascending; + (id)findFirstWithPredicate:(NSPredicate *)searchterm sortedBy:(NSString *)property ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context; + (id)findFirstWithPredicate:(NSPredicate *)searchTerm andRetrieveAttributes:(NSArray *)attributes; + (id)findFirstWithPredicate:(NSPredicate *)searchTerm andRetrieveAttributes:(NSArray *)attributes inContext:(NSManagedObjectContext *)context; + (id)findFirstWithPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortBy ascending:(BOOL)ascending andRetrieveAttributes:(id)attributes, ...; + (id)findFirstWithPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortBy ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context andRetrieveAttributes:(id)attributes, ...; + (id)findFirstByAttribute:(NSString *)attribute withValue:(id)searchValue; + (id)findFirstByAttribute:(NSString *)attribute withValue:(id)searchValue inContext:(NSManagedObjectContext *)context; + (NSArray *)findByAttribute:(NSString *)attribute withValue:(id)searchValue; + (NSArray *)findByAttribute:(NSString *)attribute withValue:(id)searchValue inContext:(NSManagedObjectContext *)context; + (NSArray *)findByAttribute:(NSString *)attribute withValue:(id)searchValue andOrderBy:(NSString *)sortTerm ascending:(BOOL)ascending; + (NSArray *)findByAttribute:(NSString *)attribute withValue:(id)searchValue andOrderBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context; #if TARGET_OS_IPHONE + (NSFetchedResultsController *)fetchAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm groupBy:(NSString *)groupingKeyPath; + (NSFetchedResultsController *)fetchAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm groupBy:(NSString *)groupingKeyPath inContext:(NSManagedObjectContext *)context; + (NSFetchedResultsController *)fetchRequest:(NSFetchRequest *)request groupedBy:(NSString *)group; + (NSFetchedResultsController *)fetchRequest:(NSFetchRequest *)request groupedBy:(NSString *)group inContext:(NSManagedObjectContext *)context; + (NSFetchedResultsController *)fetchRequestAllGroupedBy:(NSString *)group withPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortTerm ascending:(BOOL)ascending; + (NSFetchedResultsController *)fetchRequestAllGroupedBy:(NSString *)group withPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context; #endif @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._NSManagedObject+ActiveRecord.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/NSManagedObject+ActiveRecord.m
// // NSManagedObject+ActiveRecord.m // // Adapted from https://github.com/magicalpanda/MagicalRecord // Created by Saul Mora on 11/15/09. // Copyright 2010 Magical Panda Software, LLC All rights reserved. // // Created by Chad Podoski on 3/18/11. // #import <objc/runtime.h> #import "NSManagedObject+ActiveRecord.h" #import "RKManagedObjectStore.h" #import "RKLog.h" #import "RKFixCategoryBug.h" #import "NSEntityDescription+RKAdditions.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData static NSUInteger const kActiveRecordDefaultBatchSize = 10; static NSNumber *defaultBatchSize = nil; static NSManagedObjectContext *defaultContext = nil; RK_FIX_CATEGORY_BUG(NSManagedObjectContext_ActiveRecord) @implementation NSManagedObjectContext (ActiveRecord) + (NSManagedObjectContext *)defaultContext { return defaultContext; } + (void)setDefaultContext:(NSManagedObjectContext *)newDefaultContext { [newDefaultContext retain]; [defaultContext release]; defaultContext = newDefaultContext; } + (NSManagedObjectContext *)contextForCurrentThread { NSAssert([RKManagedObjectStore defaultObjectStore], @"[RKManagedObjectStore defaultObjectStore] cannot be nil"); return [[RKManagedObjectStore defaultObjectStore] managedObjectContextForCurrentThread]; } @end RK_FIX_CATEGORY_BUG(NSManagedObject_ActiveRecord) @implementation NSManagedObject (ActiveRecord) #pragma mark - RKManagedObject methods + (NSEntityDescription*)entity { NSString* className = [NSString stringWithCString:class_getName([self class]) encoding:NSASCIIStringEncoding]; return [NSEntityDescription entityForName:className inManagedObjectContext:[NSManagedObjectContext contextForCurrentThread]]; } + (NSFetchRequest*)fetchRequest { NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease]; NSEntityDescription *entity = [self entity]; [fetchRequest setEntity:entity]; return fetchRequest; } + (NSArray*)objectsWithFetchRequest:(NSFetchRequest*)fetchRequest { NSError* error = nil; NSArray* objects = [[NSManagedObjectContext contextForCurrentThread] executeFetchRequest:fetchRequest error:&error]; if (objects == nil) { RKLogError(@"Error: %@", [error localizedDescription]); } return objects; } + (NSUInteger)countOfObjectsWithFetchRequest:(NSFetchRequest*)fetchRequest { NSError* error = nil; NSUInteger objectCount = [[NSManagedObjectContext contextForCurrentThread] countForFetchRequest:fetchRequest error:&error]; if (objectCount == NSNotFound) { RKLogError(@"Error: %@", [error localizedDescription]); } return objectCount; } + (NSArray*)objectsWithFetchRequests:(NSArray*)fetchRequests { NSMutableArray* mutableObjectArray = [[NSMutableArray alloc] init]; for (NSFetchRequest* fetchRequest in fetchRequests) { [mutableObjectArray addObjectsFromArray:[self objectsWithFetchRequest:fetchRequest]]; } NSArray* objects = [NSArray arrayWithArray:mutableObjectArray]; [mutableObjectArray release]; return objects; } + (id)objectWithFetchRequest:(NSFetchRequest*)fetchRequest { [fetchRequest setFetchLimit:1]; NSArray* objects = [self objectsWithFetchRequest:fetchRequest]; if ([objects count] == 0) { return nil; } else { return [objects objectAtIndex:0]; } } + (NSArray*)objectsWithPredicate:(NSPredicate*)predicate { NSFetchRequest* fetchRequest = [self fetchRequest]; [fetchRequest setPredicate:predicate]; return [self objectsWithFetchRequest:fetchRequest]; } + (id)objectWithPredicate:(NSPredicate*)predicate { NSFetchRequest* fetchRequest = [self fetchRequest]; [fetchRequest setPredicate:predicate]; return [self objectWithFetchRequest:fetchRequest]; } + (NSArray*)allObjects { return [self objectsWithPredicate:nil]; } + (NSUInteger)count:(NSError**)error { NSFetchRequest* fetchRequest = [self fetchRequest]; return [[NSManagedObjectContext contextForCurrentThread] countForFetchRequest:fetchRequest error:error]; } + (NSUInteger)count { NSError *error = nil; return [self count:&error]; } + (id)object { id object = [[self alloc] initWithEntity:[self entity] insertIntoManagedObjectContext:[NSManagedObjectContext contextForCurrentThread]]; return [object autorelease]; } - (BOOL)isNew { NSDictionary *vals = [self committedValuesForKeys:nil]; return [vals count] == 0; } + (id)findByPrimaryKey:(id)primaryKeyValue inContext:(NSManagedObjectContext *)context { NSPredicate *predicate = [[self entityDescriptionInContext:context] predicateForPrimaryKeyAttributeWithValue:primaryKeyValue]; if (! predicate) { RKLogWarning(@"Attempt to findByPrimaryKey for entity with nil primaryKeyAttribute. Set the primaryKeyAttributeName and try again! %@", self); return nil; } return [self findFirstWithPredicate:predicate inContext:context]; } + (id)findByPrimaryKey:(id)primaryKeyValue { return [self findByPrimaryKey:primaryKeyValue inContext:[NSManagedObjectContext contextForCurrentThread]]; } #pragma mark - MagicalRecord Ported Methods + (NSManagedObjectContext*)currentContext; { return [NSManagedObjectContext contextForCurrentThread]; } + (void)setDefaultBatchSize:(NSUInteger)newBatchSize { @synchronized(defaultBatchSize) { defaultBatchSize = [NSNumber numberWithUnsignedInteger:newBatchSize]; } } + (NSInteger)defaultBatchSize { if (defaultBatchSize == nil) { [self setDefaultBatchSize:kActiveRecordDefaultBatchSize]; } return [defaultBatchSize integerValue]; } + (void)handleErrors:(NSError *)error { if (error) { NSDictionary *userInfo = [error userInfo]; for (NSArray *detailedError in [userInfo allValues]) { if ([detailedError isKindOfClass:[NSArray class]]) { for (NSError *e in detailedError) { if ([e respondsToSelector:@selector(userInfo)]) { RKLogError(@"Error Details: %@", [e userInfo]); } else { RKLogError(@"Error Details: %@", e); } } } else { RKLogError(@"Error: %@", detailedError); } } RKLogError(@"Error Domain: %@", [error domain]); RKLogError(@"Recovery Suggestion: %@", [error localizedRecoverySuggestion]); } } + (NSArray *)executeFetchRequest:(NSFetchRequest *)request inContext:(NSManagedObjectContext *)context { NSError *error = nil; NSArray *results = [context executeFetchRequest:request error:&error]; [self handleErrors:error]; return results; } + (NSArray *)executeFetchRequest:(NSFetchRequest *)request { return [self executeFetchRequest:request inContext:[self currentContext]]; } + (id)executeFetchRequestAndReturnFirstObject:(NSFetchRequest *)request inContext:(NSManagedObjectContext *)context { [request setFetchLimit:1]; NSArray *results = [self executeFetchRequest:request inContext:context]; if ([results count] == 0) { return nil; } return [results objectAtIndex:0]; } + (id)executeFetchRequestAndReturnFirstObject:(NSFetchRequest *)request { return [self executeFetchRequestAndReturnFirstObject:request inContext:[self currentContext]]; } #if TARGET_OS_IPHONE + (void)performFetch:(NSFetchedResultsController *)controller { NSError *error = nil; if (![controller performFetch:&error]) { [self handleErrors:error]; } } #endif + (NSEntityDescription *)entityDescriptionInContext:(NSManagedObjectContext *)context { NSString *entityName = NSStringFromClass([self class]); return [NSEntityDescription entityForName:entityName inManagedObjectContext:context]; } + (NSEntityDescription *)entityDescription { return [self entityDescriptionInContext:[self currentContext]]; } + (NSArray *)propertiesNamed:(NSArray *)properties { NSEntityDescription *description = [self entityDescription]; NSMutableArray *propertiesWanted = [NSMutableArray array]; if (properties) { NSDictionary *propDict = [description propertiesByName]; for (NSString *propertyName in properties) { NSPropertyDescription *property = [propDict objectForKey:propertyName]; if (property) { [propertiesWanted addObject:property]; } else { RKLogError(@"Property '%@' not found in %@ properties for %@", propertyName, [propDict count], NSStringFromClass(self)); } } } return propertiesWanted; } + (NSArray *)sortAscending:(BOOL)ascending attributes:(id)attributesToSortBy, ... { NSMutableArray *attributes = [NSMutableArray array]; if ([attributesToSortBy isKindOfClass:[NSArray class]]) { id attributeName; va_list variadicArguments; va_start(variadicArguments, attributesToSortBy); while ((attributeName = va_arg(variadicArguments, id))!= nil) { NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:attributeName ascending:ascending]; [attributes addObject:sortDescriptor]; [sortDescriptor release]; } va_end(variadicArguments); } else if ([attributesToSortBy isKindOfClass:[NSString class]]) { va_list variadicArguments; va_start(variadicArguments, attributesToSortBy); [attributes addObject:[[[NSSortDescriptor alloc] initWithKey:attributesToSortBy ascending:ascending] autorelease] ]; va_end(variadicArguments); } return attributes; } + (NSArray *)ascendingSortDescriptors:(id)attributesToSortBy, ... { return [self sortAscending:YES attributes:attributesToSortBy]; } + (NSArray *)descendingSortDescriptors:(id)attributesToSortyBy, ... { return [self sortAscending:NO attributes:attributesToSortyBy]; } + (NSFetchRequest *)createFetchRequestInContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; [request setEntity:[self entityDescriptionInContext:context]]; return request; } + (NSFetchRequest *)createFetchRequest { return [self createFetchRequestInContext:[self currentContext]]; } #pragma mark - #pragma mark Number of Entities + (NSNumber *)numberOfEntitiesWithContext:(NSManagedObjectContext *)context { NSError *error = nil; NSUInteger count = [context countForFetchRequest:[self createFetchRequestInContext:context] error:&error]; [self handleErrors:error]; return [NSNumber numberWithUnsignedInteger:count]; } + (NSNumber *)numberOfEntities { return [self numberOfEntitiesWithContext:[self currentContext]]; } + (NSNumber *)numberOfEntitiesWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context { NSError *error = nil; NSFetchRequest *request = [self createFetchRequestInContext:context]; [request setPredicate:searchTerm]; NSUInteger count = [context countForFetchRequest:request error:&error]; [self handleErrors:error]; return [NSNumber numberWithUnsignedInteger:count]; } + (NSNumber *)numberOfEntitiesWithPredicate:(NSPredicate *)searchTerm; { return [self numberOfEntitiesWithPredicate:searchTerm inContext:[self currentContext]]; } + (BOOL)hasAtLeastOneEntityInContext:(NSManagedObjectContext *)context { return [[self numberOfEntitiesWithContext:context] intValue] > 0; } + (BOOL)hasAtLeastOneEntity { return [self hasAtLeastOneEntityInContext:[self currentContext]]; } #pragma mark - #pragma mark Reqest Helpers + (NSFetchRequest *)requestAll { return [self createFetchRequestInContext:[self currentContext]]; } + (NSFetchRequest *)requestAllInContext:(NSManagedObjectContext *)context { return [self createFetchRequestInContext:context]; } + (NSFetchRequest *)requestAllWhere:(NSString *)property isEqualTo:(id)value inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self createFetchRequestInContext:context]; [request setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", property, value]]; return request; } + (NSFetchRequest *)requestAllWhere:(NSString *)property isEqualTo:(id)value { return [self requestAllWhere:property isEqualTo:value inContext:[self currentContext]]; } + (NSFetchRequest *)requestFirstWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self createFetchRequestInContext:context]; [request setPredicate:searchTerm]; [request setFetchLimit:1]; return request; } + (NSFetchRequest *)requestFirstWithPredicate:(NSPredicate *)searchTerm { return [self requestFirstWithPredicate:searchTerm inContext:[self currentContext]]; } + (NSFetchRequest *)requestFirstByAttribute:(NSString *)attribute withValue:(id)searchValue inContext:(NSManagedObjectContext *)context; { NSFetchRequest *request = [self createFetchRequestInContext:context]; [request setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", attribute, searchValue]]; return request; } + (NSFetchRequest *)requestFirstByAttribute:(NSString *)attribute withValue:(id)searchValue; { return [self requestFirstByAttribute:attribute withValue:searchValue inContext:[self currentContext]]; } + (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self requestAllInContext:context]; NSSortDescriptor *sortBy = [[NSSortDescriptor alloc] initWithKey:sortTerm ascending:ascending]; [request setSortDescriptors:[NSArray arrayWithObject:sortBy]]; [sortBy release]; return request; } + (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending { return [self requestAllSortedBy:sortTerm ascending:ascending inContext:[self currentContext]]; } + (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self requestAllInContext:context]; [request setPredicate:searchTerm]; [request setIncludesSubentities:NO]; [request setFetchBatchSize:[self defaultBatchSize]]; if (sortTerm != nil){ NSSortDescriptor *sortBy = [[NSSortDescriptor alloc] initWithKey:sortTerm ascending:ascending]; [request setSortDescriptors:[NSArray arrayWithObject:sortBy]]; [sortBy release]; } return request; } + (NSFetchRequest *)requestAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm; { NSFetchRequest *request = [self requestAllSortedBy:sortTerm ascending:ascending withPredicate:searchTerm inContext:[self currentContext]]; return request; } #pragma mark Finding Data #pragma mark - + (NSArray *)findAllInContext:(NSManagedObjectContext *)context { return [self executeFetchRequest:[self requestAllInContext:context] inContext:context]; } + (NSArray *)findAll { return [self findAllInContext:[self currentContext]]; } + (NSArray *)findAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self requestAllSortedBy:sortTerm ascending:ascending inContext:context]; return [self executeFetchRequest:request inContext:context]; } + (NSArray *)findAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending { return [self findAllSortedBy:sortTerm ascending:ascending inContext:[self currentContext]]; } + (NSArray *)findAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self requestAllSortedBy:sortTerm ascending:ascending withPredicate:searchTerm inContext:context]; return [self executeFetchRequest:request inContext:context]; } + (NSArray *)findAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm { return [self findAllSortedBy:sortTerm ascending:ascending withPredicate:searchTerm inContext:[self currentContext]]; } #pragma mark - #pragma mark NSFetchedResultsController helpers #if TARGET_OS_IPHONE + (NSFetchedResultsController *)fetchRequestAllGroupedBy:(NSString *)group withPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context { NSString *cacheName = nil; #ifdef STORE_USE_CACHE cacheName = [NSString stringWithFormat:@"ActiveRecord-Cache-%@", NSStringFromClass(self)]; #endif NSFetchRequest *request = [self requestAllSortedBy:sortTerm ascending:ascending withPredicate:searchTerm inContext:context]; NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:group cacheName:cacheName]; return [controller autorelease]; } + (NSFetchedResultsController *)fetchRequestAllGroupedBy:(NSString *)group withPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortTerm ascending:(BOOL)ascending { return [self fetchRequestAllGroupedBy:group withPredicate:searchTerm sortedBy:sortTerm ascending:ascending inContext:[self currentContext]]; } + (NSFetchedResultsController *)fetchAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm groupBy:(NSString *)groupingKeyPath inContext:(NSManagedObjectContext *)context { NSFetchedResultsController *controller = [self fetchRequestAllGroupedBy:groupingKeyPath withPredicate:searchTerm sortedBy:sortTerm ascending:ascending inContext:context]; [self performFetch:controller]; return controller; } + (NSFetchedResultsController *)fetchAllSortedBy:(NSString *)sortTerm ascending:(BOOL)ascending withPredicate:(NSPredicate *)searchTerm groupBy:(NSString *)groupingKeyPath { return [self fetchAllSortedBy:sortTerm ascending:ascending withPredicate:searchTerm groupBy:groupingKeyPath inContext:[self currentContext]]; } + (NSFetchedResultsController *)fetchRequest:(NSFetchRequest *)request groupedBy:(NSString *)group inContext:(NSManagedObjectContext *)context { NSString *cacheName = nil; #ifdef STORE_USE_CACHE cacheName = [NSString stringWithFormat:@"ActiveRecord-Cache-%@", NSStringFromClass([self class])]; #endif NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:group cacheName:cacheName]; [self performFetch:controller]; return [controller autorelease]; } + (NSFetchedResultsController *)fetchRequest:(NSFetchRequest *)request groupedBy:(NSString *)group { return [self fetchRequest:request groupedBy:group inContext:[self currentContext]]; } #endif #pragma mark - + (NSArray *)findAllWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self createFetchRequestInContext:context]; [request setPredicate:searchTerm]; return [self executeFetchRequest:request inContext:context]; } + (NSArray *)findAllWithPredicate:(NSPredicate *)searchTerm { return [self findAllWithPredicate:searchTerm inContext:[self currentContext]]; } + (id)findFirstInContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self createFetchRequestInContext:context]; return [self executeFetchRequestAndReturnFirstObject:request inContext:context]; } + (id)findFirst { return [self findFirstInContext:[self currentContext]]; } + (id)findFirstByAttribute:(NSString *)attribute withValue:(id)searchValue inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self requestFirstByAttribute:attribute withValue:searchValue inContext:context]; return [self executeFetchRequestAndReturnFirstObject:request inContext:context]; } + (id)findFirstByAttribute:(NSString *)attribute withValue:(id)searchValue { return [self findFirstByAttribute:attribute withValue:searchValue inContext:[self currentContext]]; } + (id)findFirstWithPredicate:(NSPredicate *)searchTerm inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self requestFirstWithPredicate:searchTerm]; return [self executeFetchRequestAndReturnFirstObject:request inContext:context]; } + (id)findFirstWithPredicate:(NSPredicate *)searchTerm { return [self findFirstWithPredicate:searchTerm inContext:[self currentContext]]; } + (id)findFirstWithPredicate:(NSPredicate *)searchterm sortedBy:(NSString *)property ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self requestAllSortedBy:property ascending:ascending withPredicate:searchterm inContext:context]; return [self executeFetchRequestAndReturnFirstObject:request inContext:context]; } + (id)findFirstWithPredicate:(NSPredicate *)searchterm sortedBy:(NSString *)property ascending:(BOOL)ascending { return [self findFirstWithPredicate:searchterm sortedBy:property ascending:ascending inContext:[self currentContext]]; } + (id)findFirstWithPredicate:(NSPredicate *)searchTerm andRetrieveAttributes:(NSArray *)attributes inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self createFetchRequestInContext:context]; [request setPredicate:searchTerm]; return [self executeFetchRequestAndReturnFirstObject:request inContext:context]; } + (id)findFirstWithPredicate:(NSPredicate *)searchTerm andRetrieveAttributes:(NSArray *)attributes { return [self findFirstWithPredicate:searchTerm andRetrieveAttributes:attributes inContext:[self currentContext]]; } + (id)findFirstWithPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortBy ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context andRetrieveAttributes:(id)attributes, ... { NSFetchRequest *request = [self requestAllSortedBy:sortBy ascending:ascending withPredicate:searchTerm inContext:context]; return [self executeFetchRequestAndReturnFirstObject:request inContext:context]; } + (id)findFirstWithPredicate:(NSPredicate *)searchTerm sortedBy:(NSString *)sortBy ascending:(BOOL)ascending andRetrieveAttributes:(id)attributes, ... { return [self findFirstWithPredicate:searchTerm sortedBy:sortBy ascending:ascending inContext:[self currentContext] andRetrieveAttributes:attributes]; } + (NSArray *)findByAttribute:(NSString *)attribute withValue:(id)searchValue inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [self createFetchRequestInContext:context]; [request setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", attribute, searchValue]]; return [self executeFetchRequest:request inContext:context]; } + (NSArray *)findByAttribute:(NSString *)attribute withValue:(id)searchValue { return [self findByAttribute:attribute withValue:searchValue inContext:[self currentContext]]; } + (NSArray *)findByAttribute:(NSString *)attribute withValue:(id)searchValue andOrderBy:(NSString *)sortTerm ascending:(BOOL)ascending inContext:(NSManagedObjectContext *)context { NSPredicate *searchTerm = [NSPredicate predicateWithFormat:@"%K = %@", attribute, searchValue]; NSFetchRequest *request = [self requestAllSortedBy:sortTerm ascending:ascending withPredicate:searchTerm inContext:context]; return [self executeFetchRequest:request]; } + (NSArray *)findByAttribute:(NSString *)attribute withValue:(id)searchValue andOrderBy:(NSString *)sortTerm ascending:(BOOL)ascending { return [self findByAttribute:attribute withValue:searchValue andOrderBy:sortTerm ascending:ascending inContext:[self currentContext]]; } + (id)createInContext:(NSManagedObjectContext *)context { NSString *entityName = NSStringFromClass([self class]); return [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; } + (id)createEntity { NSManagedObject *newEntity = [self createInContext:[self currentContext]]; return newEntity; } - (BOOL)deleteInContext:(NSManagedObjectContext *)context { [context deleteObject:self]; return YES; } - (BOOL)deleteEntity { [self deleteInContext:[[self class] currentContext]]; return YES; } + (BOOL)truncateAllInContext:(NSManagedObjectContext *)context { NSArray *allEntities = [self findAllInContext:context]; for (NSManagedObject *obj in allEntities) { [obj deleteInContext:context]; } return YES; } + (BOOL)truncateAll { [self truncateAllInContext:[self currentContext]]; return YES; } + (NSNumber *)maxValueFor:(NSString *)property { NSManagedObject *obj = [[self class] findFirstByAttribute:property withValue:[NSString stringWithFormat:@"max(%@)", property]]; return [obj valueForKey:property]; } + (id)objectWithMinValueFor:(NSString *)property inContext:(NSManagedObjectContext *)context { NSFetchRequest *request = [[self class] createFetchRequestInContext:context]; NSPredicate *searchFor = [NSPredicate predicateWithFormat:@"SELF = %@ AND %K = min(%@)", self, property, property]; [request setPredicate:searchFor]; return [[self class] executeFetchRequestAndReturnFirstObject:request inContext:context]; } + (id)objectWithMinValueFor:(NSString *)property { return [[self class] objectWithMinValueFor:property inContext:[self currentContext]]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._NSManagedObject+ActiveRecord.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/NSManagedObject+RKAdditions.h
// // NSManagedObject+RKAdditions.h // RestKit // // Created by Blake Watters on 3/14/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <CoreData/CoreData.h> @class RKManagedObjectStore, RKManagedObjectMapping; /** Provides extensions to NSManagedObject for various common tasks. */ @interface NSManagedObject (RKAdditions) /** The receiver's managed object store. */ - (RKManagedObjectStore *)managedObjectStore; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._NSManagedObject+RKAdditions.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/NSManagedObject+RKAdditions.m
// // NSManagedObject+RKAdditions.m // RestKit // // Created by Blake Watters on 3/14/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "NSManagedObject+RKAdditions.h" #import "NSManagedObjectContext+RKAdditions.h" @implementation NSManagedObject (RKAdditions) - (RKManagedObjectStore *)managedObjectStore { return self.managedObjectContext.managedObjectStore; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._NSManagedObject+RKAdditions.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.h
// // NSManagedObjectContext+RKAdditions.h // RestKit // // Created by Blake Watters on 3/14/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <CoreData/CoreData.h> @class RKManagedObjectStore; /** Provides extensions to NSManagedObjectContext for various common tasks. */ @interface NSManagedObjectContext (RKAdditions) /** The receiver's managed object store. */ @property (nonatomic, assign) RKManagedObjectStore *managedObjectStore; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._NSManagedObjectContext+RKAdditions.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.m
// // NSManagedObjectContext+RKAdditions.m // RestKit // // Created by Blake Watters on 3/14/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <objc/runtime.h> #import "NSManagedObjectContext+RKAdditions.h" static char NSManagedObject_RKManagedObjectStoreAssociatedKey; @implementation NSManagedObjectContext (RKAdditions) - (RKManagedObjectStore *)managedObjectStore { return (RKManagedObjectStore *) objc_getAssociatedObject(self, &NSManagedObject_RKManagedObjectStoreAssociatedKey); } - (void)setManagedObjectStore:(RKManagedObjectStore *)managedObjectStore { objc_setAssociatedObject(self, &NSManagedObject_RKManagedObjectStoreAssociatedKey, managedObjectStore, OBJC_ASSOCIATION_ASSIGN); } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._NSManagedObjectContext+RKAdditions.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKEntityByAttributeCache.h
// // RKEntityByAttributeCache.h // RestKit // // Created by Blake Watters on 5/1/12. // Copyright (c) 2012 RestKit. All rights reserved. // #import <CoreData/CoreData.h> /** Instances of RKEntityByAttributeCache provide an in-memory caching mechanism for managed objects instances of an entity in a managed object context with the value of one of the object's attributes acting as the cache key. When loaded, the cache will retrieve all instances of an entity from the store and build a dictionary mapping values for the given cache key attribute to the managed object ID for all objects matching the value. The cache can then be used to quickly retrieve objects by attribute value for the cache key without executing another fetch request against the managed object context. This can provide a large performance improvement when a large number of objects are being retrieved using a particular attribute as the key. RKEntityByAttributeCache instances are used by the RKEntityCache to provide caching for multiple entities at once. @see RKEntityCache */ @interface RKEntityByAttributeCache : NSObject ///----------------------------------------------------------------------------- /// @name Creating a Cache ///----------------------------------------------------------------------------- /** Initializes the receiver with a given entity, attribute, and managed object context. @param entity The Core Data entity description for the managed objects being cached. @param attributeName The name of an attribute within the cached entity that acts as the cache key. @param managedObjectContext The managed object context the cache retrieves the cached objects from @return The receiver, initialized with the given entity, attribute, and managed object context. */ - (id)initWithEntity:(NSEntityDescription *)entity attribute:(NSString *)attributeName managedObjectContext:(NSManagedObjectContext *)context; ///----------------------------------------------------------------------------- /// @name Getting Cache Identity ///----------------------------------------------------------------------------- /** The Core Data entity description for the managed objects being cached. */ @property (nonatomic, readonly) NSEntityDescription *entity; /** An attribute that is part of the cached entity that acts as the cache key. */ @property (nonatomic, readonly) NSString *attribute; /** The managed object context the receiver fetches cached objects from. */ @property (nonatomic, readonly) NSManagedObjectContext *managedObjectContext; /** A Boolean value determining if the receiever monitors the managed object context for changes and updates the cache entries using the notifications emitted. */ @property (nonatomic, assign) BOOL monitorsContextForChanges; ///----------------------------------------------------------------------------- /// @name Loading and Flushing the Cache ///----------------------------------------------------------------------------- /** Loads the cache by finding all instances of the configured entity and building an association between the value of the cached attribute's value and the managed object ID for the object. */ - (void)load; /** Flushes the cache by releasing all cache attribute value to managed object ID associations. */ - (void)flush; ///----------------------------------------------------------------------------- /// @name Inspecting Cache State ///----------------------------------------------------------------------------- /** A Boolean value indicating if the cache has loaded associations between cache attribute values and managed object ID's. */ - (BOOL)isLoaded; /** Returns a count of the total number of cached objects. */ - (NSUInteger)count; /** Returns the total number of cached objects with a given value for the attribute acting as the cache key. @param attributeValue The value for the cache key attribute to retrieve a count of the objects with a matching value. @return The number of objects in the cache with the given value for the cache attribute of the receiver. */ - (NSUInteger)countWithAttributeValue:(id)attributeValue; /** Returns the number of unique attribute values contained within the receiver. @return The number of unique attribute values within the receiver. */ - (NSUInteger)countOfAttributeValues; /** Returns a Boolean value that indicates whether a given object is present in the cache. @param object An object. @return YES if object is present in the cache, otherwise NO. */ - (BOOL)containsObject:(NSManagedObject *)object; /** Returns a Boolean value that indicates whether one of more objects is present in the cache with a given value of the cache key attribute. @param attributeValue The value with which to check the cache for objects with a matching value. @return YES if one or more objects with the given value for the cache key attribute is present in the cache, otherwise NO. */ - (BOOL)containsObjectWithAttributeValue:(id)attributeValue; /** Returns the first object with a matching value for the cache key attribute. @param attributeValue A value for the cache key attribute. @return An object with the value of attribute matching attributeValue or nil. */ - (NSManagedObject *)objectWithAttributeValue:(id)attributeValue; /** Returns the collection of objects with a matching value for the cache key attribute. @param attributeValue A value for the cache key attribute. @return An array of objects with the value of attribute matching attributeValue or an empty array. */ - (NSArray *)objectsWithAttributeValue:(id)attributeValue; ///----------------------------------------------------------------------------- /// @name Managing Cached Objects ///----------------------------------------------------------------------------- /** Adds a managed object to the cache. The object must be an instance of the cached entity. @param object The managed object to add to the cache. */ - (void)addObject:(NSManagedObject *)object; /** Removes a managed object from the cache. The object must be an instance of the cached entity. @param object The managed object to remove from the cache. */ - (void)removeObject:(NSManagedObject *)object; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKEntityByAttributeCache.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKEntityByAttributeCache.m
// // RKEntityByAttributeCache.m // RestKit // // Created by Blake Watters on 5/1/12. // Copyright (c) 2012 RestKit. All rights reserved. // #if TARGET_OS_IPHONE #import <UIKit/UIKit.h> #endif #import "RKEntityByAttributeCache.h" #import "RKLog.h" #import "RKObjectPropertyInspector.h" #import "RKObjectPropertyInspector+CoreData.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreDataCache @interface RKEntityByAttributeCache () @property (nonatomic, retain) NSMutableDictionary *attributeValuesToObjectIDs; @end @implementation RKEntityByAttributeCache @synthesize entity = _entity; @synthesize attribute = _attribute; @synthesize managedObjectContext = _managedObjectContext; @synthesize attributeValuesToObjectIDs = _attributeValuesToObjectIDs; @synthesize monitorsContextForChanges = _monitorsContextForChanges; - (id)initWithEntity:(NSEntityDescription *)entity attribute:(NSString *)attributeName managedObjectContext:(NSManagedObjectContext *)context { self = [self init]; if (self) { _entity = [entity retain]; _attribute = [attributeName retain]; _managedObjectContext = [context retain]; _monitorsContextForChanges = YES; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(managedObjectContextDidChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:context]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(managedObjectContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:context]; #if TARGET_OS_IPHONE [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; #endif } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [_entity release]; [_attribute release]; [_managedObjectContext release]; [_attributeValuesToObjectIDs release]; [super dealloc]; } - (NSUInteger)count { return [[[self.attributeValuesToObjectIDs allValues] valueForKeyPath:@"@sum.@count"] integerValue]; } - (NSUInteger)countOfAttributeValues { return [self.attributeValuesToObjectIDs count]; } - (NSUInteger)countWithAttributeValue:(id)attributeValue { return [[self objectsWithAttributeValue:attributeValue] count]; } - (BOOL)shouldCoerceAttributeToString:(NSString *)attributeValue { if ([attributeValue isKindOfClass:[NSString class]] || [attributeValue isEqual:[NSNull null]]) { return NO; } Class attributeType = [[RKObjectPropertyInspector sharedInspector] typeForProperty:self.attribute ofEntity:self.entity]; return [attributeType instancesRespondToSelector:@selector(stringValue)]; } - (void)load { RKLogDebug(@"Loading entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute); NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; [fetchRequest setEntity:self.entity]; [fetchRequest setResultType:NSManagedObjectIDResultType]; NSError *error = nil; NSArray *objectIDs = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; [fetchRequest release]; if (error) { RKLogError(@"Failed to load entity cache: %@", error); return; } self.attributeValuesToObjectIDs = [NSMutableDictionary dictionaryWithCapacity:[objectIDs count]]; for (NSManagedObjectID *objectID in objectIDs) { NSError *error = nil; NSManagedObject *object = [self.managedObjectContext existingObjectWithID:objectID error:&error]; if (! object && error) { RKLogError(@"Failed to retrieve managed object with ID %@: %@", objectID, error); } [self addObject:object]; } } - (void)flush { RKLogDebug(@"Flushing entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute); self.attributeValuesToObjectIDs = nil; } - (void)reload { [self flush]; [self load]; } - (BOOL)isLoaded { return (self.attributeValuesToObjectIDs != nil); } - (NSManagedObject *)objectWithAttributeValue:(id)attributeValue { NSArray *objects = [self objectsWithAttributeValue:attributeValue]; return ([objects count] > 0) ? [objects objectAtIndex:0] : nil; } - (NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID { /* NOTE: We use existingObjectWithID: as opposed to objectWithID: as objectWithID: can return us a fault that will raise an exception when fired. existingObjectWithID:error: will return nil if the ID has been deleted. objectRegisteredForID: is also an acceptable approach. */ NSError *error = nil; NSManagedObject *object = [self.managedObjectContext existingObjectWithID:objectID error:&error]; if (! object && error) { RKLogError(@"Failed to retrieve managed object with ID %@. Error %@\n%@", objectID, [error localizedDescription], [error userInfo]); return nil; } return object; } - (NSArray *)objectsWithAttributeValue:(id)attributeValue { attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue; NSMutableArray *objectIDs = [self.attributeValuesToObjectIDs objectForKey:attributeValue]; if (objectIDs) { NSMutableArray *objects = [NSMutableArray arrayWithCapacity:[objectIDs count]]; for (NSManagedObjectID *objectID in objectIDs) { NSManagedObject *object = [self objectWithID:objectID]; if (object) [objects addObject:object]; } return objects; } return [NSArray array]; } - (void)addObject:(NSManagedObject *)object { NSAssert([object.entity isEqual:self.entity], @"Cannot add object with entity '%@' to cache with entity of '%@'", [[object entity] name], [self.entity name]); id attributeValue = [object valueForKey:self.attribute]; // Coerce to a string if possible attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue; if (attributeValue) { NSManagedObjectID *objectID = [object objectID]; NSMutableArray *objectIDs = [self.attributeValuesToObjectIDs objectForKey:attributeValue]; if (objectIDs) { if (! [objectIDs containsObject:objectID]) { [objectIDs addObject:objectID]; } } else { objectIDs = [NSMutableArray arrayWithObject:objectID]; } if (nil == self.attributeValuesToObjectIDs) self.attributeValuesToObjectIDs = [NSMutableDictionary dictionary]; [self.attributeValuesToObjectIDs setValue:objectIDs forKey:attributeValue]; } else { RKLogWarning(@"Unable to add object with nil value for attribute '%@': %@", self.attribute, object); } } - (void)removeObject:(NSManagedObject *)object { NSAssert([object.entity isEqual:self.entity], @"Cannot remove object with entity '%@' from cache with entity of '%@'", [[object entity] name], [self.entity name]); id attributeValue = [object valueForKey:self.attribute]; // Coerce to a string if possible attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue; if (attributeValue) { NSManagedObjectID *objectID = [object objectID]; NSMutableArray *objectIDs = [self.attributeValuesToObjectIDs objectForKey:attributeValue]; if (objectIDs && [objectIDs containsObject:objectID]) { [objectIDs removeObject:objectID]; } } else { RKLogWarning(@"Unable to remove object with nil value for attribute '%@': %@", self.attribute, object); } } - (BOOL)containsObjectWithAttributeValue:(id)attributeValue { // Coerce to a string if possible attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue; return [[self objectsWithAttributeValue:attributeValue] count] > 0; } - (BOOL)containsObject:(NSManagedObject *)object { if (! [object.entity isEqual:self.entity]) return NO; id attributeValue = [object valueForKey:self.attribute]; // Coerce to a string if possible attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue; return [[self objectsWithAttributeValue:attributeValue] containsObject:object]; } - (void)managedObjectContextDidChange:(NSNotification *)notification { if (self.monitorsContextForChanges == NO) return; NSDictionary *userInfo = notification.userInfo; NSSet *insertedObjects = [userInfo objectForKey:NSInsertedObjectsKey]; NSSet *updatedObjects = [userInfo objectForKey:NSUpdatedObjectsKey]; NSSet *deletedObjects = [userInfo objectForKey:NSDeletedObjectsKey]; RKLogTrace(@"insertedObjects=%@, updatedObjects=%@, deletedObjects=%@", insertedObjects, updatedObjects, deletedObjects); NSMutableSet *objectsToAdd = [NSMutableSet setWithSet:insertedObjects]; [objectsToAdd unionSet:updatedObjects]; for (NSManagedObject *object in objectsToAdd) { if ([object.entity isEqual:self.entity]) { [self addObject:object]; } } for (NSManagedObject *object in deletedObjects) { if ([object.entity isEqual:self.entity]) { [self removeObject:object]; } } } - (void)managedObjectContextDidSave:(NSNotification *)notification { // After the MOC has been saved, we flush to ensure any temporary // objectID references are converted into permanent ID's on the next load. [self flush]; } - (void)didReceiveMemoryWarning:(NSNotification *)notification { [self flush]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKEntityByAttributeCache.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKEntityCache.h
// // RKEntityCache.h // RestKit // // Created by Blake Watters on 5/2/12. // Copyright (c) 2012 RestKit. All rights reserved. // #import <CoreData/CoreData.h> @class RKEntityByAttributeCache; /** Instances of RKInMemoryEntityCache provide an in-memory caching mechanism for objects in a Core Data managed object context. Managed objects can be cached by attribute for fast retrieval without repeatedly hitting the Core Data persistent store. This can provide a substantial speed advantage over issuing fetch requests in cases where repeated look-ups of the same data are performed using a small set of attributes as the query key. Internally, the cache entries are maintained as references to the NSManagedObjectID of corresponding cached objects. */ @interface RKEntityCache : NSObject ///----------------------------------------------------------------------------- /// @name Initializing the Cache ///----------------------------------------------------------------------------- /** Initializes the receiver with a managed object context containing the entity instances to be cached. @param context The managed object context containing objects to be cached. @returns self, initialized with context. */ - (id)initWithManagedObjectContext:(NSManagedObjectContext *)context; /** The managed object context with which the receiver is associated. */ @property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext; ///----------------------------------------------------------------------------- /// @name Caching Objects by Attribute ///----------------------------------------------------------------------------- /** Caches all instances of an entity using the value for an attribute as the cache key. @param entity The entity to cache all instances of. @param attributeName The attribute to cache the instances by. */ - (void)cacheObjectsForEntity:(NSEntityDescription *)entity byAttribute:(NSString *)attributeName; /** Returns a Boolean value indicating if all instances of an entity have been cached by a given attribute name. @param entity The entity to check the cache status of. @param attributeName The attribute to check the cache status with. @return YES if the cache has been loaded with instances with the given attribute, else NO. */ - (BOOL)isEntity:(NSEntityDescription *)entity cachedByAttribute:(NSString *)attributeName; /** Retrieves the first cached instance of a given entity where the specified attribute matches the given value. @param entity The entity to search the cache for instances of. @param attributeName The attribute to search the cache for matches with. @param attributeValue The value of the attribute to return a match for. @return A matching managed object instance or nil. @raise NSInvalidArgumentException Raised if instances of the entity and attribute have not been cached. */ - (NSManagedObject *)objectForEntity:(NSEntityDescription *)entity withAttribute:(NSString *)attributeName value:(id)attributeValue; /** Retrieves all cached instances of a given entity where the specified attribute matches the given value. @param entity The entity to search the cache for instances of. @param attributeName The attribute to search the cache for matches with. @param attributeValue The value of the attribute to return a match for. @return All matching managed object instances or nil. @raise NSInvalidArgumentException Raised if instances of the entity and attribute have not been cached. */ - (NSArray *)objectsForEntity:(NSEntityDescription *)entity withAttribute:(NSString *)attributeName value:(id)attributeValue; ///----------------------------------------------------------------------------- // @name Accessing Underlying Caches ///----------------------------------------------------------------------------- /** Retrieves the underlying entity attribute cache for a given entity and attribute. @param entity The entity to retrieve the entity attribute cache object for. @param attributeName The attribute to retrieve the entity attribute cache object for. @return The entity attribute cache for the given entity and attribute, or nil if none was found. */ - (RKEntityByAttributeCache *)attributeCacheForEntity:(NSEntityDescription *)entity attribute:(NSString *)attributeName; /** Retrieves all entity attributes caches for a given entity. @param entity The entity to retrieve the collection of entity attribute caches for. @return An array of entity attribute cache objects for the given entity or an empty array if none were found. */ - (NSArray *)attributeCachesForEntity:(NSEntityDescription *)entity; ///----------------------------------------------------------------------------- // @name Managing the Cache ///----------------------------------------------------------------------------- /** Flushes the entity cache by sending a flush message to each entity attribute cache contained within the receiver. @see [RKEntityByAttributeCache flush] */ - (void)flush; /** Adds a given object to all entity attribute caches for the object's entity contained within the receiver. @param object The object to add to the appropriate entity attribute caches. */ - (void)addObject:(NSManagedObject *)object; /** Removed a given object from all entity attribute caches for the object's entity contained within the receiver. @param object The object to remove from the appropriate entity attribute caches. */ - (void)removeObject:(NSManagedObject *)object; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKEntityCache.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKEntityCache.m
// // RKEntityCache.m // RestKit // // Created by Blake Watters on 5/2/12. // Copyright (c) 2012 RestKit. All rights reserved. // #import "RKEntityCache.h" #import "RKEntityByAttributeCache.h" @interface RKEntityCache () @property (nonatomic, retain) NSMutableSet *attributeCaches; @end @implementation RKEntityCache @synthesize managedObjectContext = _managedObjectContext; @synthesize attributeCaches = _attributeCaches; - (id)initWithManagedObjectContext:(NSManagedObjectContext *)context { NSAssert(context, @"Cannot initialize entity cache with a nil context"); self = [super init]; if (self) { _managedObjectContext = [context retain]; _attributeCaches = [[NSMutableSet alloc] init]; } return self; } - (id)init { return [self initWithManagedObjectContext:nil]; } - (void)dealloc { [_managedObjectContext release]; [_attributeCaches release]; [super dealloc]; } - (void)cacheObjectsForEntity:(NSEntityDescription *)entity byAttribute:(NSString *)attributeName { NSAssert(entity, @"Cannot cache objects for a nil entity"); NSAssert(attributeName, @"Cannot cache objects without an attribute"); RKEntityByAttributeCache *attributeCache = [self attributeCacheForEntity:entity attribute:attributeName]; if (attributeCache && !attributeCache.isLoaded) { [attributeCache load]; } else { attributeCache = [[RKEntityByAttributeCache alloc] initWithEntity:entity attribute:attributeName managedObjectContext:self.managedObjectContext]; [attributeCache load]; [self.attributeCaches addObject:attributeCache]; [attributeCache release]; } } - (BOOL)isEntity:(NSEntityDescription *)entity cachedByAttribute:(NSString *)attributeName { NSAssert(entity, @"Cannot check cache status for a nil entity"); NSAssert(attributeName, @"Cannot check cache status for a nil attribute"); RKEntityByAttributeCache *attributeCache = [self attributeCacheForEntity:entity attribute:attributeName]; return (attributeCache && attributeCache.isLoaded); } - (NSManagedObject *)objectForEntity:(NSEntityDescription *)entity withAttribute:(NSString *)attributeName value:(id)attributeValue { NSAssert(entity, @"Cannot retrieve cached objects with a nil entity"); NSAssert(attributeName, @"Cannot retrieve cached objects by a nil entity"); RKEntityByAttributeCache *attributeCache = [self attributeCacheForEntity:entity attribute:attributeName]; if (attributeCache) { return [attributeCache objectWithAttributeValue:attributeValue]; } return nil; } - (NSArray *)objectsForEntity:(NSEntityDescription *)entity withAttribute:(NSString *)attributeName value:(id)attributeValue { NSAssert(entity, @"Cannot retrieve cached objects with a nil entity"); NSAssert(attributeName, @"Cannot retrieve cached objects by a nil entity"); RKEntityByAttributeCache *attributeCache = [self attributeCacheForEntity:entity attribute:attributeName]; if (attributeCache) { return [attributeCache objectsWithAttributeValue:attributeValue]; } return [NSSet set]; } - (RKEntityByAttributeCache *)attributeCacheForEntity:(NSEntityDescription *)entity attribute:(NSString *)attributeName { NSAssert(entity, @"Cannot retrieve attribute cache for a nil entity"); NSAssert(attributeName, @"Cannot retrieve attribute cache for a nil attribute"); for (RKEntityByAttributeCache *cache in self.attributeCaches) { if ([cache.entity isEqual:entity] && [cache.attribute isEqualToString:attributeName]) { return cache; } } return nil; } - (NSSet *)attributeCachesForEntity:(NSEntityDescription *)entity { NSAssert(entity, @"Cannot retrieve attribute caches for a nil entity"); NSMutableSet *set = [NSMutableSet set]; for (RKEntityByAttributeCache *cache in self.attributeCaches) { if ([cache.entity isEqual:entity]) { [set addObject:cache]; } } return [NSSet setWithSet:set]; } - (void)flush { [self.attributeCaches makeObjectsPerformSelector:@selector(flush)]; } - (void)addObject:(NSManagedObject *)object { NSAssert(object, @"Cannot add a nil object to the cache"); NSArray *attributeCaches = [self attributeCachesForEntity:object.entity]; for (RKEntityByAttributeCache *cache in attributeCaches) { [cache addObject:object]; } } - (void)removeObject:(NSManagedObject *)object { NSAssert(object, @"Cannot remove a nil object from the cache"); NSArray *attributeCaches = [self attributeCachesForEntity:object.entity]; for (RKEntityByAttributeCache *cache in attributeCaches) { [cache removeObject:object]; } } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKEntityCache.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.h
// // RKFetchRequestManagedObjectCache.h // RestKit // // Created by Jeff Arena on 1/24/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKManagedObjectCaching.h" /** Provides a simple managed object cache strategy in which every request for an object is satisfied by dispatching an NSFetchRequest against the Core Data persistent store. Performance can be disappointing for data sets with a large amount of redundant data being mapped and connected together, but the memory footprint stays flat. */ @interface RKFetchRequestManagedObjectCache : NSObject <RKManagedObjectCaching> @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKFetchRequestManagedObjectCache.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.m
// // RKFetchRequestMappingCache.m // RestKit // // Created by Jeff Arena on 1/24/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKFetchRequestManagedObjectCache.h" #import "NSManagedObject+ActiveRecord.h" #import "NSEntityDescription+RKAdditions.h" #import "RKLog.h" #import "RKObjectPropertyInspector.h" #import "RKObjectPropertyInspector+CoreData.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData @implementation RKFetchRequestManagedObjectCache - (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute value:(id)primaryKeyValue inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext { NSAssert(entity, @"Cannot find existing managed object without a target class"); NSAssert(primaryKeyAttribute, @"Cannot find existing managed object instance without mapping that defines a primaryKeyAttribute"); NSAssert(primaryKeyValue, @"Cannot find existing managed object by primary key without a value"); NSAssert(managedObjectContext, @"Cannot find existing managed object with a context"); id searchValue = primaryKeyValue; Class type = [[RKObjectPropertyInspector sharedInspector] typeForProperty:primaryKeyAttribute ofEntity:entity]; if (type && ([type isSubclassOfClass:[NSString class]] && NO == [primaryKeyValue isKindOfClass:[NSString class]])) { searchValue = [NSString stringWithFormat:@"%@", primaryKeyValue]; } else if (type && ([type isSubclassOfClass:[NSNumber class]] && NO == [primaryKeyValue isKindOfClass:[NSNumber class]])) { if ([primaryKeyValue isKindOfClass:[NSString class]]) { searchValue = [NSNumber numberWithDouble:[(NSString *)primaryKeyValue doubleValue]]; } } // Use cached predicate if primary key matches NSPredicate *predicate = nil; if ([entity.primaryKeyAttributeName isEqualToString:primaryKeyAttribute]) { predicate = [entity predicateForPrimaryKeyAttributeWithValue:searchValue]; } else { // Parse a predicate predicate = [NSPredicate predicateWithFormat:@"%K = %@", primaryKeyAttribute, searchValue]; } NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; fetchRequest.entity = entity; fetchRequest.fetchLimit = 1; fetchRequest.predicate = predicate; NSArray *objects = [NSManagedObject executeFetchRequest:fetchRequest inContext:managedObjectContext]; RKLogDebug(@"Found objects '%@' using fetchRequest '%@'", objects, fetchRequest); [fetchRequest release]; NSManagedObject *object = nil; if ([objects count] > 0) { object = [objects objectAtIndex:0]; } return object; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKFetchRequestManagedObjectCache.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKInMemoryManagedObjectCache.h
// // RKInMemoryManagedObjectCache.h // RestKit // // Created by Jeff Arena on 1/24/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKManagedObjectCaching.h" /** Provides a fast managed object cache where-in object instances are retained in memory to avoid hitting the Core Data persistent store. Performance is greatly increased over fetch request based strategy at the expense of memory consumption. */ @interface RKInMemoryManagedObjectCache : NSObject <RKManagedObjectCaching> @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKInMemoryManagedObjectCache.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKInMemoryManagedObjectCache.m
// // RKInMemoryManagedObjectCache.m // RestKit // // Created by Jeff Arena on 1/24/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKInMemoryManagedObjectCache.h" #import "NSEntityDescription+RKAdditions.h" #import "RKEntityCache.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData static NSString * const RKInMemoryObjectManagedObjectCacheThreadDictionaryKey = @"RKInMemoryObjectManagedObjectCacheThreadDictionaryKey"; @implementation RKInMemoryManagedObjectCache - (RKEntityCache *)cacheForEntity:(NSEntityDescription *)entity inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext { NSAssert(entity, @"Cannot find existing managed object without a target class"); NSAssert(managedObjectContext, @"Cannot find existing managed object with a context"); NSMutableDictionary *contextDictionary = [[[NSThread currentThread] threadDictionary] objectForKey:RKInMemoryObjectManagedObjectCacheThreadDictionaryKey]; if (! contextDictionary) { contextDictionary = [NSMutableDictionary dictionaryWithCapacity:1]; [[[NSThread currentThread] threadDictionary] setObject:contextDictionary forKey:RKInMemoryObjectManagedObjectCacheThreadDictionaryKey]; } NSNumber *hashNumber = [NSNumber numberWithUnsignedInteger:[managedObjectContext hash]]; RKEntityCache *entityCache = [contextDictionary objectForKey:hashNumber]; if (! entityCache) { RKLogInfo(@"Creating thread-local entity cache for managed object context: %@", managedObjectContext); entityCache = [[RKEntityCache alloc] initWithManagedObjectContext:managedObjectContext]; [contextDictionary setObject:entityCache forKey:hashNumber]; [entityCache release]; } return entityCache; } - (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute value:(id)primaryKeyValue inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext { RKEntityCache *entityCache = [self cacheForEntity:entity inManagedObjectContext:managedObjectContext]; if (! [entityCache isEntity:entity cachedByAttribute:primaryKeyAttribute]) { RKLogInfo(@"Caching instances of Entity '%@' by primary key attribute '%@'", entity.name, primaryKeyAttribute); [entityCache cacheObjectsForEntity:entity byAttribute:primaryKeyAttribute]; RKEntityByAttributeCache *attributeCache = [entityCache attributeCacheForEntity:entity attribute:primaryKeyAttribute]; RKLogTrace(@"Cached %ld objects", (long) [attributeCache count]); } return [entityCache objectForEntity:entity withAttribute:primaryKeyAttribute value:primaryKeyValue]; } - (void)didFetchObject:(NSManagedObject *)object { RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext]; [entityCache addObject:object]; } - (void)didCreateObject:(NSManagedObject *)object { RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext]; [entityCache addObject:object]; } - (void)didDeleteObject:(NSManagedObject *)object { RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext]; [entityCache removeObject:object]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKInMemoryManagedObjectCache.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectCaching.h
// // RKManagedObjectCaching.h // RestKit // // Created by Jeff Arena on 1/24/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <CoreData/CoreData.h> /** Objects implementing the RKManagedObjectCaching protocol can act as the cache strategy for RestKit managed object stores. The managed object cache is consulted when objects are retrieved from Core Data during object mapping operations and provide an opportunity to accelerate the mapping process by trading memory for speed. */ @protocol RKManagedObjectCaching @required /** Retrieves a model object from the object store given a Core Data entity and the primary key attribute and value for the desired object. @param entity The Core Data entity for the type of object to be retrieved from the cache. @param primaryKeyAttribute The name of the attribute that acts as the primary key for the entity. @param primaryKeyValue The value for the primary key attribute of the object to be retrieved from the cache. @param mmanagedObjectContext The managed object context to be searched for a matching instance. @return A managed object that is an instance of the given entity with a primary key and value matching the specified parameters, or nil if no object was found. */ - (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute value:(id)primaryKeyValue inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext; @optional /** Tells the receiver that an object was fetched and should be added to the cache. @param object The object that was fetched from a managed object context. */ - (void)didFetchObject:(NSManagedObject *)object; /** Tells the receiver that an object was created and should be added to the cache. @param object The object that was created in a managed object context. */ - (void)didCreateObject:(NSManagedObject *)object; /** Tells the receiver that an object was deleted and should be removed to the cache. @param object The object that was deleted from a managed object context. */ - (void)didDeleteObject:(NSManagedObject *)object; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectCaching.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectLoader.h
// // RKManagedObjectLoader.h // RestKit // // Created by Blake Watters on 2/13/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectLoader.h" #import "RKManagedObjectStore.h" /** A subclass of the object loader that is dispatched when you are loading Core Data managed objects. This differs from the transient object loader only by handling the special threading concerns imposed by Core Data. */ @interface RKManagedObjectLoader : RKObjectLoader { RKManagedObjectStore *_objectStore; NSManagedObjectID* _targetObjectID; NSMutableSet* _managedObjectKeyPaths; BOOL _deleteObjectOnFailure; } /** A reference to a RestKit managed object store for interacting with Core Data @see RKManagedObjectStore */ @property (nonatomic, retain) RKManagedObjectStore* objectStore; + (id)loaderWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider objectStore:(RKManagedObjectStore *)objectStore; - (id)initWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider objectStore:(RKManagedObjectStore *)objectStore; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectLoader.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectLoader.m
// // RKManagedObjectLoader.m // RestKit // // Created by Blake Watters on 2/13/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectManager.h" #import "RKManagedObjectLoader.h" #import "RKURL.h" #import "RKObjectMapper.h" #import "RKManagedObjectThreadSafeInvocation.h" #import "NSManagedObject+ActiveRecord.h" #import "RKObjectLoader_Internals.h" #import "RKRequest_Internals.h" #import "RKObjectMappingProvider+CoreData.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData @implementation RKManagedObjectLoader @synthesize objectStore = _objectStore; + (id)loaderWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider objectStore:(RKManagedObjectStore *)objectStore { return [[[self alloc] initWithURL:URL mappingProvider:mappingProvider objectStore:objectStore] autorelease]; } - (id)initWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider objectStore:(RKManagedObjectStore *)objectStore { self = [self initWithURL:URL mappingProvider:mappingProvider]; if (self) { _objectStore = [objectStore retain]; } return self; } - (id)initWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider { self = [super initWithURL:URL mappingProvider:mappingProvider]; if (self) { _managedObjectKeyPaths = [[NSMutableSet alloc] init]; } return self; } - (void)dealloc { [_targetObjectID release]; _targetObjectID = nil; _deleteObjectOnFailure = NO; [_managedObjectKeyPaths release]; [_objectStore release]; [super dealloc]; } - (void)reset { [super reset]; [_targetObjectID release]; _targetObjectID = nil; } #pragma mark - RKObjectMapperDelegate methods - (void)objectMapper:(RKObjectMapper*)objectMapper didMapFromObject:(id)sourceObject toObject:(id)destinationObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMapping*)objectMapping { if ([destinationObject isKindOfClass:[NSManagedObject class]]) { [_managedObjectKeyPaths addObject:keyPath]; } } #pragma mark - RKObjectLoader overrides // Overload the target object reader to return a thread-local copy of the target object - (id)targetObject { if ([NSThread isMainThread] == NO && _targetObjectID) { return [self.objectStore objectWithID:_targetObjectID]; } return _targetObject; } - (void)setTargetObject:(NSObject*)targetObject { [_targetObject release]; _targetObject = nil; _targetObject = [targetObject retain]; [_targetObjectID release]; _targetObjectID = nil; } - (BOOL)prepareURLRequest { // TODO: Can we just do this if the object hasn't been saved already??? // NOTE: There is an important sequencing issue here. You MUST save the // managed object context before retaining the objectID or you will run // into an error where the object context cannot be saved. We do this // right before send to avoid sequencing issues where the target object is // set before the managed object store. if (self.targetObject && [self.targetObject isKindOfClass:[NSManagedObject class]]) { _deleteObjectOnFailure = [(NSManagedObject*)self.targetObject isNew]; [self.objectStore save:nil]; _targetObjectID = [[(NSManagedObject*)self.targetObject objectID] retain]; } return [super prepareURLRequest]; } - (NSArray *)cachedObjects { NSFetchRequest *fetchRequest = [self.mappingProvider fetchRequestForResourcePath:self.resourcePath]; if (fetchRequest) { return [NSManagedObject objectsWithFetchRequest:fetchRequest]; } return nil; } - (void)deleteCachedObjectsMissingFromResult:(RKObjectMappingResult*)result { if (! [self isGET]) { RKLogDebug(@"Skipping cleanup of objects via managed object cache: only used for GET requests."); return; } if ([self.URL isKindOfClass:[RKURL class]]) { NSArray *results = [result asCollection]; NSArray *cachedObjects = [self cachedObjects]; for (id object in cachedObjects) { if (NO == [results containsObject:object]) { RKLogTrace(@"Deleting orphaned object %@: not found in result set and expected at this resource path", object); [[self.objectStore managedObjectContextForCurrentThread] deleteObject:object]; } } } else { RKLogWarning(@"Unable to perform cleanup of server-side object deletions: unable to determine resource path."); } } // NOTE: We are on the background thread here, be mindful of Core Data's threading needs - (void)processMappingResult:(RKObjectMappingResult*)result { NSAssert(_sentSynchronously || ![NSThread isMainThread], @"Mapping result processing should occur on a background thread"); if (_targetObjectID && self.targetObject && self.method == RKRequestMethodDELETE) { NSManagedObject* backgroundThreadObject = [self.objectStore objectWithID:_targetObjectID]; RKLogInfo(@"Deleting local object %@ due to DELETE request", backgroundThreadObject); [[self.objectStore managedObjectContextForCurrentThread] deleteObject:backgroundThreadObject]; } // If the response was successful, save the store... if ([self.response isSuccessful]) { [self deleteCachedObjectsMissingFromResult:result]; NSError *error = nil; BOOL success = [self.objectStore save:&error]; if (! success) { RKLogError(@"Failed to save managed object context after mapping completed: %@", [error localizedDescription]); NSMethodSignature* signature = [(NSObject *)self methodSignatureForSelector:@selector(informDelegateOfError:)]; RKManagedObjectThreadSafeInvocation* invocation = [RKManagedObjectThreadSafeInvocation invocationWithMethodSignature:signature]; [invocation setTarget:self]; [invocation setSelector:@selector(informDelegateOfError:)]; [invocation setArgument:&error atIndex:2]; [invocation invokeOnMainThread]; dispatch_async(dispatch_get_main_queue(), ^{ [self finalizeLoad:success]; }); return; } } NSDictionary* dictionary = [result asDictionary]; NSMethodSignature* signature = [self methodSignatureForSelector:@selector(informDelegateOfObjectLoadWithResultDictionary:)]; RKManagedObjectThreadSafeInvocation* invocation = [RKManagedObjectThreadSafeInvocation invocationWithMethodSignature:signature]; [invocation setObjectStore:self.objectStore]; [invocation setTarget:self]; [invocation setSelector:@selector(informDelegateOfObjectLoadWithResultDictionary:)]; [invocation setArgument:&dictionary atIndex:2]; [invocation setManagedObjectKeyPaths:_managedObjectKeyPaths forArgument:2]; [invocation invokeOnMainThread]; } // Overloaded to handle deleting an object orphaned by a failed postObject: - (void)handleResponseError { [super handleResponseError]; if (_targetObjectID) { if (_deleteObjectOnFailure) { RKLogInfo(@"Error response encountered: Deleting existing managed object with ID: %@", _targetObjectID); NSManagedObject* objectToDelete = [self.objectStore objectWithID:_targetObjectID]; if (objectToDelete) { [[self.objectStore managedObjectContextForCurrentThread] deleteObject:objectToDelete]; [self.objectStore save:nil]; } else { RKLogWarning(@"Unable to delete existing managed object with ID: %@. Object not found in the store.", _targetObjectID); } } else { RKLogDebug(@"Skipping deletion of existing managed object"); } } } - (BOOL)isResponseMappable { if ([self.response wasLoadedFromCache]) { NSArray* cachedObjects = [self cachedObjects]; if (! cachedObjects) { RKLogDebug(@"Skipping managed object mapping optimization -> Managed object cache returned nil cachedObjects for resourcePath: %@", self.resourcePath); return [super isResponseMappable]; } [self informDelegateOfObjectLoadWithResultDictionary:[NSDictionary dictionaryWithObject:cachedObjects forKey:@""]]; return NO; } return [super isResponseMappable]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectLoader.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectMapping.h
// // RKManagedObjectMapping.h // RestKit // // Created by Blake Watters on 5/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <CoreData/CoreData.h> #import "RKObjectMapping.h" //#import "RKManagedObjectStore.h" @class RKManagedObjectStore; /** An RKManagedObjectMapping defines an object mapping with a Core Data destination entity. */ @interface RKManagedObjectMapping : RKObjectMapping { NSEntityDescription *_entity; NSString *_primaryKeyAttribute; NSMutableDictionary *_relationshipToPrimaryKeyMappings; } /** Creates a new object mapping targetting the Core Data entity represented by objectClass */ + (id)mappingForClass:(Class)objectClass inManagedObjectStore:(RKManagedObjectStore *)objectStore; /** Creates a new object mapping targetting the specified Core Data entity */ + (RKManagedObjectMapping *)mappingForEntity:(NSEntityDescription *)entity inManagedObjectStore:(RKManagedObjectStore *)objectStore; /** Creates a new object mapping targetting the Core Data entity with the specified name. The entity description is fetched from the managed object context associated with objectStore */ + (RKManagedObjectMapping *)mappingForEntityWithName:(NSString *)entityName inManagedObjectStore:(RKManagedObjectStore *)objectStore; /** The Core Data entity description used for this object mapping */ @property (nonatomic, readonly) NSEntityDescription *entity; /** The name of the attribute on the destination entity that acts as the primary key for instances of the entity in the remote backend system. Used to uniquely identify objects within the store so that existing objects are updated rather than creating new ones. @warning Note that primaryKeyAttribute defaults to the primaryKeyAttribute configured on the NSEntityDescription for the entity targetted by the receiving mapping. This provides flexibility in cases where a single entity is the target of many mappings with differing primary key definitions. If the primaryKeyAttribute is set on an RKManagedObjectMapping that targets an entity with a nil primaryKeyAttribute, then the primaryKeyAttribute will be set on the entity as well for convenience and backwards compatibility. This may change in the future. @see [NSEntityDescription primaryKeyAttribute] */ @property (nonatomic, retain) NSString *primaryKeyAttribute; /** Returns a dictionary containing Core Data relationships and attribute pairs containing the primary key for */ @property (nonatomic, readonly) NSDictionary *relationshipsAndPrimaryKeyAttributes; /** The RKManagedObjectStore containing the Core Data entity being mapped */ @property (nonatomic, readonly) RKManagedObjectStore *objectStore; /** Instructs RestKit to automatically connect a relationship of the object being mapped by looking up the related object by primary key. For example, given a Project object associated with a User, where the 'user' relationship is specified by a userID property on the managed object: [mapping connectRelationship:@"user" withObjectForPrimaryKeyAttribute:@"userID"]; Will hydrate the 'user' association on the managed object with the object in the local object graph having the primary key specified in the managed object's userID property. In effect, this approach allows foreign key relationships between managed objects to be automatically maintained from the server to the underlying Core Data object graph. */ - (void)connectRelationship:(NSString *)relationshipName withObjectForPrimaryKeyAttribute:(NSString *)primaryKeyAttribute; /** Connects relationships using the primary key values contained in the specified attribute. This method is a short-cut for repeated invocation of `connectRelationship:withObjectForPrimaryKeyAttribute:`. @see connectRelationship:withObjectForPrimaryKeyAttribute: */ - (void)connectRelationshipsWithObjectsForPrimaryKeyAttributes:(NSString *)firstRelationshipName, ... NS_REQUIRES_NIL_TERMINATION; /** Conditionally connect a relationship of the object being mapped when the object being mapped has keyPath equal to a specified value. For example, given a Project object associated with a User, where the 'admin' relationship is specified by a adminID property on the managed object: [mapping connectRelationship:@"admin" withObjectForPrimaryKeyAttribute:@"adminID" whenValueOfKeyPath:@"userType" isEqualTo:@"Admin"]; Will hydrate the 'admin' association on the managed object with the object in the local object graph having the primary key specified in the managed object's userID property. Note that this connection will only occur when the Product's 'userType' property equals 'Admin'. In cases where no match occurs, the relationship connection is skipped. @see connectRelationship:withObjectForPrimaryKeyAttribute: */ - (void)connectRelationship:(NSString *)relationshipName withObjectForPrimaryKeyAttribute:(NSString *)primaryKeyAttribute whenValueOfKeyPath:(NSString *)keyPath isEqualTo:(id)value; /** Conditionally connect a relationship of the object being mapped when the object being mapped has block evaluate to YES. This variant is useful in cases where you want to execute an arbitrary block to determine whether or not to connect a relationship. For example, given a Project object associated with a User, where the 'admin' relationship is specified by a adminID property on the managed object: [mapping connectRelationship:@"admin" withObjectForPrimaryKeyAttribute:@"adminID" usingEvaluationBlock:^(id data) { return [User isAuthenticated]; }]; Will hydrate the 'admin' association on the managed object with the object in the local object graph having the primary key specified in the managed object's userID property. Note that this connection will only occur when the provided block evalutes to YES. In cases where no match occurs, the relationship connection is skipped. @see connectRelationship:withObjectForPrimaryKeyAttribute: */ - (void)connectRelationship:(NSString *)relationshipName withObjectForPrimaryKeyAttribute:(NSString *)primaryKeyAttribute usingEvaluationBlock:(BOOL (^)(id data))block; /** Initialize a managed object mapping with a Core Data entity description and a RestKit managed object store */ - (id)initWithEntity:(NSEntityDescription *)entity inManagedObjectStore:(RKManagedObjectStore *)objectStore; /** Returns the default value for the specified attribute as expressed in the Core Data entity definition. This value will be assigned if the object mapping is applied and a value for a missing attribute is not present in the payload. */ - (id)defaultValueForMissingAttribute:(NSString *)attributeName; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectMapping.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectMapping.m
// // RKManagedObjectMapping.m // RestKit // // Created by Blake Watters on 5/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKManagedObjectMapping.h" #import "NSManagedObject+ActiveRecord.h" #import "RKManagedObjectStore.h" #import "RKDynamicObjectMappingMatcher.h" #import "RKObjectPropertyInspector+CoreData.h" #import "NSEntityDescription+RKAdditions.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData @implementation RKManagedObjectMapping @synthesize entity = _entity; @synthesize primaryKeyAttribute = _primaryKeyAttribute; @synthesize objectStore = _objectStore; + (id)mappingForClass:(Class)objectClass { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"You must provide a managedObjectStore. Invoke mappingForClass:inManagedObjectStore: instead."] userInfo:nil]; } + (id)mappingForClass:(Class)objectClass inManagedObjectStore:(RKManagedObjectStore *)objectStore { return [self mappingForEntityWithName:NSStringFromClass(objectClass) inManagedObjectStore:objectStore]; } + (RKManagedObjectMapping *)mappingForEntity:(NSEntityDescription*)entity inManagedObjectStore:(RKManagedObjectStore *)objectStore { return [[[self alloc] initWithEntity:entity inManagedObjectStore:objectStore] autorelease]; } + (RKManagedObjectMapping *)mappingForEntityWithName:(NSString*)entityName inManagedObjectStore:(RKManagedObjectStore *)objectStore { return [self mappingForEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:objectStore.primaryManagedObjectContext] inManagedObjectStore:objectStore]; } - (id)initWithEntity:(NSEntityDescription*)entity inManagedObjectStore:(RKManagedObjectStore*)objectStore { NSAssert(entity, @"Cannot initialize an RKManagedObjectMapping without an entity. Maybe you want RKObjectMapping instead?"); NSAssert(objectStore, @"Object store cannot be nil"); Class objectClass = NSClassFromString([entity managedObjectClassName]); NSAssert(objectClass, @"The managedObjectClass for an object mapped entity cannot be nil."); self = [self init]; if (self) { _objectClass = [objectClass retain]; _entity = [entity retain]; _objectStore = objectStore; [self addObserver:self forKeyPath:@"entity" options:NSKeyValueObservingOptionInitial context:nil]; [self addObserver:self forKeyPath:@"primaryKeyAttribute" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:nil]; } return self; } - (id)init { self = [super init]; if (self) { _relationshipToPrimaryKeyMappings = [[NSMutableDictionary alloc] init]; } return self; } - (void)dealloc { [self removeObserver:self forKeyPath:@"entity"]; [self removeObserver:self forKeyPath:@"primaryKeyAttribute"]; [_entity release]; [_relationshipToPrimaryKeyMappings release]; [super dealloc]; } - (NSDictionary*)relationshipsAndPrimaryKeyAttributes { return _relationshipToPrimaryKeyMappings; } - (void)connectRelationship:(NSString*)relationshipName withObjectForPrimaryKeyAttribute:(NSString*)primaryKeyAttribute { NSAssert([_relationshipToPrimaryKeyMappings objectForKey:relationshipName] == nil, @"Cannot add connect relationship %@ by primary key, a mapping already exists.", relationshipName); [_relationshipToPrimaryKeyMappings setObject:primaryKeyAttribute forKey:relationshipName]; } - (void)connectRelationshipsWithObjectsForPrimaryKeyAttributes:(NSString*)firstRelationshipName, ... { va_list args; va_start(args, firstRelationshipName); for (NSString* relationshipName = firstRelationshipName; relationshipName != nil; relationshipName = va_arg(args, NSString*)) { NSString* primaryKeyAttribute = va_arg(args, NSString*); NSAssert(primaryKeyAttribute != nil, @"Cannot connect a relationship without an attribute containing the primary key"); [self connectRelationship:relationshipName withObjectForPrimaryKeyAttribute:primaryKeyAttribute]; // TODO: Raise proper exception here, argument error... } va_end(args); } - (void)connectRelationship:(NSString*)relationshipName withObjectForPrimaryKeyAttribute:(NSString*)primaryKeyAttribute whenValueOfKeyPath:(NSString*)keyPath isEqualTo:(id)value { NSAssert([_relationshipToPrimaryKeyMappings objectForKey:relationshipName] == nil, @"Cannot add connect relationship %@ by primary key, a mapping already exists.", relationshipName); RKDynamicObjectMappingMatcher* matcher = [[RKDynamicObjectMappingMatcher alloc] initWithKey:keyPath value:value primaryKeyAttribute:primaryKeyAttribute]; [_relationshipToPrimaryKeyMappings setObject:matcher forKey:relationshipName]; [matcher release]; } - (void)connectRelationship:(NSString*)relationshipName withObjectForPrimaryKeyAttribute:(NSString*)primaryKeyAttribute usingEvaluationBlock:(BOOL (^)(id data))block { NSAssert([_relationshipToPrimaryKeyMappings objectForKey:relationshipName] == nil, @"Cannot add connect relationship %@ by primary key, a mapping already exists.", relationshipName); RKDynamicObjectMappingMatcher* matcher = [[RKDynamicObjectMappingMatcher alloc] initWithPrimaryKeyAttribute:primaryKeyAttribute evaluationBlock:block]; [_relationshipToPrimaryKeyMappings setObject:matcher forKey:relationshipName]; [matcher release]; } - (id)defaultValueForMissingAttribute:(NSString*)attributeName { NSAttributeDescription *desc = [[self.entity attributesByName] valueForKey:attributeName]; return [desc defaultValue]; } - (id)mappableObjectForData:(id)mappableData { NSAssert(mappableData, @"Mappable data cannot be nil"); id object = nil; id primaryKeyValue = nil; NSString* primaryKeyAttribute; NSEntityDescription* entity = [self entity]; RKObjectAttributeMapping* primaryKeyAttributeMapping = nil; primaryKeyAttribute = [self primaryKeyAttribute]; if (primaryKeyAttribute) { // If a primary key has been set on the object mapping, find the attribute mapping // so that we can extract any existing primary key from the mappable data for (RKObjectAttributeMapping* attributeMapping in self.attributeMappings) { if ([attributeMapping.destinationKeyPath isEqualToString:primaryKeyAttribute]) { primaryKeyAttributeMapping = attributeMapping; break; } } // Get the primary key value out of the mappable data (if any) if ([primaryKeyAttributeMapping isMappingForKeyOfNestedDictionary]) { RKLogDebug(@"Detected use of nested dictionary key as primaryKey attribute..."); primaryKeyValue = [[mappableData allKeys] lastObject]; } else { NSString* keyPathForPrimaryKeyElement = primaryKeyAttributeMapping.sourceKeyPath; if (keyPathForPrimaryKeyElement) { primaryKeyValue = [mappableData valueForKeyPath:keyPathForPrimaryKeyElement]; } else { RKLogWarning(@"Unable to find source attribute for primaryKeyAttribute '%@': unable to find existing object instances by primary key.", primaryKeyAttribute); } } } // If we have found the primary key attribute & value, try to find an existing instance to update if (primaryKeyAttribute && primaryKeyValue && NO == [primaryKeyValue isEqual:[NSNull null]]) { object = [self.objectStore.cacheStrategy findInstanceOfEntity:entity withPrimaryKeyAttribute:primaryKeyAttribute value:primaryKeyValue inManagedObjectContext:[self.objectStore managedObjectContextForCurrentThread]]; if (object && [self.objectStore.cacheStrategy respondsToSelector:@selector(didFetchObject:)]) { [self.objectStore.cacheStrategy didFetchObject:object]; } } if (object == nil) { object = [[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:[_objectStore managedObjectContextForCurrentThread]] autorelease]; if (primaryKeyAttribute && primaryKeyValue && ![primaryKeyValue isEqual:[NSNull null]]) { id coercedPrimaryKeyValue = [entity coerceValueForPrimaryKey:primaryKeyValue]; [object setValue:coercedPrimaryKeyValue forKey:primaryKeyAttribute]; } if ([self.objectStore.cacheStrategy respondsToSelector:@selector(didCreateObject:)]) { [self.objectStore.cacheStrategy didCreateObject:object]; } } return object; } - (Class)classForProperty:(NSString*)propertyName { Class propertyClass = [super classForProperty:propertyName]; if (! propertyClass) { propertyClass = [[RKObjectPropertyInspector sharedInspector] typeForProperty:propertyName ofEntity:self.entity]; } return propertyClass; } /* Allows the primaryKeyAttributeName property on the NSEntityDescription to configure the mapping and vice-versa */ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"entity"]) { if (! self.primaryKeyAttribute) { self.primaryKeyAttribute = [self.entity primaryKeyAttributeName]; } } else if ([keyPath isEqualToString:@"primaryKeyAttribute"]) { if (! self.entity.primaryKeyAttribute) { self.entity.primaryKeyAttributeName = self.primaryKeyAttribute; } } } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectMapping.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectMappingOperation.h
// // RKManagedObjectMappingOperation.h // RestKit // // Created by Blake Watters on 5/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectMappingOperation.h" /** Enhances the object mapping operation process with Core Data specific logic */ @interface RKManagedObjectMappingOperation : RKObjectMappingOperation { } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectMappingOperation.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectMappingOperation.m
// // RKManagedObjectMappingOperation.m // RestKit // // Created by Blake Watters on 5/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKManagedObjectMappingOperation.h" #import "RKManagedObjectMapping.h" #import "NSManagedObject+ActiveRecord.h" #import "RKDynamicObjectMappingMatcher.h" #import "RKManagedObjectCaching.h" #import "RKManagedObjectStore.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData @implementation RKManagedObjectMappingOperation - (void)connectRelationship:(NSString *)relationshipName { NSDictionary* relationshipsAndPrimaryKeyAttributes = [(RKManagedObjectMapping*)self.objectMapping relationshipsAndPrimaryKeyAttributes]; id primaryKeyObject = [relationshipsAndPrimaryKeyAttributes objectForKey:relationshipName]; NSString* primaryKeyAttribute = nil; if ([primaryKeyObject isKindOfClass:[RKDynamicObjectMappingMatcher class]]) { RKLogTrace(@"Found a dynamic matcher attempting to connect relationshipName: %@", relationshipName); RKDynamicObjectMappingMatcher* matcher = (RKDynamicObjectMappingMatcher*)primaryKeyObject; if ([matcher isMatchForData:self.destinationObject]) { primaryKeyAttribute = matcher.primaryKeyAttribute; RKLogTrace(@"Dynamic matched succeeded. Proceeding to connect relationshipName '%@' using primaryKeyAttribute '%@'", relationshipName, primaryKeyAttribute); } else { RKLogTrace(@"Dynamic matcher match failed. Skipping connection of relationshipName: %@", relationshipName); return; } } else if ([primaryKeyObject isKindOfClass:[NSString class]]) { primaryKeyAttribute = (NSString*)primaryKeyObject; } NSAssert(primaryKeyAttribute, @"Cannot connect relationship without primaryKeyAttribute"); RKObjectRelationshipMapping* relationshipMapping = [self.objectMapping mappingForRelationship:relationshipName]; RKObjectMappingDefinition *mapping = relationshipMapping.mapping; NSAssert(mapping, @"Attempted to connect relationship for keyPath '%@' without a relationship mapping defined."); if (! [mapping isKindOfClass:[RKObjectMapping class]]) { RKLogWarning(@"Can only connect relationships for RKObjectMapping relationships. Found %@: Skipping...", NSStringFromClass([mapping class])); return; } RKManagedObjectMapping *objectMapping = (RKManagedObjectMapping *) mapping; NSAssert(relationshipMapping, @"Unable to find relationship mapping '%@' to connect by primaryKey", relationshipName); NSAssert([relationshipMapping isKindOfClass:[RKObjectRelationshipMapping class]], @"Expected mapping for %@ to be a relationship mapping", relationshipName); NSAssert([relationshipMapping.mapping isKindOfClass:[RKManagedObjectMapping class]], @"Can only connect RKManagedObjectMapping relationships"); NSString* primaryKeyAttributeOfRelatedObject = [(RKManagedObjectMapping*)objectMapping primaryKeyAttribute]; NSAssert(primaryKeyAttributeOfRelatedObject, @"Cannot connect relationship: mapping for %@ has no primary key attribute specified", NSStringFromClass(objectMapping.objectClass)); id valueOfLocalPrimaryKeyAttribute = [self.destinationObject valueForKey:primaryKeyAttribute]; if (valueOfLocalPrimaryKeyAttribute) { id relatedObject = nil; if ([valueOfLocalPrimaryKeyAttribute conformsToProtocol:@protocol(NSFastEnumeration)]) { RKLogTrace(@"Connecting has-many relationship at keyPath '%@' to object with primaryKey attribute '%@'", relationshipName, primaryKeyAttributeOfRelatedObject); // Implemented for issue 284 - https://github.com/RestKit/RestKit/issues/284 relatedObject = [NSMutableSet set]; NSObject<RKManagedObjectCaching> *cache = [[(RKManagedObjectMapping*)[self objectMapping] objectStore] cacheStrategy]; for (id foreignKey in valueOfLocalPrimaryKeyAttribute) { id searchResult = [cache findInstanceOfEntity:objectMapping.entity withPrimaryKeyAttribute:primaryKeyAttributeOfRelatedObject value:foreignKey inManagedObjectContext:[[(RKManagedObjectMapping*)[self objectMapping] objectStore] managedObjectContextForCurrentThread]]; if (searchResult) { [relatedObject addObject:searchResult]; } } } else { RKLogTrace(@"Connecting has-one relationship at keyPath '%@' to object with primaryKey attribute '%@'", relationshipName, primaryKeyAttributeOfRelatedObject); // Normal foreign key NSObject<RKManagedObjectCaching> *cache = [[(RKManagedObjectMapping*)[self objectMapping] objectStore] cacheStrategy]; relatedObject = [cache findInstanceOfEntity:objectMapping.entity withPrimaryKeyAttribute:primaryKeyAttributeOfRelatedObject value:valueOfLocalPrimaryKeyAttribute inManagedObjectContext:[self.destinationObject managedObjectContext]]; } if (relatedObject) { RKLogDebug(@"Connected relationship '%@' to object with primary key value '%@': %@", relationshipName, valueOfLocalPrimaryKeyAttribute, relatedObject); } else { RKLogDebug(@"Failed to find instance of '%@' to connect relationship '%@' with primary key value '%@'", [[objectMapping entity] name], relationshipName, valueOfLocalPrimaryKeyAttribute); } if ([relatedObject isKindOfClass:[NSManagedObject class]]) { // Sanity check the managed object contexts NSAssert([[(NSManagedObject *)self.destinationObject managedObjectContext] isEqual:[(NSManagedObject *)relatedObject managedObjectContext]], nil); } RKLogTrace(@"setValue of %@ forKeyPath %@", relatedObject, relationshipName); [self.destinationObject setValue:relatedObject forKeyPath:relationshipName]; } else { RKLogTrace(@"Failed to find primary key value for attribute '%@'", primaryKeyAttribute); } } - (void)connectRelationships { NSDictionary* relationshipsAndPrimaryKeyAttributes = [(RKManagedObjectMapping *)self.objectMapping relationshipsAndPrimaryKeyAttributes]; RKLogTrace(@"relationshipsAndPrimaryKeyAttributes: %@", relationshipsAndPrimaryKeyAttributes); for (NSString* relationshipName in relationshipsAndPrimaryKeyAttributes) { if (self.queue) { RKLogTrace(@"Enqueueing relationship connection using operation queue"); __block RKManagedObjectMappingOperation *selfRef = self; [self.queue addOperationWithBlock:^{ [selfRef connectRelationship:relationshipName]; }]; } else { [self connectRelationship:relationshipName]; } } } - (BOOL)performMapping:(NSError **)error { BOOL success = [super performMapping:error]; if ([self.objectMapping isKindOfClass:[RKManagedObjectMapping class]]) { /** NOTE: Processing the pending changes here ensures that the managed object context generates observable callbacks that are important for maintaining any sort of cache that is consistent within a single object mapping operation. As the MOC is only saved when the aggregate operation is processed, we must manually invoke processPendingChanges to prevent recreating objects with the same primary key. See https://github.com/RestKit/RestKit/issues/661 */ [self connectRelationships]; } return success; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectMappingOperation.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectSearchEngine.h
// // RKManagedObjectSearchEngine.h // RestKit // // Created by Jeff Arena on 3/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKSearchEngine.h" @interface RKManagedObjectSearchEngine : NSObject { RKSearchMode _mode; } /** * The type of searching to perform. Can be either RKSearchModeAnd or RKSearchModeOr. * * Defaults to RKSearchModeOr */ @property (nonatomic, assign) RKSearchMode mode; /** * Construct a new search engine */ + (id)searchEngine; /** * Normalize and tokenize the provided string into an NSArray. * Note that returned value may contain entries of empty strings. */ + (NSArray*)tokenizedNormalizedString:(NSString*)string; /** * Generate a predicate for the supplied search term against * searchableAttributes (defined for an RKSearchableManagedObject) */ - (NSPredicate*)predicateForSearch:(NSString*)searchText; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectSearchEngine.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectSearchEngine.m
// // RKManagedObjectSearchEngine.m // RestKit // // Created by Jeff Arena on 3/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKManagedObjectSearchEngine.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData @implementation RKManagedObjectSearchEngine static NSMutableCharacterSet* __removeSet; @synthesize mode = _mode; + (id)searchEngine { RKManagedObjectSearchEngine* searchEngine = [[[RKManagedObjectSearchEngine alloc] init] autorelease]; return searchEngine; } - (id)init { if (self = [super init]) { _mode = RKSearchModeOr; } return self; } #pragma mark - #pragma mark Private - (NSPredicate*)predicateForSearch:(NSArray*)searchTerms compoundSelector:(SEL)selector { NSMutableArray* termPredicates = [NSMutableArray array]; for (NSString* searchTerm in searchTerms) { [termPredicates addObject: [NSPredicate predicateWithFormat:@"(ANY searchWords.word beginswith %@)", searchTerm]]; } return [NSCompoundPredicate performSelector:selector withObject:termPredicates]; } #pragma mark - #pragma mark Public + (NSArray*)tokenizedNormalizedString:(NSString*)string { if (__removeSet == nil) { NSMutableCharacterSet* removeSet = [[NSCharacterSet alphanumericCharacterSet] mutableCopy]; [removeSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]; [removeSet invert]; __removeSet = removeSet; } NSString* scannerString = [[[[string lowercaseString] decomposedStringWithCanonicalMapping] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] stringByReplacingOccurrencesOfString:@"-" withString:@" "]; NSArray* tokens = [[[scannerString componentsSeparatedByCharactersInSet:__removeSet] componentsJoinedByString:@""] componentsSeparatedByString:@" "]; return tokens; } - (NSPredicate*)predicateForSearch:(NSString*)searchText { NSString* searchQuery = [searchText copy]; NSArray* searchTerms = [RKManagedObjectSearchEngine tokenizedNormalizedString:searchQuery]; [searchQuery release]; if ([searchTerms count] == 0) { return nil; } if (_mode == RKSearchModeOr) { return [self predicateForSearch:searchTerms compoundSelector:@selector(orPredicateWithSubpredicates:)]; } else if (_mode == RKSearchModeAnd) { return [self predicateForSearch:searchTerms compoundSelector:@selector(andPredicateWithSubpredicates:)]; } else { return nil; } } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectSearchEngine.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectSeeder.h
// // RKManagedObjectSeeder.h // RestKit // // Created by Blake Watters on 3/4/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "ObjectMapping.h" // The default seed database filename. Used when the object store has not been initialized extern NSString* const RKDefaultSeedDatabaseFileName; @protocol RKManagedObjectSeederDelegate @required // Invoked when the seeder creates a new object - (void)didSeedObject:(NSManagedObject*)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 using the supplied object mapping. */ - (void)seedObjectsFromFile:(NSString*)fileName withObjectMapping:(RKObjectMapping*)nilOrObjectMapping; /** * Seed the database with objects from the specified file, from the specified bundle, using the supplied object mapping. */ - (void)seedObjectsFromFile:(NSString *)fileName withObjectMapping:(RKObjectMapping *)nilOrObjectMapping bundle:(NSBundle *)nilOrBundle; /** * Completes a seeding session by persisting the store, outputing an informational message * and exiting the process */ - (void)finalizeSeedingAndExit; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectSeeder.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectSeeder.m
// // RKObjectSeeder.m // RestKit // // Created by Blake Watters on 3/4/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #if TARGET_OS_IPHONE #import <MobileCoreServices/UTType.h> #endif #import "RKManagedObjectSeeder.h" #import "RKManagedObjectStore.h" #import "RKParserRegistry.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData @interface RKManagedObjectSeeder (Private) - (id)initWithObjectManager:(RKObjectManager*)manager; - (void)seedObjectsFromFileNames:(NSArray*)fileNames; @end NSString* const RKDefaultSeedDatabaseFileName = @"RKSeedDatabase.sqlite"; @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 withObjectMapping: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]; // If the user hasn't configured an object store, set one up for them if (nil == _manager.objectStore) { _manager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:RKDefaultSeedDatabaseFileName]; } // Delete any existing persistent store [_manager.objectStore deletePersistentStore]; } 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 withObjectMapping:nil]; } } - (void)seedObjectsFromFile:(NSString*)fileName withObjectMapping:(RKObjectMapping *)nilOrObjectMapping { [self seedObjectsFromFile:fileName withObjectMapping:nilOrObjectMapping bundle:nil]; } - (void)seedObjectsFromFile:(NSString *)fileName withObjectMapping:(RKObjectMapping *)nilOrObjectMapping bundle:(NSBundle *)nilOrBundle { NSError* error = nil; if (nilOrBundle == nil) { nilOrBundle = [NSBundle mainBundle]; } NSString* filePath = [nilOrBundle pathForResource:fileName ofType:nil]; NSString* payload = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error]; if (payload) { NSString* MIMEType = [fileName MIMETypeForPathExtension]; if (MIMEType == nil) { // Default the MIME type to the value of the Accept header if we couldn't detect it... MIMEType = _manager.acceptMIMEType; } id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:MIMEType]; NSAssert1(parser, @"Could not find a parser for the MIME Type '%@'", MIMEType); id parsedData = [parser objectFromString:payload error:&error]; NSAssert(parsedData, @"Cannot perform object load without data for mapping"); RKObjectMappingProvider* mappingProvider = nil; if (nilOrObjectMapping) { mappingProvider = [[RKObjectMappingProvider new] autorelease]; [mappingProvider setMapping:nilOrObjectMapping forKeyPath:@""]; } else { mappingProvider = _manager.mappingProvider; } RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:mappingProvider]; RKObjectMappingResult* result = [mapper performMapping]; if (result == nil) { RKLogError(@"Database seeding from file '%@' failed due to object mapping errors: %@", fileName, mapper.errors); return; } NSArray* mappedObjects = [result asCollection]; NSAssert1([mappedObjects isKindOfClass:[NSArray class]], @"Expected an NSArray of objects, got %@", mappedObjects); // Inform the delegate if (self.delegate) { for (NSManagedObject* object in mappedObjects) { [self.delegate didSeedObject:object fromFile:fileName]; } } RKLogInfo(@"Seeded %lu objects from %@...", (unsigned long) [mappedObjects count], [NSString stringWithFormat:@"%@", fileName]); } else { RKLogError(@"Unable to read file %@: %@", fileName, [error localizedDescription]); } } - (void)finalizeSeedingAndExit { NSError *error = nil; BOOL success = [[_manager objectStore] save:&error]; if (! success) { RKLogError(@"[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]; RKLogInfo(@"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
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectSeeder.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectStore.h
// // RKManagedObjectStore.h // RestKit // // Created by Blake Watters on 9/22/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <CoreData/CoreData.h> #import "RKManagedObjectMapping.h" #import "RKManagedObjectCaching.h" @class RKManagedObjectStore; /** * Notifications */ extern NSString* const RKManagedObjectStoreDidFailSaveNotification; /////////////////////////////////////////////////////////////////// @protocol RKManagedObjectStoreDelegate @optional - (void)managedObjectStore:(RKManagedObjectStore *)objectStore didFailToCreatePersistentStoreCoordinatorWithError:(NSError *)error; - (void)managedObjectStore:(RKManagedObjectStore *)objectStore didFailToDeletePersistentStore:(NSString *)pathToStoreFile error:(NSError *)error; - (void)managedObjectStore:(RKManagedObjectStore *)objectStore didFailToCopySeedDatabase:(NSString *)seedDatabase error:(NSError *)error; - (void)managedObjectStore:(RKManagedObjectStore *)objectStore didFailToSaveContext:(NSManagedObjectContext *)context error:(NSError *)error exception:(NSException *)exception; @end /////////////////////////////////////////////////////////////////// @interface RKManagedObjectStore : NSObject { NSObject<RKManagedObjectStoreDelegate>* _delegate; NSString* _storeFilename; NSString* _pathToStoreFile; NSManagedObjectModel* _managedObjectModel; NSPersistentStoreCoordinator* _persistentStoreCoordinator; } // The delegate for this object store @property (nonatomic, assign) NSObject<RKManagedObjectStoreDelegate>* delegate; // The filename of the database backing this object store @property (nonatomic, readonly) NSString* storeFilename; // The full path to the database backing this object store @property (nonatomic, readonly) NSString* pathToStoreFile; // Core Data @property (nonatomic, readonly) NSManagedObjectModel* managedObjectModel; @property (nonatomic, readonly) NSPersistentStoreCoordinator* persistentStoreCoordinator; ///----------------------------------------------------------------------------- /// @name Accessing the Default Object Store ///----------------------------------------------------------------------------- + (RKManagedObjectStore *)defaultObjectStore; + (void)setDefaultObjectStore:(RKManagedObjectStore *)objectStore; ///----------------------------------------------------------------------------- /// @name Deleting Store Files ///----------------------------------------------------------------------------- /** Deletes the SQLite file backing an RKManagedObjectStore instance at a given path. @param path The complete path to the store file to delete. */ + (void)deleteStoreAtPath:(NSString *)path; /** Deletes the SQLite file backing an RKManagedObjectStore instance with a given filename within the application data directory. @param filename The name of the file within the application data directory backing a managed object store. */ + (void)deleteStoreInApplicationDataDirectoryWithFilename:(NSString *)filename; ///----------------------------------------------------------------------------- /// @name Initializing an Object Store ///----------------------------------------------------------------------------- /** */ @property (nonatomic, retain) NSObject<RKManagedObjectCaching> *cacheStrategy; /** * Initialize a new managed object store with a SQLite database with the filename specified */ + (RKManagedObjectStore*)objectStoreWithStoreFilename:(NSString*)storeFilename; /** * Initialize a new managed object store backed by a SQLite database with the specified filename. * If a seed database name is provided and no existing database is found, initialize the store by * copying the seed database from the main bundle. If the managed object model provided is nil, * all models will be merged from the main bundle for you. */ + (RKManagedObjectStore*)objectStoreWithStoreFilename:(NSString *)storeFilename usingSeedDatabaseName:(NSString *)nilOrNameOfSeedDatabaseInMainBundle managedObjectModel:(NSManagedObjectModel*)nilOrManagedObjectModel delegate:(id)delegate; /** * Initialize a new managed object store backed by a SQLite database with the specified filename, * in the specified directory. If no directory is specified, will use the app's Documents * directory. If a seed database name is provided and no existing database is found, initialize * the store by copying the seed database from the main bundle. If the managed object model * provided is nil, all models will be merged from the main bundle for you. */ + (RKManagedObjectStore*)objectStoreWithStoreFilename:(NSString *)storeFilename inDirectory:(NSString *)directory usingSeedDatabaseName:(NSString *)nilOrNameOfSeedDatabaseInMainBundle managedObjectModel:(NSManagedObjectModel*)nilOrManagedObjectModel delegate:(id)delegate; /** * Initialize a new managed object store with a SQLite database with the filename specified * @deprecated */ - (id)initWithStoreFilename:(NSString*)storeFilename DEPRECATED_ATTRIBUTE; /** * Save the current contents of the managed object store */ - (BOOL)save:(NSError **)error; /** * This deletes and recreates the managed object context and * persistent store, effectively clearing all data */ - (void)deletePersistentStoreUsingSeedDatabaseName:(NSString *)seedFile; - (void)deletePersistentStore; /** * Retrieves a model object from the appropriate context using the objectId */ - (NSManagedObject*)objectWithID:(NSManagedObjectID*)objectID; /** * Retrieves a array of model objects from the appropriate context using * an array of NSManagedObjectIDs */ - (NSArray*)objectsWithIDs:(NSArray*)objectIDs; ///----------------------------------------------------------------------------- /// @name Retrieving Managed Object Contexts ///----------------------------------------------------------------------------- /** Retrieves the Managed Object Context for the main thread that was initialized when the object store was created. */ @property (nonatomic, retain, readonly) NSManagedObjectContext *primaryManagedObjectContext; /** Instantiates a new managed object context */ - (NSManagedObjectContext *)newManagedObjectContext; /* * This returns an appropriate managed object context for this object store. * Because of the intrecacies of how Core Data works across threads it returns * a different NSManagedObjectContext for each thread. */ - (NSManagedObjectContext *)managedObjectContextForCurrentThread; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectStore.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectStore.m
// // RKManagedObjectStore.m // RestKit // // Created by Blake Watters on 9/22/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKManagedObjectStore.h" #import "NSManagedObject+ActiveRecord.h" #import "RKLog.h" #import "RKSearchWordObserver.h" #import "RKObjectPropertyInspector.h" #import "RKObjectPropertyInspector+CoreData.h" #import "RKAlert.h" #import "RKDirectory.h" #import "RKInMemoryManagedObjectCache.h" #import "RKFetchRequestManagedObjectCache.h" #import "NSBundle+RKAdditions.h" #import "NSManagedObjectContext+RKAdditions.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData NSString* const RKManagedObjectStoreDidFailSaveNotification = @"RKManagedObjectStoreDidFailSaveNotification"; static NSString* const RKManagedObjectStoreThreadDictionaryContextKey = @"RKManagedObjectStoreThreadDictionaryContextKey"; static NSString* const RKManagedObjectStoreThreadDictionaryEntityCacheKey = @"RKManagedObjectStoreThreadDictionaryEntityCacheKey"; static RKManagedObjectStore *defaultObjectStore = nil; @interface RKManagedObjectStore () @property (nonatomic, retain, readwrite) NSManagedObjectContext *primaryManagedObjectContext; - (id)initWithStoreFilename:(NSString *)storeFilename inDirectory:(NSString *)nilOrDirectoryPath usingSeedDatabaseName:(NSString *)nilOrNameOfSeedDatabaseInMainBundle managedObjectModel:(NSManagedObjectModel*)nilOrManagedObjectModel delegate:(id)delegate; - (void)createPersistentStoreCoordinator; - (void)createStoreIfNecessaryUsingSeedDatabase:(NSString*)seedDatabase; - (NSManagedObjectContext*)newManagedObjectContext; @end @implementation RKManagedObjectStore @synthesize delegate = _delegate; @synthesize storeFilename = _storeFilename; @synthesize pathToStoreFile = _pathToStoreFile; @synthesize managedObjectModel = _managedObjectModel; @synthesize persistentStoreCoordinator = _persistentStoreCoordinator; @synthesize cacheStrategy = _cacheStrategy; @synthesize primaryManagedObjectContext; + (RKManagedObjectStore *)defaultObjectStore { return defaultObjectStore; } + (void)setDefaultObjectStore:(RKManagedObjectStore *)objectStore { [objectStore retain]; [defaultObjectStore release]; defaultObjectStore = objectStore; [NSManagedObjectContext setDefaultContext:objectStore.primaryManagedObjectContext]; } + (void)deleteStoreAtPath:(NSString *)path { NSURL* storeURL = [NSURL fileURLWithPath:path]; NSError* error = nil; if ([[NSFileManager defaultManager] fileExistsAtPath:storeURL.path]) { if (! [[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error]) { NSAssert(NO, @"Managed object store failed to delete persistent store : %@", error); } } else { RKLogWarning(@"Asked to delete persistent store but no store file exists at path: %@", storeURL.path); } } + (void)deleteStoreInApplicationDataDirectoryWithFilename:(NSString *)filename { NSString *path = [[RKDirectory applicationDataDirectory] stringByAppendingPathComponent:filename]; [self deleteStoreAtPath:path]; } + (RKManagedObjectStore*)objectStoreWithStoreFilename:(NSString*)storeFilename { return [self objectStoreWithStoreFilename:storeFilename usingSeedDatabaseName:nil managedObjectModel:nil delegate:nil]; } + (RKManagedObjectStore*)objectStoreWithStoreFilename:(NSString *)storeFilename usingSeedDatabaseName:(NSString *)nilOrNameOfSeedDatabaseInMainBundle managedObjectModel:(NSManagedObjectModel*)nilOrManagedObjectModel delegate:(id)delegate { return [[[self alloc] initWithStoreFilename:storeFilename inDirectory:nil usingSeedDatabaseName:nilOrNameOfSeedDatabaseInMainBundle managedObjectModel:nilOrManagedObjectModel delegate:delegate] autorelease]; } + (RKManagedObjectStore*)objectStoreWithStoreFilename:(NSString *)storeFilename inDirectory:(NSString *)directory usingSeedDatabaseName:(NSString *)nilOrNameOfSeedDatabaseInMainBundle managedObjectModel:(NSManagedObjectModel*)nilOrManagedObjectModel delegate:(id)delegate { return [[[self alloc] initWithStoreFilename:storeFilename inDirectory:directory usingSeedDatabaseName:nilOrNameOfSeedDatabaseInMainBundle managedObjectModel:nilOrManagedObjectModel delegate:delegate] autorelease]; } - (id)initWithStoreFilename:(NSString*)storeFilename { return [self initWithStoreFilename:storeFilename inDirectory:nil usingSeedDatabaseName:nil managedObjectModel:nil delegate:nil]; } - (id)initWithStoreFilename:(NSString *)storeFilename inDirectory:(NSString *)nilOrDirectoryPath usingSeedDatabaseName:(NSString *)nilOrNameOfSeedDatabaseInMainBundle managedObjectModel:(NSManagedObjectModel*)nilOrManagedObjectModel delegate:(id)delegate { self = [self init]; if (self) { _storeFilename = [storeFilename retain]; if (nilOrDirectoryPath == nil) { // If initializing into Application Data directory, ensure the directory exists nilOrDirectoryPath = [RKDirectory applicationDataDirectory]; [RKDirectory ensureDirectoryExistsAtPath:nilOrDirectoryPath error:nil]; } else { // If path given, caller is responsible for directory's existence BOOL isDir; NSAssert1([[NSFileManager defaultManager] fileExistsAtPath:nilOrDirectoryPath isDirectory:&isDir] && isDir == YES, @"Specified storage directory exists", nilOrDirectoryPath); } _pathToStoreFile = [[nilOrDirectoryPath stringByAppendingPathComponent:_storeFilename] retain]; if (nilOrManagedObjectModel == nil) { // NOTE: allBundles permits Core Data setup in unit tests nilOrManagedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]]; } NSMutableArray* allManagedObjectModels = [NSMutableArray arrayWithObject:nilOrManagedObjectModel]; _managedObjectModel = [[NSManagedObjectModel modelByMergingModels:allManagedObjectModels] retain]; _delegate = delegate; if (nilOrNameOfSeedDatabaseInMainBundle) { [self createStoreIfNecessaryUsingSeedDatabase:nilOrNameOfSeedDatabaseInMainBundle]; } [self createPersistentStoreCoordinator]; self.primaryManagedObjectContext = [[self newManagedObjectContext] autorelease]; _cacheStrategy = [RKInMemoryManagedObjectCache new]; // Ensure there is a search word observer [RKSearchWordObserver sharedObserver]; // Hydrate the defaultObjectStore if (! defaultObjectStore) { [RKManagedObjectStore setDefaultObjectStore:self]; } } return self; } - (void)setThreadLocalObject:(id)value forKey:(id)key { NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary]; NSString *objectStoreKey = [NSString stringWithFormat:@"RKManagedObjectStore_%p", self]; if (! [threadDictionary valueForKey:objectStoreKey]) { [threadDictionary setValue:[NSMutableDictionary dictionary] forKey:objectStoreKey]; } [[threadDictionary objectForKey:objectStoreKey] setObject:value forKey:key]; } - (id)threadLocalObjectForKey:(id)key { NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary]; NSString *objectStoreKey = [NSString stringWithFormat:@"RKManagedObjectStore_%p", self]; if (! [threadDictionary valueForKey:objectStoreKey]) { [threadDictionary setObject:[NSMutableDictionary dictionary] forKey:objectStoreKey]; } return [[threadDictionary objectForKey:objectStoreKey] objectForKey:key]; } - (void)removeThreadLocalObjectForKey:(id)key { NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary]; NSString *objectStoreKey = [NSString stringWithFormat:@"RKManagedObjectStore_%p", self]; if (! [threadDictionary valueForKey:objectStoreKey]) { [threadDictionary setObject:[NSMutableDictionary dictionary] forKey:objectStoreKey]; } [[threadDictionary objectForKey:objectStoreKey] removeObjectForKey:key]; } - (void)clearThreadLocalStorage { // Clear out our Thread local information NSManagedObjectContext *managedObjectContext = [self threadLocalObjectForKey:RKManagedObjectStoreThreadDictionaryContextKey]; if (managedObjectContext) { [self removeThreadLocalObjectForKey:RKManagedObjectStoreThreadDictionaryContextKey]; } if ([self threadLocalObjectForKey:RKManagedObjectStoreThreadDictionaryEntityCacheKey]) { [self removeThreadLocalObjectForKey:RKManagedObjectStoreThreadDictionaryEntityCacheKey]; } } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [self clearThreadLocalStorage]; [_storeFilename release]; _storeFilename = nil; [_pathToStoreFile release]; _pathToStoreFile = nil; [_managedObjectModel release]; _managedObjectModel = nil; [_persistentStoreCoordinator release]; _persistentStoreCoordinator = nil; [_cacheStrategy release]; _cacheStrategy = nil; [primaryManagedObjectContext release]; primaryManagedObjectContext = nil; [super dealloc]; } /** Performs the save action for the application, which is to send the save: message to the application's managed object context. */ - (BOOL)save:(NSError **)error { NSManagedObjectContext* moc = [self managedObjectContextForCurrentThread]; NSError *localError = nil; @try { if (![moc save:&localError]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(managedObjectStore:didFailToSaveContext:error:exception:)]) { [self.delegate managedObjectStore:self didFailToSaveContext:moc error:localError exception:nil]; } NSDictionary* userInfo = [NSDictionary dictionaryWithObject:localError forKey:@"error"]; [[NSNotificationCenter defaultCenter] postNotificationName:RKManagedObjectStoreDidFailSaveNotification object:self userInfo:userInfo]; if ([[localError domain] isEqualToString:@"NSCocoaErrorDomain"]) { NSDictionary *userInfo = [localError userInfo]; NSArray *errors = [userInfo valueForKey:@"NSDetailedErrors"]; if (errors) { for (NSError *detailedError in errors) { NSDictionary *subUserInfo = [detailedError userInfo]; RKLogError(@"Core Data Save Error\n \ NSLocalizedDescription:\t\t%@\n \ NSValidationErrorKey:\t\t\t%@\n \ NSValidationErrorPredicate:\t%@\n \ NSValidationErrorObject:\n%@\n", [subUserInfo valueForKey:@"NSLocalizedDescription"], [subUserInfo valueForKey:@"NSValidationErrorKey"], [subUserInfo valueForKey:@"NSValidationErrorPredicate"], [subUserInfo valueForKey:@"NSValidationErrorObject"]); } } else { RKLogError(@"Core Data Save Error\n \ NSLocalizedDescription:\t\t%@\n \ NSValidationErrorKey:\t\t\t%@\n \ NSValidationErrorPredicate:\t%@\n \ NSValidationErrorObject:\n%@\n", [userInfo valueForKey:@"NSLocalizedDescription"], [userInfo valueForKey:@"NSValidationErrorKey"], [userInfo valueForKey:@"NSValidationErrorPredicate"], [userInfo valueForKey:@"NSValidationErrorObject"]); } } if (error) { *error = localError; } return NO; } } @catch (NSException* e) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(managedObjectStore:didFailToSaveContext:error:exception:)]) { [self.delegate managedObjectStore:self didFailToSaveContext:moc error:nil exception:e]; } else { @throw; } } return YES; } - (NSManagedObjectContext *)newManagedObjectContext { NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] init]; [managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; [managedObjectContext setUndoManager:nil]; [managedObjectContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; managedObjectContext.managedObjectStore = self; return managedObjectContext; } - (void)createStoreIfNecessaryUsingSeedDatabase:(NSString*)seedDatabase { if (NO == [[NSFileManager defaultManager] fileExistsAtPath:self.pathToStoreFile]) { NSString* seedDatabasePath = [[NSBundle mainBundle] pathForResource:seedDatabase ofType:nil]; NSAssert1(seedDatabasePath, @"Unable to find seed database file '%@' in the Main Bundle, aborting...", seedDatabase); RKLogInfo(@"No existing database found, copying from seed path '%@'", seedDatabasePath); NSError* error; if (![[NSFileManager defaultManager] copyItemAtPath:seedDatabasePath toPath:self.pathToStoreFile error:&error]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(managedObjectStore:didFailToCopySeedDatabase:error:)]) { [self.delegate managedObjectStore:self didFailToCopySeedDatabase:seedDatabase error:error]; } else { RKLogError(@"Encountered an error during seed database copy: %@", [error localizedDescription]); } } NSAssert1([[NSFileManager defaultManager] fileExistsAtPath:seedDatabasePath], @"Seed database not found at path '%@'!", seedDatabasePath); } } - (void)createPersistentStoreCoordinator { NSAssert(_managedObjectModel, @"Cannot create persistent store coordinator without a managed object model"); NSAssert(!_persistentStoreCoordinator, @"Cannot create persistent store coordinator: one already exists."); NSURL *storeURL = [NSURL fileURLWithPath:self.pathToStoreFile]; NSError *error; _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel]; // Allow inferred migration from the original version of the application. NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(managedObjectStore:didFailToCreatePersistentStoreCoordinatorWithError:)]) { [self.delegate managedObjectStore:self didFailToCreatePersistentStoreCoordinatorWithError:error]; } else { NSAssert(NO, @"Managed object store failed to create persistent store coordinator: %@", error); } } } - (void)deletePersistentStoreUsingSeedDatabaseName:(NSString *)seedFile { NSURL* storeURL = [NSURL fileURLWithPath:self.pathToStoreFile]; NSError* error = nil; if ([[NSFileManager defaultManager] fileExistsAtPath:storeURL.path]) { if (![[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error]) { if (self.delegate != nil && [self.delegate respondsToSelector:@selector(managedObjectStore:didFailToDeletePersistentStore:error:)]) { [self.delegate managedObjectStore:self didFailToDeletePersistentStore:self.pathToStoreFile error:error]; } else { NSAssert(NO, @"Managed object store failed to delete persistent store : %@", error); } } } else { RKLogWarning(@"Asked to delete persistent store but no store file exists at path: %@", storeURL.path); } [_persistentStoreCoordinator release]; _persistentStoreCoordinator = nil; if (seedFile) { [self createStoreIfNecessaryUsingSeedDatabase:seedFile]; } [self createPersistentStoreCoordinator]; // Recreate the MOC self.primaryManagedObjectContext = [[self newManagedObjectContext] autorelease]; } - (void)deletePersistentStore { [self deletePersistentStoreUsingSeedDatabaseName:nil]; } - (NSManagedObjectContext *)managedObjectContextForCurrentThread { if ([NSThread isMainThread]) { return self.primaryManagedObjectContext; } // Background threads leverage thread-local storage NSManagedObjectContext* managedObjectContext = [self threadLocalObjectForKey:RKManagedObjectStoreThreadDictionaryContextKey]; if (!managedObjectContext) { managedObjectContext = [self newManagedObjectContext]; // Store into thread local storage dictionary [self setThreadLocalObject:managedObjectContext forKey:RKManagedObjectStoreThreadDictionaryContextKey]; [managedObjectContext release]; // If we are a background Thread MOC, we need to inform the main thread on save [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:managedObjectContext]; } return managedObjectContext; } - (void)mergeChangesOnMainThreadWithNotification:(NSNotification*)notification { assert([NSThread isMainThread]); [self.primaryManagedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:YES]; } - (void)mergeChanges:(NSNotification *)notification { // Merge changes into the main context on the main thread [self performSelectorOnMainThread:@selector(mergeChangesOnMainThreadWithNotification:) withObject:notification waitUntilDone:YES]; } #pragma mark - #pragma mark Helpers - (NSManagedObject*)objectWithID:(NSManagedObjectID *)objectID { NSAssert(objectID, @"Cannot fetch a managedObject with a nil objectID"); return [[self managedObjectContextForCurrentThread] objectWithID:objectID]; } - (NSArray*)objectsWithIDs:(NSArray*)objectIDs { NSMutableArray* objects = [[NSMutableArray alloc] init]; for (NSManagedObjectID* objectID in objectIDs) { [objects addObject:[self objectWithID:objectID]]; } NSArray* objectArray = [NSArray arrayWithArray:objects]; [objects release]; return objectArray; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectStore.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectThreadSafeInvocation.h
// // RKManagedObjectThreadSafeInvocation.h // RestKit // // Created by Blake Watters on 5/12/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKManagedObjectStore.h" @interface RKManagedObjectThreadSafeInvocation : NSInvocation { NSMutableDictionary* _argumentKeyPaths; RKManagedObjectStore* _objectStore; } @property (nonatomic, retain) RKManagedObjectStore* objectStore; + (RKManagedObjectThreadSafeInvocation*)invocationWithMethodSignature:(NSMethodSignature*)methodSignature; - (void)setManagedObjectKeyPaths:(NSSet*)keyPaths forArgument:(NSInteger)index; - (void)invokeOnMainThread; // Private - (void)serializeManagedObjectsForArgument:(id)argument withKeyPaths:(NSSet*)keyPaths; - (void)deserializeManagedObjectIDsForArgument:(id)argument withKeyPaths:(NSSet*)keyPaths; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectThreadSafeInvocation.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKManagedObjectThreadSafeInvocation.m
// // RKManagedObjectThreadSafeInvocation.m // RestKit // // Created by Blake Watters on 5/12/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKManagedObjectThreadSafeInvocation.h" @implementation RKManagedObjectThreadSafeInvocation @synthesize objectStore = _objectStore; + (RKManagedObjectThreadSafeInvocation*)invocationWithMethodSignature:(NSMethodSignature*)methodSignature { return (RKManagedObjectThreadSafeInvocation*) [super invocationWithMethodSignature:methodSignature]; } - (void)setManagedObjectKeyPaths:(NSSet*)keyPaths forArgument:(NSInteger)index { if (nil == _argumentKeyPaths) { _argumentKeyPaths = [[NSMutableDictionary alloc] init]; } NSNumber* argumentIndex = [NSNumber numberWithInteger:index]; [_argumentKeyPaths setObject:keyPaths forKey:argumentIndex]; } - (void)setValue:(id)value forKeyPathOrKey:(NSString *)keyPath object:(id)object { [object setValue:value forKeyPath:keyPath]; id testValue = [object valueForKeyPath:keyPath]; if (![value isEqual:testValue]) { [object setValue:value forKey:keyPath]; testValue = [object valueForKeyPath:keyPath]; NSAssert([value isEqual:testValue], @"Could not set value"); } } - (void)serializeManagedObjectsForArgument:(id)argument withKeyPaths:(NSSet*)keyPaths { for (NSString* keyPath in keyPaths) { id value = [argument valueForKeyPath:keyPath]; if ([value isKindOfClass:[NSManagedObject class]]) { NSManagedObjectID *objectID = [(NSManagedObject*)value objectID]; [self setValue:objectID forKeyPathOrKey:keyPath object:argument]; } else if ([value respondsToSelector:@selector(allObjects)]) { id collection = [[[[[value class] alloc] init] autorelease] mutableCopy]; for (id subObject in value) { if ([subObject isKindOfClass:[NSManagedObject class]]) { [collection addObject:[(NSManagedObject*)subObject objectID]]; } else { [collection addObject:subObject]; } } [self setValue:collection forKeyPathOrKey:keyPath object:argument]; [collection release]; } } } - (void)deserializeManagedObjectIDsForArgument:(id)argument withKeyPaths:(NSSet*)keyPaths { for (NSString* keyPath in keyPaths) { id value = [argument valueForKeyPath:keyPath]; if ([value isKindOfClass:[NSManagedObjectID class]]) { NSAssert(self.objectStore, @"Object store cannot be nil"); NSManagedObject* managedObject = [self.objectStore objectWithID:(NSManagedObjectID*)value]; NSAssert(managedObject, @"Expected managed object for ID %@, got nil", value); [self setValue:managedObject forKeyPathOrKey:keyPath object:argument]; } else if ([value respondsToSelector:@selector(allObjects)]) { id collection = [[[[[value class] alloc] init] autorelease] mutableCopy]; for (id subObject in value) { if ([subObject isKindOfClass:[NSManagedObjectID class]]) { NSAssert(self.objectStore, @"Object store cannot be nil"); NSManagedObject* managedObject = [self.objectStore objectWithID:(NSManagedObjectID*)subObject]; [collection addObject:managedObject]; } else { [collection addObject:subObject]; } } [self setValue:collection forKeyPathOrKey:keyPath object:argument]; [collection release]; } } } - (void)serializeManagedObjects { for (NSNumber* argumentIndex in _argumentKeyPaths) { NSSet* managedKeyPaths = [_argumentKeyPaths objectForKey:argumentIndex]; id argument = nil; [self getArgument:&argument atIndex:[argumentIndex intValue]]; if (argument) { [self serializeManagedObjectsForArgument:argument withKeyPaths:managedKeyPaths]; } } } - (void)deserializeManagedObjects { for (NSNumber* argumentIndex in _argumentKeyPaths) { NSSet* managedKeyPaths = [_argumentKeyPaths objectForKey:argumentIndex]; id argument = nil; [self getArgument:&argument atIndex:[argumentIndex intValue]]; if (argument) { [self deserializeManagedObjectIDsForArgument:argument withKeyPaths:managedKeyPaths]; } } } - (void)performInvocationOnMainThread { [self deserializeManagedObjects]; [self invoke]; } - (void)invokeOnMainThread { [self retain]; [self serializeManagedObjects]; [self performSelectorOnMainThread:@selector(performInvocationOnMainThread) withObject:nil waitUntilDone:YES]; [self release]; } - (void)dealloc { [_argumentKeyPaths release]; [_objectStore release]; [super dealloc]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKManagedObjectThreadSafeInvocation.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKObjectMappingProvider+CoreData.h
// // RKObjectMappingProvider+CoreData.h // RestKit // // Created by Jeff Arena on 1/26/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKObjectMappingProvider.h" #import <CoreData/CoreData.h> typedef NSFetchRequest *(^RKObjectMappingProviderFetchRequestBlock)(NSString *resourcePath); /** Provides extensions to RKObjectMappingProvider to support Core Data specific functionality. */ @interface RKObjectMappingProvider (CoreData) /** Configures an object mapping to be used when during a load event where the resourcePath of the RKObjectLoader instance matches resourcePathPattern. The resourcePathPattern is a SOCKit pattern matching property names preceded by colons within a path. For example, if a collection of reviews for a product were loaded from a remote system at the resourcePath @"/products/1234/reviews", object mapping could be configured to handle this request with a resourcePathPattern of @"/products/:productID/reviews". **NOTE** that care must be taken when configuring patterns within the provider. The patterns will be evaluated in the order they are added to the provider, so more specific patterns must precede more general patterns where either would generate a match. @param objectMapping The object mapping to use when the resourcePath matches the specified resourcePathPattern. @param resourcePathPattern A pattern to be evaluated using an RKPathMatcher against a resourcePath to determine if objectMapping is the appropriate mapping. @param fetchRequestBlock A block that accepts an individual resourcePath and returns an NSFetchRequest that should be used to fetch the local objects associated with resourcePath from CoreData, for use in properly processing local deletes @see RKPathMatcher @see RKURL @see RKObjectLoader */ - (void)setObjectMapping:(RKObjectMappingDefinition *)objectMapping forResourcePathPattern:(NSString *)resourcePathPattern withFetchRequestBlock:(RKObjectMappingProviderFetchRequestBlock)fetchRequestBlock; /** Retrieves the NSFetchRequest object that will retrieve cached objects for a given resourcePath. @param resourcePath A resourcePath to retrieve the fetch request for. @return An NSFetchRequest object for fetching objects for the given resource path or nil. */ - (NSFetchRequest *)fetchRequestForResourcePath:(NSString *)resourcePath; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKObjectMappingProvider+CoreData.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKObjectMappingProvider+CoreData.m
// // RKObjectMappingProvider+CoreData.m // RestKit // // Created by Jeff Arena on 1/26/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKObjectMappingProvider+CoreData.h" #import "RKOrderedDictionary.h" #import "RKFixCategoryBug.h" RK_FIX_CATEGORY_BUG(RKObjectMappingProvider_CoreData) @implementation RKObjectMappingProvider (CoreData) - (void)setObjectMapping:(RKObjectMappingDefinition *)objectMapping forResourcePathPattern:(NSString *)resourcePath withFetchRequestBlock:(RKObjectMappingProviderFetchRequestBlock)fetchRequestBlock { [self setEntry:[RKObjectMappingProviderContextEntry contextEntryWithMapping:objectMapping userData:Block_copy(fetchRequestBlock)] forResourcePathPattern:resourcePath]; } - (NSFetchRequest *)fetchRequestForResourcePath:(NSString *)resourcePath { RKObjectMappingProviderContextEntry *entry = [self entryForResourcePath:resourcePath]; if (entry.userData) { NSFetchRequest *(^fetchRequestBlock)(NSString *) = entry.userData; return fetchRequestBlock(resourcePath); } return nil; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKObjectMappingProvider+CoreData.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKObjectPropertyInspector+CoreData.h
// // RKObjectPropertyInspector+CoreData.h // RestKit // // Created by Blake Watters on 8/14/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectPropertyInspector.h" @interface RKObjectPropertyInspector (CoreData) - (NSDictionary *)propertyNamesAndTypesForEntity:(NSEntityDescription*)entity; /** Returns the Class type of the specified property on the object class */ - (Class)typeForProperty:(NSString*)propertyName ofEntity:(NSEntityDescription*)entity; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKObjectPropertyInspector+CoreData.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKObjectPropertyInspector+CoreData.m
// // RKObjectPropertyInspector+CoreData.m // RestKit // // Created by Blake Watters on 8/14/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <CoreData/CoreData.h> #import "RKObjectPropertyInspector+CoreData.h" #import "RKLog.h" #import "RKFixCategoryBug.h" #import <objc/message.h> RK_FIX_CATEGORY_BUG(RKObjectPropertyInspector_CoreData) // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData @implementation RKObjectPropertyInspector (CoreData) - (NSDictionary *)propertyNamesAndTypesForEntity:(NSEntityDescription*)entity { NSMutableDictionary* propertyNamesAndTypes = [_cachedPropertyNamesAndTypes objectForKey:[entity name]]; if (propertyNamesAndTypes) { return propertyNamesAndTypes; } propertyNamesAndTypes = [NSMutableDictionary dictionary]; for (NSString* name in [entity attributesByName]) { NSAttributeDescription* attributeDescription = [[entity attributesByName] valueForKey:name]; if ([attributeDescription attributeValueClassName]) { [propertyNamesAndTypes setValue:NSClassFromString([attributeDescription attributeValueClassName]) forKey:name]; } else if ([attributeDescription attributeType] == NSTransformableAttributeType && ![name isEqualToString:@"_mapkit_hasPanoramaID"]) { const char* className = [[entity managedObjectClassName] cStringUsingEncoding:NSUTF8StringEncoding]; const char* propertyName = [name cStringUsingEncoding:NSUTF8StringEncoding]; Class managedObjectClass = objc_getClass(className); // property_getAttributes() returns everything we need to implement this... // See: http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW5 objc_property_t prop = class_getProperty(managedObjectClass, propertyName); NSString* attributeString = [NSString stringWithCString:property_getAttributes(prop) encoding:NSUTF8StringEncoding]; const char* destinationClassName = [[RKObjectPropertyInspector propertyTypeFromAttributeString:attributeString] cStringUsingEncoding:NSUTF8StringEncoding]; Class destinationClass = objc_getClass(destinationClassName); if (destinationClass) { [propertyNamesAndTypes setObject:destinationClass forKey:name]; } } } for (NSString* name in [entity relationshipsByName]) { NSRelationshipDescription* relationshipDescription = [[entity relationshipsByName] valueForKey:name]; if ([relationshipDescription isToMany]) { [propertyNamesAndTypes setValue:[NSSet class] forKey:name]; } else { NSEntityDescription* destinationEntity = [relationshipDescription destinationEntity]; Class destinationClass = NSClassFromString([destinationEntity managedObjectClassName]); [propertyNamesAndTypes setValue:destinationClass forKey:name]; } } [_cachedPropertyNamesAndTypes setObject:propertyNamesAndTypes forKey:[entity name]]; RKLogDebug(@"Cached property names and types for Entity '%@': %@", entity, propertyNamesAndTypes); return propertyNamesAndTypes; } - (Class)typeForProperty:(NSString*)propertyName ofEntity:(NSEntityDescription*)entity { return [[self propertyNamesAndTypesForEntity:entity] valueForKey:propertyName]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKObjectPropertyInspector+CoreData.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKSearchableManagedObject.h
// // RKSearchableManagedObject.h // RestKit // // Created by Jeff Arena on 3/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "NSManagedObject+ActiveRecord.h" #import "RKManagedObjectSearchEngine.h" @class RKSearchWord; /** RKSearchableManagedObject provides an abstract base class for Core Data entities that are searchable using the RKManagedObjectSearchEngine interface. The collection of search words is maintained by the RKSearchWordObserver singleton at managed object context save time. @see RKSearchWord @see RKSearchWordObserver @see RKManagedObjectSearchEngine */ @interface RKSearchableManagedObject : NSManagedObject ///----------------------------------------------------------------------------- /// @name Configuring Searchable Attributes ///----------------------------------------------------------------------------- /** Returns an array of attributes which should be processed by the search word observer to build the set of search words for entities with the type of the receiver. Subclasses must provide an implementation for indexing to occur as the base implementation returns an empty array. @warning *NOTE*: May only include attributes property names, not key paths. @return An array of attribute names containing searchable textual content for entities with the type of the receiver. @see RKSearchWordObserver @see searchWords */ + (NSArray *)searchableAttributes; ///----------------------------------------------------------------------------- /// @name Obtaining a Search Predicate ///----------------------------------------------------------------------------- /** A predicate that will search for the specified text with the specified mode. Mode can be configured to be RKSearchModeAnd or RKSearchModeOr. @return A predicate that will search for the specified text with the specified mode. @see RKSearchMode */ + (NSPredicate *)predicateForSearchWithText:(NSString *)searchText searchMode:(RKSearchMode)mode; ///----------------------------------------------------------------------------- /// @name Managing the Search Words ///----------------------------------------------------------------------------- /** The set of tokenized search words contained in the receiver. */ @property (nonatomic, retain) NSSet *searchWords; /** Rebuilds the set of tokenized search words associated with the receiver by processing the searchable attributes and tokenizing the contents into RKSearchWord instances. @see [RKSearchableManagedObject searchableAttributes] */ - (void)refreshSearchWords; @end @interface RKSearchableManagedObject (SearchWordsAccessors) /** Adds a search word object to the receiver's set of search words. @param searchWord The search word to be added to the set of search words. */ - (void)addSearchWordsObject:(RKSearchWord *)searchWord; /** Removes a search word object from the receiver's set of search words. @param searchWord The search word to be removed from the receiver's set of search words. */ - (void)removeSearchWordsObject:(RKSearchWord *)searchWord; /** Adds a set of search word objects to the receiver's set of search words. @param searchWords The set of search words to be added to receiver's the set of search words. */ - (void)addSearchWords:(NSSet *)searchWords; /** Removes a set of search word objects from the receiver's set of search words. @param searchWords The set of search words to be removed from receiver's the set of search words. */ - (void)removeSearchWords:(NSSet *)searchWords; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKSearchableManagedObject.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKSearchableManagedObject.m
// // RKSearchableManagedObject.m // RestKit // // Created by Jeff Arena on 3/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKSearchableManagedObject.h" #import "CoreData.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreDataSearchEngine @implementation RKSearchableManagedObject @dynamic searchWords; + (NSArray *)searchableAttributes { return [NSArray array]; } + (NSPredicate *)predicateForSearchWithText:(NSString *)searchText searchMode:(RKSearchMode)mode { if (searchText == nil) { return nil; } else { RKManagedObjectSearchEngine *searchEngine = [RKManagedObjectSearchEngine searchEngine]; searchEngine.mode = mode; return [searchEngine predicateForSearch:searchText]; } } - (void)refreshSearchWords { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; RKLogDebug(@"Refreshing search words for %@ %@", NSStringFromClass([self class]), [self objectID]); NSMutableSet *searchWords = [NSMutableSet set]; for (NSString *searchableAttribute in [[self class] searchableAttributes]) { NSString *attributeValue = [self valueForKey:searchableAttribute]; if (attributeValue) { RKLogTrace(@"Generating search words for searchable attribute: %@", searchableAttribute); NSArray *attributeValueWords = [RKManagedObjectSearchEngine tokenizedNormalizedString:attributeValue]; for (NSString *word in attributeValueWords) { if (word && [word length] > 0) { RKSearchWord *searchWord = [RKSearchWord findFirstByAttribute:RKSearchWordPrimaryKeyAttribute withValue:word inContext:self.managedObjectContext]; if (! searchWord) { searchWord = [RKSearchWord createInContext:self.managedObjectContext]; } searchWord.word = word; [searchWords addObject:searchWord]; } } } } self.searchWords = searchWords; RKLogTrace(@"Generating searchWords: %@", [searchWords valueForKey:RKSearchWordPrimaryKeyAttribute]); [pool drain]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKSearchableManagedObject.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKSearchWord.h
// // RKSearchWord.m // RestKit // // Created by Jeff Arena on 3/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "NSManagedObject+ActiveRecord.h" #import "RKSearchableManagedObject.h" extern NSString * const RKSearchWordPrimaryKeyAttribute; @interface RKSearchWord : NSManagedObject @property (nonatomic, retain) NSString* word; @property (nonatomic, retain) NSSet* searchableManagedObjects; @end @interface RKSearchWord (SearchableManagedObjectsAccessors) - (void)addSearchableManagedObjectsObject:(RKSearchableManagedObject*)searchableManagedObject; - (void)removeSearchableManagedObjectsObject:(RKSearchableManagedObject*)searchableManagedObject; - (void)addSearchableManagedObjects:(NSSet*)searchableManagedObjects; - (void)removeSearchableManagedObjects:(NSSet*)searchableManagedObjects; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKSearchWord.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKSearchWord.m
// // RKSearchWord.m // RestKit // // Created by Jeff Arena on 3/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKSearchWord.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreData NSString * const RKSearchWordPrimaryKeyAttribute = @"word"; @implementation RKSearchWord @dynamic word; @dynamic searchableManagedObjects; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKSearchWord.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKSearchWordObserver.h
// // RKSearchWordObserver.h // RestKit // // Created by Blake Watters on 7/25/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> /** Provides an observer responsible for initiating refresh of searchable Core Data attributes at managed object context save time. */ @interface RKSearchWordObserver : NSObject /** Returns the shared observer */ + (RKSearchWordObserver *)sharedObserver; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKSearchWordObserver.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/RKSearchWordObserver.m
// // RKSearchWordObserver.m // RestKit // // Created by Blake Watters on 7/25/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <CoreData/CoreData.h> #import "RKSearchWordObserver.h" #import "RKSearchableManagedObject.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitCoreDataSearchEngine static RKSearchWordObserver *sharedSearchWordObserver = nil; @implementation RKSearchWordObserver + (RKSearchWordObserver *)sharedObserver { if (! sharedSearchWordObserver) { sharedSearchWordObserver = [[RKSearchWordObserver alloc] init]; } return sharedSearchWordObserver; } - (id)init { self = [super init]; if (self) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(managedObjectContextWillSaveNotification:) name:NSManagedObjectContextWillSaveNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } - (void)managedObjectContextWillSaveNotification:(NSNotification *)notification { NSManagedObjectContext *context = [notification object]; NSSet *candidateObjects = [[NSSet setWithSet:context.insertedObjects] setByAddingObjectsFromSet:context.updatedObjects]; RKLogDebug(@"Managed object context will save notification received. Checking changed and inserted objects for searchable entities..."); for (NSManagedObject *object in candidateObjects) { if (! [object isKindOfClass:[RKSearchableManagedObject class]]) { RKLogTrace(@"Skipping search words refresh for entity of type '%@': not searchable.", NSStringFromClass([object class])); continue; } NSArray *searchableAttributes = [[object class] searchableAttributes]; for (NSString *attribute in searchableAttributes) { if ([[object changedValues] objectForKey:attribute]) { RKLogDebug(@"Detected change to searchable attribute '%@' for %@ entity: refreshing search words.", attribute, NSStringFromClass([object class])); [(RKSearchableManagedObject *)object refreshSearchWords]; break; } } } } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/CoreData/._RKSearchWordObserver.m
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/._CoreData
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/Network.h
// // Network.h // RestKit // // Created by Blake Watters on 9/30/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKClient.h" #import "RKURL.h" #import "RKRequest.h" #import "RKResponse.h" #import "RKRequestSerializable.h" #import "RKReachabilityObserver.h" #import "RKRequestQueue.h" #import "RKNotifications.h" #import "RKOAuthClient.h"
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._Network.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/NSData+RKAdditions.h
// // NSData+RKAdditions.h // RestKit // // Created by Jeff Arena on 4/4/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // /** Provides extensions to NSData for various common tasks. */ @interface NSData (RKAdditions) /** Returns a string of the MD5 sum of the receiver. @return A new string containing the MD5 sum of the receiver. */ - (NSString *)MD5; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._NSData+RKAdditions.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/NSData+RKAdditions.m
// // NSData+MD5.m // RestKit // // Created by Jeff Arena on 4/4/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <CommonCrypto/CommonDigest.h> #import "NSData+RKAdditions.h" #import "RKFixCategoryBug.h" RK_FIX_CATEGORY_BUG(NSData_RKAdditions) @implementation NSData (RKAdditions) - (NSString *)MD5 { // Create byte array of unsigned chars unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; // Create 16 byte MD5 hash value, store in buffer CC_MD5(self.bytes, (CC_LONG) self.length, md5Buffer); // Convert unsigned char buffer to NSString of hex values NSMutableString* output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { [output appendFormat:@"%02x",md5Buffer[i]]; } return output; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._NSData+RKAdditions.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/NSDictionary+RKRequestSerialization.h
// // NSDictionary+RKRequestSerialization.h // RestKit // // Created by Blake Watters on 7/28/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> #import "RKRequestSerializable.h" /* Extends NSDictionary to enable usage as the params of an RKRequest. This category provides for the serialization of the receiving NSDictionary into a URL encoded string representation (MIME Type application/x-www-form-urlencoded). This enables NSDictionary objects to act as the params for an RKRequest. @see RKRequestSerializable @see [RKRequest params] @class NSDictionary (RKRequestSerialization) */ @interface NSDictionary (RKRequestSerialization) <RKRequestSerializable> @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._NSDictionary+RKRequestSerialization.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/NSDictionary+RKRequestSerialization.m
// // NSDictionary+RKRequestSerialization.m // RestKit // // Created by Blake Watters on 7/28/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "NSDictionary+RKRequestSerialization.h" #import "NSDictionary+RKAdditions.h" #import "RKFixCategoryBug.h" #import "RKMIMETypes.h" RK_FIX_CATEGORY_BUG(NSDictionary_RKRequestSerialization) @implementation NSDictionary (RKRequestSerialization) - (NSString *)HTTPHeaderValueForContentType { return RKMIMETypeFormURLEncoded; } - (NSData *)HTTPBody { return [[self URLEncodedString] dataUsingEncoding:NSUTF8StringEncoding]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._NSDictionary+RKRequestSerialization.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/NSObject+URLEncoding.h
// // NSObject+URLEncoding.h // RestKit // // Created by Jeff Arena on 7/11/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // @interface NSObject (URLEncoding) /** * Returns a representation of the object as a URLEncoded string * * @returns A UTF-8 encoded string representation of the object */ - (NSString*)URLEncodedString; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._NSObject+URLEncoding.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/NSObject+URLEncoding.m
// // NSObject+URLEncoding.m // RestKit // // Created by Jeff Arena on 7/11/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "NSObject+URLEncoding.h" @implementation NSObject (URLEncoding) - (NSString*)URLEncodedString { NSString *string = [NSString stringWithFormat:@"%@", self]; NSString *encodedString = (NSString*)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)string, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8); return [encodedString autorelease]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._NSObject+URLEncoding.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKClient.h
// // RKClient.h // RestKit // // Created by Blake Watters on 7/28/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKURL.h" #import "RKRequest.h" #import "RKParams.h" #import "RKResponse.h" #import "NSDictionary+RKRequestSerialization.h" #import "RKReachabilityObserver.h" #import "RKRequestCache.h" #import "RKRequestQueue.h" #import "RKConfigurationDelegate.h" /** RKClient exposes the low level client interface for working with HTTP servers and RESTful services. It wraps the request/response cycle with a clean, simple interface. RKClient can be thought of as analogous to a web browser or other HTTP user agent. The client's primary purpose is to configure and dispatch requests to a remote service for processing in a global way. When working with the Network layer, a user will generally construct and dispatch all RKRequest objects via the interfaces exposed by RKClient. ### Base URL and Resource Paths Core to an effective utilization of RKClient is an understanding of the Base URL and Resource Path concepts. The Base URL forms the common beginning part of a complete URL string that is used to access a remote web service. RKClient instances are configured with a Base URL and all requests dispatched through the client will be sent to a URL consisting of the base URL plus the resource path specified. The resource path is simply the remaining part of the URL once all common text is removed. For example, given a remote web service at `http://restkit.org` and RESTful services at `http://restkit.org/services` and `http://restkit.org/objects`, our base URL would be `http://restkit.org` and we would have resource paths of `/services` and `/objects`. Base URLs simplify interaction with remote services by freeing us from having to interpolate strings and construct NSURL objects to get work done. We are also able to quickly retarget an entire application to a different server or API version by changing the base URL. This is commonly done via conditional compilation to create builds against a staging and production server, for example. ### Memory Management Note that memory management of requests sent via RKClient instances are automatically managed for you. When sent, the request is retained by the requestQueue and is released when all request processing has completed. Generally speaking this means that you can dispatch requests and work with the response in the delegate methods without regard for memory management. ### Request Serialization RKClient and RKRequest support the serialization of objects into payloads to be sent as the body of a request. This functionality is commonly used to provide a dictionary of simple values to be encoded and sent as a form encoding with POST and PUT operations. It is worth noting however that this functionality is provided via the RKRequestSerializable protocol and is not specific to NSDictionary objects. ### Sending Asynchronous Requests A handful of methods are provided as a convenience to cover the common asynchronous request tasks. All other request needs should instantiate a request via [RKClient requestWithResourcePath:] and work with the RKRequest object directly. @see RKRequest @see RKResponse @see RKRequestQueue @see RKRequestSerializable */ @interface RKClient : NSObject <RKConfigurationDelegate> { RKURL *_baseURL; RKRequestAuthenticationType _authenticationType; NSString *_username; NSString *_password; NSString *_OAuth1ConsumerKey; NSString *_OAuth1ConsumerSecret; NSString *_OAuth1AccessToken; NSString *_OAuth1AccessTokenSecret; NSString *_OAuth2AccessToken; NSString *_OAuth2RefreshToken; NSMutableDictionary *_HTTPHeaders; RKReachabilityObserver *_reachabilityObserver; NSString *_serviceUnavailableAlertTitle; NSString *_serviceUnavailableAlertMessage; BOOL _serviceUnavailableAlertEnabled; RKRequestQueue *_requestQueue; RKRequestCache *_requestCache; RKRequestCachePolicy _cachePolicy; NSMutableSet *_additionalRootCertificates; BOOL _disableCertificateValidation; NSStringEncoding _defaultHTTPEncoding; NSString *_runLoopMode; // Queue suspension flags BOOL _awaitingReachabilityDetermination; } ///----------------------------------------------------------------------------- /// @name Initializing a Client ///----------------------------------------------------------------------------- /** Returns a client scoped to a particular base URL. If the singleton client is nil, the return client is set as the singleton. @see baseURL @param baseURL The baseURL to set for the client. All requests will be relative to this base URL. @return A configured RKClient instance ready to send requests */ + (RKClient *)clientWithBaseURL:(NSURL *)baseURL; /** Returns a client scoped to a particular base URL. If the singleton client is nil, the return client is set as the singleton. @see baseURL @param baseURLString The string to use to construct the NSURL to set the baseURL. All requests will be relative to this base URL. @return A configured RKClient instance ready to send requests */ + (RKClient *)clientWithBaseURLString:(NSString *)baseURLString; /** Returns a Rest client scoped to a particular base URL with a set of HTTP AUTH credentials. If the singleton client is nil, the return client is set as the singleton. @bug **DEPRECATED** in version 0.9.4: Use [RKClient clientWithBaseURLString:] and set username and password afterwards. @param baseURL The baseURL to set for the client. All requests will be relative to this base URL. @param username The username to use for HTTP Authentication challenges @param password The password to use for HTTP Authentication challenges @return A configured RKClient instance ready to send requests */ + (RKClient *)clientWithBaseURL:(NSString *)baseURL username:(NSString *)username password:(NSString *)password DEPRECATED_ATTRIBUTE; /** Returns a client scoped to a particular base URL. If the singleton client is nil, the return client is set as the singleton. @see baseURL @param baseURL The baseURL to set for the client. All requests will be relative to this base URL. @return A configured RKClient instance ready to send requests */ - (id)initWithBaseURL:(NSURL *)baseURL; /** Returns a client scoped to a particular base URL. If the singleton client is nil, the return client is set as the singleton. @see baseURL @param baseURLString The string to use to construct the NSURL to set the baseURL. All requests will be relative to this base URL. @return A configured RKClient instance ready to send requests */ - (id)initWithBaseURLString:(NSString *)baseURLString; ///----------------------------------------------------------------------------- /// @name Configuring the Client ///----------------------------------------------------------------------------- /** The base URL all resources are nested underneath. All requests created through the client will their URL built by appending a resourcePath to the baseURL to form a complete URL. Changing the baseURL has the side-effect of causing the requestCache instance to be rebuilt. Caches are maintained a per-host basis. @see requestCache */ @property (nonatomic, retain) RKURL *baseURL; /** A dictionary of headers to be sent with each request */ @property (nonatomic, retain, readonly) NSMutableDictionary *HTTPHeaders; /** An optional timeout interval within which the request should be cancelled. This is passed along to RKRequest if set. If it isn't set, it will default to RKRequest's default timeoutInterval. *Default*: Falls through to RKRequest's timeoutInterval */ @property (nonatomic, assign) NSTimeInterval timeoutInterval; /** The request queue to push asynchronous requests onto. *Default*: A new request queue is instantiated for you during init. */ @property (nonatomic, retain) RKRequestQueue *requestQueue; /** The run loop mode under which the underlying NSURLConnection is performed *Default*: NSRunLoopCommonModes */ @property (nonatomic, copy) NSString *runLoopMode; /** The default value used to decode HTTP body content when HTTP headers received do not provide information on the content. This encoding will be used by the RKResponse when creating the body content */ @property (nonatomic, assign) NSStringEncoding defaultHTTPEncoding; /** Adds an HTTP header to each request dispatched through the client @param value The string value to set for the HTTP header @param header The HTTP header to add @see HTTPHeaders */ - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)header; ///----------------------------------------------------------------------------- /// @name Handling SSL Validation ///----------------------------------------------------------------------------- /** Flag for disabling SSL certificate validation. *Default*: NO @warning **WARNING**: This is a potential security exposure and should be used **ONLY while debugging** in a controlled environment. */ @property (nonatomic, assign) BOOL disableCertificateValidation; /** A set of additional certificates to be used in evaluating server SSL certificates. */ @property (nonatomic, retain, readonly) NSSet *additionalRootCertificates; /** Adds an additional certificate that will be used to evaluate server SSL certs. @param cert The SecCertificateRef to add to the list of additional SSL certs. @see additionalRootCertificates */ - (void)addRootCertificate:(SecCertificateRef)cert; ///----------------------------------------------------------------------------- /// @name Authentication ///----------------------------------------------------------------------------- /** The type of authentication to use for this request. This must be assigned one of the following: - `RKRequestAuthenticationTypeNone`: Disable the use of authentication - `RKRequestAuthenticationTypeHTTP`: Use NSURLConnection's HTTP AUTH auto-negotiation - `RKRequestAuthenticationTypeHTTPBasic`: Force the use of HTTP Basic authentication. This will supress AUTH challenges as RestKit will add an Authorization header establishing login via HTTP basic. This is an optimization that skips the challenge portion of the request. - `RKRequestAuthenticationTypeOAuth1`: Enable the use of OAuth 1.0 authentication. OAuth1ConsumerKey, OAuth1ConsumerSecret, OAuth1AccessToken, and OAuth1AccessTokenSecret must be set. - `RKRequestAuthenticationTypeOAuth2`: Enable the use of OAuth 2.0 authentication. OAuth2AccessToken must be set. **Default**: RKRequestAuthenticationTypeNone */ @property (nonatomic, assign) RKRequestAuthenticationType authenticationType; /** The username to use for authentication via HTTP AUTH. Used to respond to an authentication challenge when authenticationType is RKRequestAuthenticationTypeHTTP or RKRequestAuthenticationTypeHTTPBasic. @see authenticationType */ @property (nonatomic, retain) NSString *username; /** The password to use for authentication via HTTP AUTH. Used to respond to an authentication challenge when authenticationType is RKRequestAuthenticationTypeHTTP or RKRequestAuthenticationTypeHTTPBasic. @see authenticationType */ @property (nonatomic, retain) NSString *password; ///----------------------------------------------------------------------------- /// @name OAuth1 Secrets ///----------------------------------------------------------------------------- /** The OAuth 1.0 consumer key Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1ConsumerKey; /** The OAuth 1.0 consumer secret Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1ConsumerSecret; /** The OAuth 1.0 access token Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1AccessToken; /** The OAuth 1.0 access token secret Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1AccessTokenSecret; ///----------------------------------------------------------------------------- /// @name OAuth2 Secrets ///----------------------------------------------------------------------------- /** The OAuth 2.0 access token Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth2 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth2AccessToken; /** The OAuth 2.0 refresh token Used to retrieve a new access token before expiration and to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth2 @bug **NOT IMPLEMENTED**: This functionality is not yet implemented. @see authenticationType */ @property (nonatomic, retain) NSString *OAuth2RefreshToken; ///----------------------------------------------------------------------------- /// @name Reachability & Service Availability Alerting ///----------------------------------------------------------------------------- /** An instance of RKReachabilityObserver used for determining the availability of network access. Initialized using [RKReachabilityObserver reachabilityObserverForInternet] to monitor connectivity to the Internet. Can be changed to directly monitor a remote hostname/IP address or the local WiFi interface instead. @warning **WARNING**: Changing the reachability observer has the side-effect of temporarily suspending the requestQueue until reachability to the new host can be established. @see RKReachabilityObserver */ @property (nonatomic, retain) RKReachabilityObserver *reachabilityObserver; /** The title to use in the alert shown when a request encounters a ServiceUnavailable (503) response. *Default*: _"Service Unavailable"_ */ @property (nonatomic, retain) NSString *serviceUnavailableAlertTitle; /** The message to use in the alert shown when a request encounters a ServiceUnavailable (503) response. *Default*: _"The remote resource is unavailable. Please try again later."_ */ @property (nonatomic, retain) NSString *serviceUnavailableAlertMessage; /** Flag that determines whether the Service Unavailable alert is shown in response to a ServiceUnavailable (503) response. *Default*: _NO_ */ @property (nonatomic, assign) BOOL serviceUnavailableAlertEnabled; ///----------------------------------------------------------------------------- /// @name Reachability helpers ///----------------------------------------------------------------------------- /** Convenience method for returning the current reachability status from the reachabilityObserver. Equivalent to executing `[RKClient isNetworkReachable]` on the sharedClient @see RKReachabilityObserver @return YES if the remote host is accessible */ - (BOOL)isNetworkReachable; /** Convenience method for returning the current reachability status from the reachabilityObserver. @bug **DEPRECATED** in v0.10.0: Use [RKClient isNetworkReachable] @see RKReachabilityObserver @return YES if the remote host is accessible */ - (BOOL)isNetworkAvailable DEPRECATED_ATTRIBUTE; ///----------------------------------------------------------------------------- /// @name Caching ///----------------------------------------------------------------------------- /** An instance of the request cache used to store/load cacheable responses for requests sent through this client @bug **DEPRECATED** in v0.10.0: Use requestCache instead. */ @property (nonatomic, retain) RKRequestCache *cache DEPRECATED_ATTRIBUTE; /** An instance of the request cache used to store/load cacheable responses for requests sent through this client */ @property (nonatomic, retain) RKRequestCache *requestCache; /** The timeout interval within which the requests should not be sent and the cached response should be used. This is only used if the cache policy includes RKRequestCachePolicyTimeout. */ @property (nonatomic, assign) NSTimeInterval cacheTimeoutInterval; /** The default cache policy to apply for all requests sent through this client This must be assigned one of the following: - `RKRequestCachePolicyNone`: Never use the cache. - `RKRequestCachePolicyLoadIfOffline`: Load from the cache when offline. - `RKRequestCachePolicyLoadOnError`: Load from the cache if an error is encountered. - `RKRequestCachePolicyEtag`: Load from the cache if there is data stored and the server returns a 304 (Not Modified) response. - `RKRequestCachePolicyEnabled`: Load from the cache whenever data has been stored. - `RKRequestCachePolicyTimeout`: Load from the cache if the cacheTimeoutInterval is reached before the server responds. @see RKRequest */ @property (nonatomic, assign) RKRequestCachePolicy cachePolicy; /** The path used to store response data for this client's request cache. The path that is used is the device's cache directory with `RKClientRequestCache-host` appended. */ @property (nonatomic, readonly) NSString *cachePath; ///----------------------------------------------------------------------------- /// @name Shared Client Instance ///----------------------------------------------------------------------------- /** Returns the shared instance of the client */ + (RKClient *)sharedClient; /** Sets the shared instance of the client, releasing the current instance (if any) @param client An RKClient instance to configure as the new shared instance */ + (void)setSharedClient:(RKClient *)client; ///----------------------------------------------------------------------------- /// @name Building Requests ///----------------------------------------------------------------------------- /** Return a request object targetted at a resource path relative to the base URL. By default the method is set to GET. All headers set on the client will automatically be applied to the request as well. @bug **DEPRECATED** in v0.10.0: Use [RKClient requestWithResourcePath:] instead. @param resourcePath The resource path to configure the request for. @param delegate A delegate to inform of events in the request lifecycle. @return A fully configured RKRequest instance ready for sending. @see RKRequestDelegate */ - (RKRequest *)requestWithResourcePath:(NSString *)resourcePath delegate:(NSObject<RKRequestDelegate> *)delegate DEPRECATED_ATTRIBUTE; /** Return a request object targeted at a resource path relative to the base URL. By default the method is set to GET. All headers set on the client will automatically be applied to the request as well. @param resourcePath The resource path to configure the request for. @return A fully configured RKRequest instance ready for sending. @see RKRequestDelegate */ - (RKRequest *)requestWithResourcePath:(NSString *)resourcePath; ///----------------------------------------------------------------------------- /// @name Sending Asynchronous Requests ///----------------------------------------------------------------------------- /** Perform an asynchronous GET request for a resource and inform a delegate of the results. @param resourcePath The resourcePath to target the request at @param delegate A delegate object to inform of the results @return The RKRequest object built and sent to the remote system */ - (RKRequest *)get:(NSString *)resourcePath delegate:(NSObject<RKRequestDelegate> *)delegate; /** Fetch a resource via an HTTP GET with a dictionary of params. This request _only_ allows NSDictionary objects as the params. The dictionary will be coerced into a URL encoded string and then appended to the resourcePath as the query string of the request. @param resourcePath The resourcePath to target the request at @param queryParameters A dictionary of query parameters to append to the resourcePath. Assumes that resourcePath does not contain a query string. @param delegate A delegate object to inform of the results @return The RKRequest object built and sent to the remote system */ - (RKRequest *)get:(NSString *)resourcePath queryParameters:(NSDictionary *)queryParameters delegate:(NSObject<RKRequestDelegate> *)delegate; /** Fetches a resource via an HTTP GET after executing a given a block using the configured request object. @param resourcePath The resourcePath to target the request at @param block The block to execute with the request before sending it for processing. */ - (void)get:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block; /** Create a resource via an HTTP POST with a set of form parameters. The form parameters passed here must conform to RKRequestSerializable, such as an instance of RKParams. @see RKParams @param resourcePath The resourcePath to target the request at @param params A RKRequestSerializable object to use as the body of the request @param delegate A delegate object to inform of the results @return The RKRequest object built and sent to the remote system @see RKRequestSerializable */ - (RKRequest *)post:(NSString *)resourcePath params:(NSObject<RKRequestSerializable> *)params delegate:(NSObject<RKRequestDelegate> *)delegate; /** Creates a resource via an HTTP POST after executing a given a block using the configured request object. @param resourcePath The resourcePath to target the request at @param block The block to execute with the request before sending it for processing. */ - (void)post:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block; /** Update a resource via an HTTP PUT. The form parameters passed here must conform to RKRequestSerializable, such as an instance of RKParams. @see RKParams @param resourcePath The resourcePath to target the request at @param params A RKRequestSerializable object to use as the body of the request @param delegate A delegate object to inform of the results @return The RKRequest object built and sent to the remote system @see RKRequestSerializable */ - (RKRequest *)put:(NSString *)resourcePath params:(NSObject<RKRequestSerializable> *)params delegate:(NSObject<RKRequestDelegate> *)delegate; /** Updates a resource via an HTTP PUT after executing a given a block using the configured request object. @param resourcePath The resourcePath to target the request at @param block The block to execute with the request before sending it for processing. */ - (void)put:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block; /** Destroy a resource via an HTTP DELETE. @param resourcePath The resourcePath to target the request at @param delegate A delegate object to inform of the results @return The RKRequest object built and sent to the remote system */ - (RKRequest *)delete:(NSString *)resourcePath delegate:(NSObject<RKRequestDelegate> *)delegate; /** Destroys a resource via an HTTP DELETE after executing a given a block using the configured request object. @param resourcePath The resourcePath to target the request at @param block The block to execute with the request before sending it for processing. */ - (void)delete:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block; ///----------------------------------------------------------------------------- /// @name Constructing Resource Paths and URLs ///----------------------------------------------------------------------------- /** Returns a NSURL by adding a resource path to the base URL @bug **DEPRECATED** in v0.10.0: Use [RKURL URLByAppendingResourcePath:] @param resourcePath The resource path to build a URL against @return An NSURL constructed by concatenating the baseURL and the resourcePath */ - (NSURL *)URLForResourcePath:(NSString *)resourcePath DEPRECATED_ATTRIBUTE; /** Returns an NSString by adding a resource path to the base URL @bug **DEPRECATED**: Use `[RKURL URLByAppendingResourcePath:] absoluteString` @param resourcePath The resource path to build a URL against @return A string URL constructed by concatenating the baseURL and the resourcePath. */ - (NSString *)URLPathForResourcePath:(NSString *)resourcePath DEPRECATED_ATTRIBUTE; /** Returns a resource path with a dictionary of query parameters URL encoded and appended This is a convenience method for constructing a new resource path that includes a query. For example, when given a resourcePath of /contacts and a dictionary of parameters containing foo=bar and color=red, will return /contacts?foo=bar&color=red @warning **NOTE**: This assumes that the resource path does not already contain any query parameters. @bug **DEPRECATED**: Use [RKURL URLByAppendingQueryParameters:] @param resourcePath The resource path to append the query parameters onto @param queryParams A dictionary of query parameters to be URL encoded and appended to the resource path. @return A new resource path with the query parameters appended */ - (NSString *)resourcePath:(NSString *)resourcePath withQueryParams:(NSDictionary *)queryParams DEPRECATED_ATTRIBUTE; /** Returns a NSURL by adding a resource path to the base URL and appending a URL encoded set of query parameters This is a convenience method for constructing a new resource path that includes a query. For example, when given a resourcePath of /contacts and a dictionary of parameters containing foo=bar and color=red, will return /contacts?foo=bar&color=red @warning **NOTE**: Assumes that the resource path does not already contain any query parameters. @bug **DEPRECATED**: Use [RKURL URLByAppendingResourcePath:queryParameters:] @param resourcePath The resource path to append the query parameters onto @param queryParams A dictionary of query parameters to be URL encoded and appended to the resource path. @return A URL constructed by concatenating the baseURL and the resourcePath with the query parameters appended. */ - (NSURL *)URLForResourcePath:(NSString *)resourcePath queryParams:(NSDictionary *)queryParams DEPRECATED_ATTRIBUTE; @end ///----------------------------------------------------------------------------- /// @name URL & URL Path Convenience methods ///----------------------------------------------------------------------------- /** Returns an NSURL with the specified resource path appended to the base URL that the shared RKClient instance is configured with. Shortcut for calling `[[RKClient sharedClient] URLForResourcePath:@"/some/path"]` @bug **DEPRECATED** in v0.10.0: Use [[RKClient sharedClient].baseURL URLByAppendingResourcePath:] @param resourcePath The resource path to append to the baseURL of the `[RKClient sharedClient]` @return A fully constructed NSURL consisting of baseURL of the shared client singleton and the supplied resource path */ NSURL *RKMakeURL(NSString *resourcePath) DEPRECATED_ATTRIBUTE; /** Returns an NSString with the specified resource path appended to the base URL that the shared RKClient instance is configured with Shortcut for calling `[[RKClient sharedClient] URLPathForResourcePath:@"/some/path"]` @bug **DEPRECATED** in v0.10.0: Use [[[RKClient sharedClient].baseURL URLByAppendingResourcePath:] absoluteString] @param resourcePath The resource path to append to the baseURL of the `[RKClient sharedClient]` @return A fully constructed NSURL consisting of baseURL of the shared client singleton and the supplied resource path */ NSString *RKMakeURLPath(NSString *resourcePath) DEPRECATED_ATTRIBUTE; /** Convenience method for generating a path against the properties of an object. Takes a string with property names encoded with colons and interpolates the values of the properties specified and returns the generated path. Defaults to adding escapes. If desired, turn them off with RKMakePathWithObjectAddingEscapes. For example, given an 'article' object with an 'articleID' property of 12345 and a 'name' of Blake, RKMakePathWithObject(@"articles/:articleID/:name", article) would generate @"articles/12345/Blake" This functionality is the basis for resource path generation in the Router. @bug **DEPRECATED** in v0.10.0: Use [NSString interpolateWithObject:] @param path The colon encoded path pattern string to use for interpolation. @param object The object containing the properties needed for interpolation. @return A new path string, replacing the pattern's parameters with the object's actual property values. @see RKMakePathWithObjectAddingEscapes */ NSString *RKMakePathWithObject(NSString *path, id object) DEPRECATED_ATTRIBUTE; /** Convenience method for generating a path against the properties of an object. Takes a string with property names encoded with colons and interpolates the values of the properties specified and returns the generated path. For example, given an 'article' object with an 'articleID' property of 12345 and a 'code' of "This/That", `RKMakePathWithObjectAddingEscapes(@"articles/:articleID/:code", article, YES)` would generate @"articles/12345/This%2FThat" This functionality is the basis for resource path generation in the Router. @bug **DEPRECATED** in v0.10.0: Use [NSString interpolateWithObject:addingEscapes:] @param path The colon encoded path pattern string to use for interpolation. @param object The object containing the properties needed for interpolation. @param addEscapes Conditionally add percent escapes to the interpolated property values. @return A new path string, replacing the pattern's parameters with the object's actual property values. */ NSString *RKMakePathWithObjectAddingEscapes(NSString *pattern, id object, BOOL addEscapes) DEPRECATED_ATTRIBUTE; /** Returns a resource path with a dictionary of query parameters URL encoded and appended. This is a convenience method for constructing a new resource path that includes a query. For example, when given a resourcePath of /contacts and a dictionary of parameters containing `foo=bar` and `color=red`, will return `/contacts?foo=bar&color=red`. @warning This assumes that the resource path does not already contain any query parameters. @bug **DEPRECATED** in v0.10.0: Use [NSString stringByAppendingQueryParameters:] instead @param resourcePath The resource path to append the query parameters onto @param queryParams A dictionary of query parameters to be URL encoded and appended to the resource path. @return A new resource path with the query parameters appended. */ NSString *RKPathAppendQueryParams(NSString *resourcePath, NSDictionary *queryParams) DEPRECATED_ATTRIBUTE;
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKClient.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKClient.m
// // RKClient.m // RestKit // // Created by Blake Watters on 7/28/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKClient.h" #import "RKURL.h" #import "RKNotifications.h" #import "RKAlert.h" #import "RKLog.h" #import "RKPathMatcher.h" #import "NSString+RKAdditions.h" #import "RKDirectory.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetwork /////////////////////////////////////////////////////////////////////////////////////////////////// // Global static RKClient *sharedClient = nil; /////////////////////////////////////////////////////////////////////////////////////////////////// // URL Conveniences functions NSURL *RKMakeURL(NSString *resourcePath) { return [[RKClient sharedClient].baseURL URLByAppendingResourcePath:resourcePath]; } NSString *RKMakeURLPath(NSString *resourcePath) { return [[[RKClient sharedClient].baseURL URLByAppendingResourcePath:resourcePath] absoluteString]; } NSString *RKMakePathWithObjectAddingEscapes(NSString* pattern, id object, BOOL addEscapes) { NSCAssert(pattern != NULL, @"Pattern string must not be empty in order to create a path from an interpolated object."); NSCAssert(object != NULL, @"Object provided is invalid; cannot create a path from a NULL object"); RKPathMatcher *matcher = [RKPathMatcher matcherWithPattern:pattern]; NSString *interpolatedPath = [matcher pathFromObject:object addingEscapes:addEscapes]; return interpolatedPath; } NSString *RKMakePathWithObject(NSString *pattern, id object) { return RKMakePathWithObjectAddingEscapes(pattern, object, YES); } NSString *RKPathAppendQueryParams(NSString *resourcePath, NSDictionary *queryParams) { return [resourcePath stringByAppendingQueryParameters:queryParams]; } /////////////////////////////////////////////////////////////////////////////////////////////////// @interface RKClient () @property (nonatomic, retain, readwrite) NSMutableDictionary *HTTPHeaders; @property (nonatomic, retain, readwrite) NSSet *additionalRootCertificates; @end @implementation RKClient @synthesize baseURL = _baseURL; @synthesize authenticationType = _authenticationType; @synthesize username = _username; @synthesize password = _password; @synthesize OAuth1ConsumerKey = _OAuth1ConsumerKey; @synthesize OAuth1ConsumerSecret = _OAuth1ConsumerSecret; @synthesize OAuth1AccessToken = _OAuth1AccessToken; @synthesize OAuth1AccessTokenSecret = _OAuth1AccessTokenSecret; @synthesize OAuth2AccessToken = _OAuth2AccessToken; @synthesize OAuth2RefreshToken = _OAuth2RefreshToken; @synthesize HTTPHeaders = _HTTPHeaders; @synthesize additionalRootCertificates = _additionalRootCertificates; @synthesize disableCertificateValidation = _disableCertificateValidation; @synthesize reachabilityObserver = _reachabilityObserver; @synthesize serviceUnavailableAlertTitle = _serviceUnavailableAlertTitle; @synthesize serviceUnavailableAlertMessage = _serviceUnavailableAlertMessage; @synthesize serviceUnavailableAlertEnabled = _serviceUnavailableAlertEnabled; @synthesize requestCache = _requestCache; @synthesize cachePolicy = _cachePolicy; @synthesize requestQueue = _requestQueue; @synthesize timeoutInterval = _timeoutInterval; @synthesize defaultHTTPEncoding = _defaultHTTPEncoding; @synthesize cacheTimeoutInterval = _cacheTimeoutInterval; @synthesize runLoopMode = _runLoopMode; + (RKClient *)sharedClient { return sharedClient; } + (void)setSharedClient:(RKClient *)client { [sharedClient release]; sharedClient = [client retain]; } + (RKClient *)clientWithBaseURLString:(NSString *)baseURLString { return [self clientWithBaseURL:[RKURL URLWithString:baseURLString]]; } + (RKClient *)clientWithBaseURL:(NSURL *)baseURL { RKClient *client = [[[self alloc] initWithBaseURL:baseURL] autorelease]; return client; } + (RKClient *)clientWithBaseURL:(NSString *)baseURL username:(NSString *)username password:(NSString *)password { RKClient *client = [RKClient clientWithBaseURLString:baseURL]; client.authenticationType = RKRequestAuthenticationTypeHTTPBasic; client.username = username; client.password = password; return client; } - (id)init { self = [super init]; if (self) { self.HTTPHeaders = [NSMutableDictionary dictionary]; self.additionalRootCertificates = [NSMutableSet set]; self.defaultHTTPEncoding = NSUTF8StringEncoding; self.cacheTimeoutInterval = 0; self.runLoopMode = NSRunLoopCommonModes; self.requestQueue = [RKRequestQueue requestQueue]; self.serviceUnavailableAlertEnabled = NO; self.serviceUnavailableAlertTitle = NSLocalizedString(@"Service Unavailable", nil); self.serviceUnavailableAlertMessage = NSLocalizedString(@"The remote resource is unavailable. Please try again later.", nil); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(serviceDidBecomeUnavailableNotification:) name:RKServiceDidBecomeUnavailableNotification object:nil]; // Configure observers [self addObserver:self forKeyPath:@"reachabilityObserver" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; [self addObserver:self forKeyPath:@"baseURL" options:NSKeyValueObservingOptionNew context:nil]; [self addObserver:self forKeyPath:@"requestQueue" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial context:nil]; } return self; } - (id)initWithBaseURL:(NSURL *)baseURL { self = [self init]; if (self) { self.cachePolicy = RKRequestCachePolicyDefault; self.baseURL = [RKURL URLWithBaseURL:baseURL]; if (sharedClient == nil) { [RKClient setSharedClient:self]; // Initialize Logging as soon as a client is created RKLogInitialize(); } } return self; } - (id)initWithBaseURLString:(NSString *)baseURLString { return [self initWithBaseURL:[RKURL URLWithString:baseURLString]]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; // Allow KVO to fire self.reachabilityObserver = nil; self.baseURL = nil; self.requestQueue = nil; [self removeObserver:self forKeyPath:@"reachabilityObserver"]; [self removeObserver:self forKeyPath:@"baseURL"]; [self removeObserver:self forKeyPath:@"requestQueue"]; self.username = nil; self.password = nil; self.serviceUnavailableAlertTitle = nil; self.serviceUnavailableAlertMessage = nil; self.requestCache = nil; self.runLoopMode = nil; [_HTTPHeaders release]; [_additionalRootCertificates release]; if (sharedClient == self) sharedClient = nil; [super dealloc]; } - (NSString *)cachePath { NSString *cacheDirForClient = [NSString stringWithFormat:@"RKClientRequestCache-%@", [self.baseURL host]]; NSString *cachePath = [[RKDirectory cachesDirectory] stringByAppendingPathComponent:cacheDirForClient]; return cachePath; } - (BOOL)isNetworkReachable { BOOL isNetworkReachable = YES; if (self.reachabilityObserver) { isNetworkReachable = [self.reachabilityObserver isNetworkReachable]; } return isNetworkReachable; } - (void)configureRequest:(RKRequest *)request { request.additionalHTTPHeaders = _HTTPHeaders; request.authenticationType = self.authenticationType; request.username = self.username; request.password = self.password; request.cachePolicy = self.cachePolicy; request.cache = self.requestCache; request.queue = self.requestQueue; request.reachabilityObserver = self.reachabilityObserver; request.defaultHTTPEncoding = self.defaultHTTPEncoding; request.additionalRootCertificates = self.additionalRootCertificates; request.disableCertificateValidation = self.disableCertificateValidation; request.runLoopMode = self.runLoopMode; // If a timeoutInterval was set on the client, we'll pass it on to the request. // Otherwise, we'll let the request default to its own timeout interval. if (self.timeoutInterval) { request.timeoutInterval = self.timeoutInterval; } if (self.cacheTimeoutInterval) { request.cacheTimeoutInterval = self.cacheTimeoutInterval; } // OAuth 1 Parameters request.OAuth1AccessToken = self.OAuth1AccessToken; request.OAuth1AccessTokenSecret = self.OAuth1AccessTokenSecret; request.OAuth1ConsumerKey = self.OAuth1ConsumerKey; request.OAuth1ConsumerSecret = self.OAuth1ConsumerSecret; // OAuth2 Parameters request.OAuth2AccessToken = self.OAuth2AccessToken; request.OAuth2RefreshToken = self.OAuth2RefreshToken; } - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)header { [_HTTPHeaders setValue:value forKey:header]; } - (void)addRootCertificate:(SecCertificateRef)cert { [_additionalRootCertificates addObject:(id)cert]; } - (void)reachabilityObserverDidChange:(NSDictionary *)change { RKReachabilityObserver *oldReachabilityObserver = [change objectForKey:NSKeyValueChangeOldKey]; RKReachabilityObserver *newReachabilityObserver = [change objectForKey:NSKeyValueChangeNewKey]; if (! [oldReachabilityObserver isEqual:[NSNull null]]) { RKLogDebug(@"Reachability observer changed for RKClient %@, disposing of previous instance: %@", self, oldReachabilityObserver); // Cleanup if changed immediately after client init [[NSNotificationCenter defaultCenter] removeObserver:self name:RKReachabilityWasDeterminedNotification object:oldReachabilityObserver]; } if (! [newReachabilityObserver isEqual:[NSNull null]]) { // Suspend the queue until reachability to our new hostname is established if (! [newReachabilityObserver isReachabilityDetermined]) { self.requestQueue.suspended = YES; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityWasDetermined:) name:RKReachabilityWasDeterminedNotification object:newReachabilityObserver]; RKLogDebug(@"Reachability observer changed for client %@, suspending queue %@ until reachability to host '%@' can be determined", self, self.requestQueue, newReachabilityObserver.host); // Maintain a flag for Reachability determination status. This ensures that we can do the right thing in the // event that the requestQueue is changed while we are in an inderminate suspension state _awaitingReachabilityDetermination = YES; } else { self.requestQueue.suspended = NO; RKLogDebug(@"Reachability observer changed for client %@, unsuspending queue %@ as new observer already has determined reachability to %@", self, self.requestQueue, newReachabilityObserver.host); _awaitingReachabilityDetermination = NO; } } } - (void)baseURLDidChange:(NSDictionary *)change { RKURL *newBaseURL = [change objectForKey:NSKeyValueChangeNewKey]; // Don't crash if baseURL is nil'd out (i.e. dealloc) if (! [newBaseURL isEqual:[NSNull null]]) { // Configure a cache for the new base URL [_requestCache release]; _requestCache = [[RKRequestCache alloc] initWithPath:[self cachePath] storagePolicy:RKRequestCacheStoragePolicyPermanently]; // Determine reachability strategy (if user has not already done so) if (self.reachabilityObserver == nil) { NSString *hostName = [newBaseURL host]; if ([hostName isEqualToString:@"localhost"] || [hostName isIPAddress]) { self.reachabilityObserver = [RKReachabilityObserver reachabilityObserverForHost:hostName]; } else { self.reachabilityObserver = [RKReachabilityObserver reachabilityObserverForInternet]; } } } } - (void)requestQueueDidChange:(NSDictionary *)change { if (! _awaitingReachabilityDetermination) { return; } // If we are awaiting reachability determination, suspend the new queue RKRequestQueue *newQueue = [change objectForKey:NSKeyValueChangeNewKey]; if (! [newQueue isEqual:[NSNull null]]) { // The request queue has changed while we were awaiting reachability. // Suspend the queue until reachability is determined newQueue.suspended = !self.reachabilityObserver.reachabilityDetermined; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"baseURL"]) { [self baseURLDidChange:change]; } else if ([keyPath isEqualToString:@"requestQueue"]) { [self requestQueueDidChange:change]; } else if ([keyPath isEqualToString:@"reachabilityObserver"]) { [self reachabilityObserverDidChange:change]; } } - (RKRequest *)requestWithResourcePath:(NSString *)resourcePath { RKRequest *request = [[RKRequest alloc] initWithURL:[self.baseURL URLByAppendingResourcePath:resourcePath]]; [self configureRequest:request]; [request autorelease]; return request; } - (RKRequest *)requestWithResourcePath:(NSString *)resourcePath delegate:(NSObject<RKRequestDelegate> *)delegate { RKRequest *request = [self requestWithResourcePath:resourcePath]; request.delegate = delegate; return request; } /////////////////////////////////////////////////////////////////////////////////////////////////////////// // Asynchronous Requests /////////////////////////////////////////////////////////////////////////////////////////////////////////// - (RKRequest *)load:(NSString *)resourcePath method:(RKRequestMethod)method params:(NSObject<RKRequestSerializable> *)params delegate:(id)delegate { RKURL* resourcePathURL = nil; if (method == RKRequestMethodGET) { resourcePathURL = [self.baseURL URLByAppendingResourcePath:resourcePath queryParameters:(NSDictionary *)params]; } else { resourcePathURL = [self.baseURL URLByAppendingResourcePath:resourcePath]; } RKRequest *request = [RKRequest requestWithURL:resourcePathURL]; request.delegate = delegate; [self configureRequest:request]; request.method = method; if (method != RKRequestMethodGET) { request.params = params; } [request send]; return request; } - (RKRequest *)get:(NSString *)resourcePath delegate:(id)delegate { return [self load:resourcePath method:RKRequestMethodGET params:nil delegate:delegate]; } - (RKRequest *)get:(NSString *)resourcePath queryParameters:(NSDictionary *)queryParameters delegate:(id)delegate { return [self load:resourcePath method:RKRequestMethodGET params:queryParameters delegate:delegate]; } - (RKRequest *)post:(NSString *)resourcePath params:(NSObject<RKRequestSerializable> *)params delegate:(id)delegate { return [self load:resourcePath method:RKRequestMethodPOST params:params delegate:delegate]; } - (RKRequest *)put:(NSString *)resourcePath params:(NSObject<RKRequestSerializable> *)params delegate:(id)delegate { return [self load:resourcePath method:RKRequestMethodPUT params:params delegate:delegate]; } - (RKRequest *)delete:(NSString *)resourcePath delegate:(id)delegate { return [self load:resourcePath method:RKRequestMethodDELETE params:nil delegate:delegate]; } - (void)serviceDidBecomeUnavailableNotification:(NSNotification *)notification { if (self.serviceUnavailableAlertEnabled) { RKAlertWithTitle(self.serviceUnavailableAlertMessage, self.serviceUnavailableAlertTitle); } } - (void)reachabilityWasDetermined:(NSNotification *)notification { RKReachabilityObserver *observer = (RKReachabilityObserver *) [notification object]; NSAssert(observer == self.reachabilityObserver, @"Received unexpected reachability notification from inappropriate reachability observer"); RKLogDebug(@"Reachability to host '%@' determined for client %@, unsuspending queue %@", observer.host, self, self.requestQueue); _awaitingReachabilityDetermination = NO; self.requestQueue.suspended = NO; [[NSNotificationCenter defaultCenter] removeObserver:self name:RKReachabilityWasDeterminedNotification object:observer]; } #pragma mark - Deprecations // deprecated - (RKRequestCache *)cache { return _requestCache; } // deprecated - (void)setCache:(RKRequestCache *)requestCache { self.requestCache = requestCache; } #pragma mark - Block Request Dispatching - (RKRequest *)sendRequestToResourcePath:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block { RKRequest *request = [self requestWithResourcePath:resourcePath]; if (block) block(request); [request send]; return request; } - (void)get:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block { [self sendRequestToResourcePath:resourcePath usingBlock:^(RKRequest *request) { request.method = RKRequestMethodGET; block(request); }]; } - (void)post:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block { [self sendRequestToResourcePath:resourcePath usingBlock:^(RKRequest *request) { request.method = RKRequestMethodPOST; block(request); }]; } - (void)put:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block { [self sendRequestToResourcePath:resourcePath usingBlock:^(RKRequest *request) { request.method = RKRequestMethodPUT; block(request); }]; } - (void)delete:(NSString *)resourcePath usingBlock:(void (^)(RKRequest *request))block { [self sendRequestToResourcePath:resourcePath usingBlock:^(RKRequest *request) { request.method = RKRequestMethodDELETE; block(request); }]; } // deprecated - (BOOL)isNetworkAvailable { return [self isNetworkReachable]; } - (NSString *)resourcePath:(NSString *)resourcePath withQueryParams:(NSDictionary *)queryParams { return RKPathAppendQueryParams(resourcePath, queryParams); } - (NSURL *)URLForResourcePath:(NSString *)resourcePath { return [self.baseURL URLByAppendingResourcePath:resourcePath]; } - (NSString *)URLPathForResourcePath:(NSString *)resourcePath { return [[self URLForResourcePath:resourcePath] absoluteString]; } - (NSURL *)URLForResourcePath:(NSString *)resourcePath queryParams:(NSDictionary *)queryParams { return [self.baseURL URLByAppendingResourcePath:resourcePath queryParameters:queryParams]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKClient.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKNotifications.h
// // RKNotifications.h // RestKit // // Created by Blake Watters on 9/24/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> /** Request Auditing RKClient exposes a set of NSNotifications that can be used to audit the request/response cycle of your application. This is useful for doing things like generating automatic logging for all your requests or sending the response times. */ extern NSString * const RKRequestSentNotification; extern NSString * const RKRequestDidLoadResponseNotification; extern NSString * const RKRequestDidLoadResponseNotificationUserInfoResponseKey; extern NSString * const RKRequestDidFailWithErrorNotification; extern NSString * const RKRequestDidFailWithErrorNotificationUserInfoErrorKey; extern NSString * const RKRequestDidFinishLoadingNotification; extern NSString * const RKServiceDidBecomeUnavailableNotification;
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKNotifications.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKNotifications.m
// // RKNotifications.m // RestKit // // Created by Blake Watters on 9/24/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKNotifications.h" NSString * const RKRequestSentNotification = @"RKRequestSentNotification"; NSString * const RKRequestDidFailWithErrorNotification = @"RKRequestDidFailWithErrorNotification"; NSString * const RKRequestDidFailWithErrorNotificationUserInfoErrorKey = @"error"; NSString * const RKRequestDidLoadResponseNotification = @"RKRequestDidLoadResponseNotification"; NSString * const RKRequestDidLoadResponseNotificationUserInfoResponseKey = @"response"; NSString * const RKServiceDidBecomeUnavailableNotification = @"RKServiceDidBecomeUnavailableNotification"; NSString * const RKRequestDidFinishLoadingNotification = @"RKRequestDidFinishLoadingNotification";
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKNotifications.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKOAuthClient.h
// // RKOAuthClient.h // RestKit // // Created by Rodrigo Garcia on 7/20/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> #import "RKClient.h" #import "RKRequest.h" /** Defines error codes for OAuth client errors that are returned via a callback to RKOAuthClient's delegate */ typedef enum RKOAuthClientErrors { /** An invalid authorization code was encountered */ RKOAuthClientErrorInvalidGrant = 3001, /** The client is not authorized to perform the action */ RKOAuthClientErrorUnauthorizedClient = 3002, /** Client authentication failed (e.g. unknown client, no client authentication included, or unsupported authentication method). */ RKOAuthClientErrorInvalidClient = 3003, /** The request is missing a required parameter, includes an unsupported parameter value, repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed. */ RKOAuthClientErrorInvalidRequest = 3004, /** The authorization grant type is not supported by the authorization server. */ RKOAuthClientErrorUnsupportedGrantType = 3005, /** The requested scope is invalid, unknown, malformed, or exceeds the scope granted by the resource owner. */ RKOAuthClientErrorInvalidScope = 3006, /** An underlying RKRequest failed due to an error. The userInfo dictionary will contain an NSUnderlyingErrorKey with the details of the failure */ RKOAuthClientErrorRequestFailure = 3007, /** Error was encountered and error_description unknown */ RKOAuthClientErrorUnknown = 0 } RKOAuthClientErrorCode; @protocol RKOAuthClientDelegate; /** An OAuth client implementation that conforms to RKRequestDelegate to handle the authentication involved with the OAuth 2 authorization code flow. RKOAuthClient sets up a pre-configured RKRequest and RKResponse handler to give easy access to retrieving an access token and handling errors through RKOAuthClientDelegate. **Example**: RKOAuthClient *oauthClient; oauthClient = [RKClientOAuth clientWithClientID:@"YOUR_CLIENT_ID" secret:@"YOUR_CLIENT_SECRET" delegate:yourDelegate]; oauthClient.authorizationCode = @"AUTHORIZATION_CODE"; oauthClient.authorizationURL = @"https://foursquare.com/oauth2/authenticate"; oauthClient.callbackURL = @"https://example.com/callback"; [oauthClient validateAuthorizationCode]; From here, errors and the access token are returned through the implementation of RKOAuthClientDelegate specified. For more information on the OAuth 2 implementation, see http://tools.ietf.org/html/draft-ietf-oauth-v2-22 @see RKOAuthClientDelegate */ @interface RKOAuthClient : NSObject { NSString *_clientID; NSString *_clientSecret; NSString *_authorizationCode; NSString *_authorizationURL; NSString *_callbackURL; NSString *_accessToken; id<RKOAuthClientDelegate> _delegate; } ///----------------------------------------------------------------------------- /// @name Creating an RKOAuthClient ///----------------------------------------------------------------------------- /** Initialize a new RKOAuthClient with OAuth client credentials. @param clientID The ID of your application obtained from the OAuth provider. @param secret Confidential key obtained from the OAuth provider that is used to sign requests sent to the authentication server. @return An RKOAuthClient initialized with a client ID and secret key. */ - (id)initWithClientID:(NSString *)clientID secret:(NSString *)secret; /** Creates and returns an RKOAuthClient initialized with OAuth client credentials. @param clientID The ID of your application obtained from the OAuth provider. @param secret Confidential key obtained from the OAuth provider that is used to sign requests sent to the authentication server. @return An RKOAuthClient initialized with a client ID and secret key. */ + (RKOAuthClient *)clientWithClientID:(NSString *)clientID secret:(NSString *)secret; ///----------------------------------------------------------------------------- /// @name General properties ///----------------------------------------------------------------------------- /** A delegate that must conform to the RKOAuthClientDelegate protocol. The delegate will get callbacks such as successful access token acquisitions as well as any errors that are encountered. Reference the RKOAuthClientDelegate for more information. @see RKOAuthClientDelegate. */ @property (nonatomic, assign) id<RKOAuthClientDelegate> delegate; ///----------------------------------------------------------------------------- /// @name Client credentials ///----------------------------------------------------------------------------- /** The ID of your application obtained from the OAuth provider */ @property (nonatomic, retain) NSString *clientID; /** Confidential key obtained from the OAuth provider that is used to sign requests sent to the authentication server. */ @property (nonatomic, retain) NSString *clientSecret; ///----------------------------------------------------------------------------- /// @name Endpoints ///----------------------------------------------------------------------------- /** A string of the URL where the authorization server can be accessed */ @property (nonatomic, retain) NSString *authorizationURL; /** A string of the URL where authorization attempts will be redirected to */ @property (nonatomic, retain) NSString *callbackURL; ///----------------------------------------------------------------------------- /// @name Working with the authorization flow ///----------------------------------------------------------------------------- /** The authorization code is used in conjunction with your client secret to obtain an access token. */ @property (nonatomic, retain) NSString *authorizationCode; /** Returns the access token retrieved from the authentication server */ @property (nonatomic, readonly) NSString *accessToken; /** Fire a request to the authentication server to validate the authorization code that has been set on the authorizationCode property. All responses are handled by the delegate. @see RKOAuthClientDelegate */ - (void)validateAuthorizationCode; @end /** The delegate of an RKOAuthClient object must adopt the RKOAuthClientDelegate protocol. The protocol defines all methods relating to obtaining an accessToken and handling any errors along the way. It optionally provides callbacks for many different OAuth2 exceptions that may occur during the authorization code flow. */ @protocol RKOAuthClientDelegate <NSObject> @required ///----------------------------------------------------------------------------- /// @name Successful responses ///----------------------------------------------------------------------------- /** Sent when a new access token has been acquired @param client A reference to the RKOAuthClient that triggered the callback @param token A string of the access token acquired from the authentication server. */ - (void)OAuthClient:(RKOAuthClient *)client didAcquireAccessToken:(NSString *)token; ///----------------------------------------------------------------------------- /// @name Handling errors ///----------------------------------------------------------------------------- /** Sent when an access token request has failed due an invalid authorization code @param client A reference to the RKOAuthClient that triggered the callback @param error An NSError object containing the RKOAuthClientError that triggered the callback */ - (void)OAuthClient:(RKOAuthClient *)client didFailWithInvalidGrantError:(NSError *)error; @optional /** Sent to the delegate when the OAuth client encounters any error. @param client A reference to the RKOAuthClient that triggered the callback @param error An NSError object containing the RKOAuthClientError that triggered the callback */ - (void)OAuthClient:(RKOAuthClient *)client didFailWithError:(NSError *)error; /** Sent when the client isn't authorized to perform the requested action @param client A reference to the RKOAuthClient that triggered the callback @param error An NSError object containing the RKOAuthClientError that triggered the callback */ - (void)OAuthClient:(RKOAuthClient *)client didFailWithUnauthorizedClientError:(NSError *)error; /** Sent when an error is encountered with the OAuth client such as an unknown client, there is no client authentication included, or an unsupported authentication method was used. @param client A reference to the RKOAuthClient that triggered the callback @param error An NSError object containing the RKOAuthClientError that triggered the callback */ - (void)OAuthClient:(RKOAuthClient *)client didFailWithInvalidClientError:(NSError *)error; /** Sent when the request sent to the authentication server is invalid @param client A reference to the RKOAuthClient that triggered the callback @param error An NSError object containing the RKOAuthClientError that triggered the callback */ - (void)OAuthClient:(RKOAuthClient *)client didFailWithInvalidRequestError:(NSError *)error; /** Sent when the grant type specified isn't supported by the authentication server @param client A reference to the RKOAuthClient that triggered the callback @param error An NSError object containing the RKOAuthClientError that triggered the callback */ - (void)OAuthClient:(RKOAuthClient *)client didFailWithUnsupportedGrantTypeError:(NSError *)error; /** Sent when the requested scope is invalid, unknown, malformed, or exceeds the scope granted by the resource owner. @param client A reference to the RKOAuthClient that triggered the callback @param error An NSError object containing the RKOAuthClientError that triggered the callback */ - (void)OAuthClient:(RKOAuthClient *)client didFailWithInvalidScopeError:(NSError *)error; /** Sent to the delegate when an authorization code flow request failed due to a loading error somewhere within the RKRequest call @param client A reference to the RKOAuthClient that triggered the callback @param request A reference to the RKRequest that failed @param error An NSError object containing the RKOAuthClientError that triggered the callback */ - (void)OAuthClient:(RKOAuthClient *)client didFailLoadingRequest:(RKRequest *)request withError:(NSError *)error; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKOAuthClient.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKOAuthClient.m
// // RKOAuthClient.m // RestKit // // Created by Rodrigo Garcia on 7/20/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKOAuthClient.h" #import "RKErrors.h" @interface RKOAuthClient () <RKRequestDelegate> @end @implementation RKOAuthClient @synthesize clientID = _clientID; @synthesize clientSecret = _clientSecret; @synthesize authorizationCode = _authorizationCode; @synthesize authorizationURL = _authorizationURL; @synthesize callbackURL = _callbackURL; @synthesize delegate = _delegate; @synthesize accessToken = _accessToken; + (RKOAuthClient *)clientWithClientID:(NSString *)clientID secret:(NSString *)secret { RKOAuthClient *client = [[[self alloc] initWithClientID:clientID secret:secret] autorelease]; return client; } - (id)initWithClientID:(NSString *)clientID secret:(NSString *)secret { self = [super init]; if (self) { _clientID = [clientID copy]; _clientSecret = [secret copy]; } return self; } - (void)dealloc { [_clientID release]; [_clientSecret release]; [_accessToken release]; [super dealloc]; } - (void)validateAuthorizationCode { NSString *httpBody = [NSString stringWithFormat:@"client_id=%@&client_secret=%@&code=%@&redirect_uri=%@&grant_type=authorization_code", _clientID, _clientSecret, _authorizationCode, _callbackURL]; NSURL *URL = [NSURL URLWithString:_authorizationURL]; RKRequest *theRequest = [RKRequest requestWithURL:URL]; theRequest.delegate = self; [theRequest setHTTPBodyString:httpBody]; [theRequest setMethod:RKRequestMethodPOST]; [theRequest send]; } - (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response { NSError *error = nil; NSString *errorResponse = nil; //Use the parsedBody answer in NSDictionary NSDictionary* oauthResponse = (NSDictionary *) [response parsedBody:&error]; if ([oauthResponse isKindOfClass:[NSDictionary class]]) { //Check the if an access token comes in the response _accessToken = [[oauthResponse objectForKey:@"access_token"] copy]; errorResponse = [oauthResponse objectForKey:@"error"]; if (_accessToken) { // W00T We got an accessToken [self.delegate OAuthClient:self didAcquireAccessToken:_accessToken]; return; } else if (errorResponse) { // Heads-up! There is an error in the response // The possible errors are defined in the OAuth2 Protocol RKOAuthClientErrorCode errorCode = RKOAuthClientErrorUnknown; NSString *errorDescription = [oauthResponse objectForKey:@"error_description"]; if ([errorResponse isEqualToString:@"invalid_grant"]) { errorCode = RKOAuthClientErrorInvalidGrant; } else if([errorResponse isEqualToString:@"unauthorized_client"]){ errorCode = RKOAuthClientErrorUnauthorizedClient; } else if([errorResponse isEqualToString:@"invalid_client"]){ errorCode = RKOAuthClientErrorInvalidClient; } else if([errorResponse isEqualToString:@"invalid_request"]){ errorCode = RKOAuthClientErrorInvalidRequest; } else if([errorResponse isEqualToString:@"unsupported_grant_type"]){ errorCode = RKOAuthClientErrorUnsupportedGrantType; } else if([errorResponse isEqualToString:@"invalid_scope"]){ errorCode = RKOAuthClientErrorInvalidScope; } NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys: errorDescription, NSLocalizedDescriptionKey, nil]; NSError *error = [NSError errorWithDomain:RKErrorDomain code:errorCode userInfo:userInfo]; // Inform the delegate of what happened if ([self.delegate respondsToSelector:@selector(OAuthClient:didFailWithError:)]) { [self.delegate OAuthClient:self didFailWithError:error]; } // Invalid grant if (errorCode == RKOAuthClientErrorInvalidGrant && [self.delegate respondsToSelector:@selector(OAuthClient:didFailWithInvalidGrantError:)]) { [self.delegate OAuthClient:self didFailWithInvalidGrantError:error]; } // Unauthorized client if (errorCode == RKOAuthClientErrorUnauthorizedClient && [self.delegate respondsToSelector:@selector(OAuthClient:didFailWithUnauthorizedClientError:)]) { [self.delegate OAuthClient:self didFailWithUnauthorizedClientError:error]; } // Invalid client if (errorCode == RKOAuthClientErrorInvalidClient && [self.delegate respondsToSelector:@selector(OAuthClient:didFailWithInvalidClientError:)]) { [self.delegate OAuthClient:self didFailWithInvalidClientError:error]; } // Invalid request if (errorCode == RKOAuthClientErrorInvalidRequest && [self.delegate respondsToSelector:@selector(OAuthClient:didFailWithInvalidRequestError:)]) { [self.delegate OAuthClient:self didFailWithInvalidRequestError:error]; } // Unsupported grant type if (errorCode == RKOAuthClientErrorUnsupportedGrantType && [self.delegate respondsToSelector:@selector(OAuthClient:didFailWithUnsupportedGrantTypeError:)]) { [self.delegate OAuthClient:self didFailWithUnsupportedGrantTypeError:error]; } // Invalid scope if (errorCode == RKOAuthClientErrorInvalidScope && [self.delegate respondsToSelector:@selector(OAuthClient:didFailWithInvalidScopeError:)]) { [self.delegate OAuthClient:self didFailWithInvalidScopeError:error]; } } } else if (error) { if ([self.delegate respondsToSelector:@selector(OAuthClient:didFailWithError:)]) { [self.delegate OAuthClient:self didFailWithError:error]; } } else { // TODO: Logging... } } - (void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error { NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys: error, NSUnderlyingErrorKey, nil]; NSError *clientError = [NSError errorWithDomain:RKErrorDomain code:RKOAuthClientErrorRequestFailure userInfo:userInfo]; if ([self.delegate respondsToSelector:@selector(OAuthClient:didFailLoadingRequest:withError:)]) { [self.delegate OAuthClient:self didFailLoadingRequest:request withError:clientError]; } if ([self.delegate respondsToSelector:@selector(OAuthClient:didFailWithError:)]) { [self.delegate OAuthClient:self didFailWithError:clientError]; } } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKOAuthClient.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKParams.h
// // RKParams.h // RestKit // // Created by Blake Watters on 8/3/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> #import "RKRequestSerializable.h" #import "RKParamsAttachment.h" /** This helper class implements the RKRequestSerializable protocol to provide support for creating the multi-part request body for RKRequest objects. RKParams enables simple support for file uploading from NSData objects and files stored locally. RKParams will serialize these objects into a multi-part form representation that is suitable for submission to a remote web server for processing. After creating the RKParams object, use [RKClient post:params:delegate:] as the example below does. **Example**: RKParams *params = [RKParams params]; NSData *imageData = UIImagePNGRepresentation([_imageView image]); [params setData:imageData MIMEType:@"image/png" forParam:@"image1"]; UIImage *image = [UIImage imageNamed:@"RestKit.png"]; imageData = UIImagePNGRepresentation(image); [params setData:imageData MIMEType:@"image/png" forParam:@"image2"]; [_client post:@"/RKParamsExample" params:params delegate:self]; It is also used internally by RKRequest for its OAuth1 implementation. */ @interface RKParams : NSInputStream <RKRequestSerializable> { @private NSMutableArray *_attachments; NSStreamStatus _streamStatus; NSData *_footer; NSUInteger _bytesDelivered; NSUInteger _length; NSUInteger _footerLength; NSUInteger _currentPart; } ///----------------------------------------------------------------------------- /// @name Creating an RKParams object ///----------------------------------------------------------------------------- /** Creates and returns an RKParams object that is ready for population. @return An RKParams object to be populated. */ + (RKParams *)params; /** Creates and returns an RKParams object created from a dictionary of key/value pairs. @param dictionary NSDictionary of key/value pairs to add as RKParamsAttachment objects. @return An RKParams object with the key/value pairs of the dictionary. */ + (RKParams *)paramsWithDictionary:(NSDictionary *)dictionary; /** Initalize an RKParams object from a dictionary of key/value pairs @param dictionary NSDictionary of key/value pairs to add as RKParamsAttachment objects. @return An RKParams object with the key/value pairs of the dictionary. */ - (RKParams *)initWithDictionary:(NSDictionary *)dictionary; ///----------------------------------------------------------------------------- /// @name Working with attachments ///----------------------------------------------------------------------------- /** Array of all RKParamsAttachment attachments */ @property (nonatomic, readonly) NSMutableArray *attachments; /** Creates a new RKParamsAttachment from the key/value pair passed in and adds it to the attachments array. @param value Value of the attachment to add @param param Key name of the attachment to add @return the new RKParamsAttachment that was added to the attachments array */ - (RKParamsAttachment *)setValue:(id <NSObject>)value forParam:(NSString *)param; /** Creates a new RKParamsAttachment for a named parameter with the data contained in the file at the given path and adds it to the attachments array. @param filePath String of the path to the file to be attached @param param Key name of the attachment to add @return the new RKParamsAttachment that was added to the attachments array */ - (RKParamsAttachment *)setFile:(NSString *)filePath forParam:(NSString *)param; /** Creates a new RKParamsAttachment for a named parameter with the data given and adds it to the attachments array. A default MIME type of application/octet-stream will be used. @param data NSData object of the data to be attached @param param Key name of the attachment to add @return the new RKParamsAttachment that was added to the attachments array */ - (RKParamsAttachment *)setData:(NSData *)data forParam:(NSString *)param; /** Creates a new RKParamsAttachment for a named parameter with the data given and the MIME type specified and adds it to the attachments array. @param data NSData object of the data to be attached @param MIMEType String of the MIME type of the data @param param Key name of the attachment to add @return the new RKParamsAttachment that was added to the attachments array */ - (RKParamsAttachment *)setData:(NSData *)data MIMEType:(NSString *)MIMEType forParam:(NSString *)param; /** Creates a new RKParamsAttachment and sets the value for a named parameter to a data object with the specified MIME Type and attachment file name. @bug **DEPRECATED**: Use [RKParams setData:MIMEType:forParam:] and set the fileName on the returned RKParamsAttachment instead. @param data NSData object of the data to be attached @param MIMEType String of the MIME type of the data @param fileName String of the attachment file name @param param Key name of the attachment to add @return the new RKParamsAttachment that was added to the attachments array */ - (RKParamsAttachment *)setData:(NSData *)data MIMEType:(NSString *)MIMEType fileName:(NSString *)fileName forParam:(NSString *)param DEPRECATED_ATTRIBUTE; /** Creates a new RKParamsAttachment and sets the value for a named parameter to the data contained in a file at the given path with the specified MIME Type and attachment file name. @bug **DEPRECATED**: Use [RKParams setFile:forParam:] and set the MIMEType and fileName on the returned RKParamsAttachment instead. @param filePath String of the path to the file to be attached @param MIMEType String of the MIME type of the data @param fileName String of the attachment file name @param param Key name of the attachment to add @return the new RKParamsAttachment that was added to the attachments array */ - (RKParamsAttachment *)setFile:(NSString *)filePath MIMEType:(NSString *)MIMEType fileName:(NSString *)fileName forParam:(NSString *)param DEPRECATED_ATTRIBUTE; /** Get the dictionary of params which are plain text as specified by [RFC 5849](http://tools.ietf.org/html/rfc5849#section-3.4.1.3). This is largely used for RKClient's OAuth1 implementation. The params in this dictionary include those where: - The entity-body is single-part. - The entity-body follows the encoding requirements of the "application/x-www-form-urlencoded" content-type as defined by [W3C.REC-html40-19980424]. - The HTTP request entity-header includes the "Content-Type" header field set to "application/x-www-form-urlencoded". @return NSDictionary of key/values extracting from the RKParamsAttachment objects that meet the plain text criteria */ - (NSDictionary *)dictionaryOfPlainTextParams; ///----------------------------------------------------------------------------- /// @name Resetting and checking states ///----------------------------------------------------------------------------- /** Resets the state of the RKParams stream. */ - (void)reset; /** Return a composite MD5 checksum value for all attachments. */ - (NSString *)MD5; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKParams.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKParams.m
// // RKParams.m // RestKit // // Created by Blake Watters on 8/3/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKParams.h" #import "RKLog.h" #import "NSString+RKAdditions.h" // Need for iOS 5 UIDevice workaround #if TARGET_OS_IPHONE #import <UIKit/UIKit.h> #endif // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetwork /** * The boundary used used for multi-part headers */ NSString* const kRKStringBoundary = @"0xKhTmLbOuNdArY"; @implementation RKParams + (RKParams*)params { RKParams* params = [[[RKParams alloc] init] autorelease]; return params; } + (RKParams*)paramsWithDictionary:(NSDictionary*)dictionary { RKParams* params = [[[RKParams alloc] initWithDictionary:dictionary] autorelease]; return params; } - (id)init { self = [super init]; if (self) { _attachments = [NSMutableArray new]; _footer = [[[NSString stringWithFormat:@"--%@--\r\n", kRKStringBoundary] dataUsingEncoding:NSUTF8StringEncoding] retain]; _footerLength = [_footer length]; } return self; } - (void)dealloc { [_attachments release]; [_footer release]; [super dealloc]; } - (RKParams *)initWithDictionary:(NSDictionary *)dictionary { self = [self init]; if (self) { // NOTE: We sort the keys to try and ensure given identical dictionaries we'll wind up // with matching MD5 checksums. NSArray *sortedKeys = [[dictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; for (NSString *key in sortedKeys) { id value = [dictionary objectForKey:key]; [self setValue:value forParam:key]; } } return self; } - (RKParamsAttachment *)setValue:(id <NSObject>)value forParam:(NSString *)param { RKParamsAttachment *attachment = [[RKParamsAttachment alloc] initWithName:param value:value]; [_attachments addObject:attachment]; [attachment release]; return attachment; } - (NSDictionary *)dictionaryOfPlainTextParams { NSMutableDictionary *result = [NSMutableDictionary dictionary]; for (RKParamsAttachment *attachment in _attachments) if (attachment.value) // if the value exist, it is plain text param [result setValue:attachment.value forKey:attachment.name]; return [NSDictionary dictionaryWithDictionary:result]; } - (RKParamsAttachment *)setFile:(NSString *)filePath forParam:(NSString *)param { NSParameterAssert(filePath); NSParameterAssert(param); RKParamsAttachment *attachment = [[RKParamsAttachment alloc] initWithName:param file:filePath]; [_attachments addObject:attachment]; [attachment release]; return attachment; } - (RKParamsAttachment *)setData:(NSData *)data forParam:(NSString *)param { NSParameterAssert(data); NSParameterAssert(param); RKParamsAttachment *attachment = [[RKParamsAttachment alloc] initWithName:param data:data]; [_attachments addObject:attachment]; [attachment release]; return attachment; } - (RKParamsAttachment *)setData:(NSData *)data MIMEType:(NSString *)MIMEType forParam:(NSString *)param { NSParameterAssert(data); NSParameterAssert(MIMEType); NSParameterAssert(param); RKParamsAttachment *attachment = [self setData:data forParam:param]; if (MIMEType != nil) { attachment.MIMEType = MIMEType; } return attachment; } - (RKParamsAttachment *)setData:(NSData *)data MIMEType:(NSString *)MIMEType fileName:(NSString *)fileName forParam:(NSString *)param { NSParameterAssert(data); NSParameterAssert(param); RKParamsAttachment *attachment = [self setData:data forParam:param]; if (MIMEType) { attachment.MIMEType = MIMEType; } if (fileName) { attachment.fileName = fileName; } return attachment; } - (RKParamsAttachment *)setFile:(NSString *)filePath MIMEType:(NSString *)MIMEType fileName:(NSString *)fileName forParam:(NSString *)param { NSParameterAssert(filePath); NSParameterAssert(param); RKParamsAttachment *attachment = [self setFile:filePath forParam:param]; if (MIMEType) { attachment.MIMEType = MIMEType; } if (fileName) { attachment.fileName = fileName; } return attachment; } #pragma mark RKRequestSerializable methods - (NSString *)HTTPHeaderValueForContentType { return [NSString stringWithFormat:@"multipart/form-data; boundary=%@", kRKStringBoundary]; } - (NSUInteger)HTTPHeaderValueForContentLength { return _length; } - (void)reset { _bytesDelivered = 0; _length = 0; _streamStatus = NSStreamStatusNotOpen; } - (NSInputStream *)HTTPBodyStream { // Open each of our attachments [_attachments makeObjectsPerformSelector:@selector(open)]; // Calculate the length of the stream _length = _footerLength; for (RKParamsAttachment *attachment in _attachments) { _length += [attachment length]; } return (NSInputStream*)self; } #pragma mark NSInputStream methods - (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)maxLength { NSUInteger bytesSentInThisRead = 0, bytesRead; NSUInteger lengthOfAttachments = (_length - _footerLength); // Proxy the read through to our attachments _streamStatus = NSStreamStatusReading; while (_bytesDelivered < _length && bytesSentInThisRead < maxLength && _currentPart < [_attachments count]) { if ((bytesRead = [[_attachments objectAtIndex:_currentPart] read:buffer + bytesSentInThisRead maxLength:maxLength - bytesSentInThisRead]) == 0) { _currentPart ++; continue; } bytesSentInThisRead += bytesRead; _bytesDelivered += bytesRead; } // If we have sent all the attachments data, begin emitting the boundary footer if ((_bytesDelivered >= lengthOfAttachments) && (bytesSentInThisRead < maxLength)) { NSUInteger footerBytesSent, footerBytesRemaining, bytesRemainingInBuffer; // Calculate our position in the stream & buffer footerBytesSent = _bytesDelivered - lengthOfAttachments; footerBytesRemaining = _footerLength - footerBytesSent; bytesRemainingInBuffer = maxLength - bytesSentInThisRead; // Send the entire footer back if there is room bytesRead = (footerBytesRemaining < bytesRemainingInBuffer) ? footerBytesRemaining : bytesRemainingInBuffer; [_footer getBytes:buffer + bytesSentInThisRead range:NSMakeRange(footerBytesSent, bytesRead)]; bytesSentInThisRead += bytesRead; _bytesDelivered += bytesRead; } return bytesSentInThisRead; } - (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len { return NO; } - (BOOL)hasBytesAvailable { return _bytesDelivered < _length; } - (void)open { _streamStatus = NSStreamStatusOpen; RKLogTrace(@"RKParams stream opened..."); } - (void)close { if (_streamStatus != NSStreamStatusClosed) { _streamStatus = NSStreamStatusClosed; RKLogTrace(@"RKParams stream closed. Releasing self."); #if TARGET_OS_IPHONE // NOTE: When we are assigned to the URL request, we get // retained. We release ourselves here to ensure the retain // count will hit zero after upload is complete. // // This behavior does not seem to happen on iOS 5. This is a workaround until // the problem can be analyzed in more detail if ([[[UIDevice currentDevice] systemVersion] compare:@"5.0" options:NSNumericSearch] == NSOrderedAscending) { [self release]; } #endif } } - (NSStreamStatus)streamStatus { if (_streamStatus != NSStreamStatusClosed && _bytesDelivered >= _length) { _streamStatus = NSStreamStatusAtEnd; } return _streamStatus; } - (NSArray *)attachments { return [NSArray arrayWithArray:_attachments]; } - (NSString *)MD5 { NSMutableString *attachmentsMD5 = [[NSMutableString new] autorelease]; for (RKParamsAttachment *attachment in self.attachments) { [attachmentsMD5 appendString:[attachment MD5]]; } return [attachmentsMD5 MD5]; } #pragma mark Core Foundation stream methods - (void)_scheduleInCFRunLoop:(NSRunLoop *)runLoop forMode:(id)mode { } - (void)_setCFClientFlags:(CFOptionFlags)flags callback:(CFReadStreamClientCallBack)callback context:(CFStreamClientContext)context { } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKParams.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKParamsAttachment.h
// // RKParamsAttachment.h // RestKit // // Created by Blake Watters on 8/6/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> /** Models an individual part of a multi-part MIME document. These attachments are stacked together within the RKParams document to allow for uploading files via HTTP. Typically, interactions with the RKParamsAttachment are accomplished through the RKParams class and there shouldn't be much need to deal directly with this class. */ @interface RKParamsAttachment : NSObject { NSString *_name; NSString *_fileName; NSString *_MIMEType; @private NSString *_filePath; NSData *_body; NSInputStream *_bodyStream; NSData *_MIMEHeader; NSUInteger _MIMEHeaderLength; NSUInteger _bodyLength; NSUInteger _length; NSUInteger _delivered; id<NSObject> _value; } ///----------------------------------------------------------------------------- /// @name Creating an Attachment ///----------------------------------------------------------------------------- /** Returns a newly initialized attachment with a given parameter name and value. @param name The parameter name of this attachment in the multi-part document. @param value A value that is used to create the attachment body @return An initialized attachment with the given name and value. */ - (id)initWithName:(NSString *)name value:(id<NSObject>)value; /** Returns a newly initialized attachment with a given parameter name and the data stored in an NSData object. @param name The parameter name of this attachment in the multi-part document. @param data The data that is used to create the attachment body. @return An initialized attachment with the given name and data. */ - (id)initWithName:(NSString *)name data:(NSData *)data; /** Returns a newly initialized attachment with a given parameter name and the data stored on disk at the given file path. @param name The parameter name of this attachment in the multi-part document. @param filePath The complete path of a file to use its data contents as the attachment body. @return An initialized attachment with the name and the contents of the file at the path given. */ - (id)initWithName:(NSString *)name file:(NSString *)filePath; ///----------------------------------------------------------------------------- /// @name Working with the Attachment ///----------------------------------------------------------------------------- /** The parameter name of this attachment in the multi-part document. */ @property (nonatomic, retain) NSString *name; /** The MIME type of the attached file in the MIME stream. MIME Type will be auto-detected from the file extension of the attached file. **Default**: nil */ @property (nonatomic, retain) NSString *MIMEType; /** The MIME boundary string */ @property (nonatomic, readonly) NSString *MIMEBoundary; /** The complete path to the attached file on disk. */ @property (nonatomic, readonly) NSString *filePath; /** The name of the attached file in the MIME stream **Default**: The name of the file attached or nil if there is not one. */ @property (nonatomic, retain) NSString *fileName; /** The value that is set when initialized through initWithName:value: */ @property (nonatomic, retain) id<NSObject> value; /** Open the attachment stream to begin reading. This will generate a MIME header and prepare the attachment for writing to an RKParams stream. */ - (void)open; /** The length of the entire attachment including the MIME header and the body. @return Unsigned integer of the MIME header and the body. */ - (NSUInteger)length; /** Calculate and return an MD5 checksum for the body of this attachment. This works for simple values, NSData structures in memory, or by efficiently streaming a file and calculating an MD5. */ - (NSString *)MD5; ///----------------------------------------------------------------------------- /// @name Input streaming ///----------------------------------------------------------------------------- /** Read the attachment body in a streaming fashion for NSInputStream. @param buffer A data buffer. The buffer must be large enough to contain the number of bytes specified by len. @param len The maximum number of bytes to read. @return A number indicating the outcome of the operation: - A positive number indicates the number of bytes read; - 0 indicates that the end of the buffer was reached; - A negative number means that the operation failed. */ - (NSUInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKParamsAttachment.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKParamsAttachment.m
// // RKParamsAttachment.m // RestKit // // Created by Blake Watters on 8/6/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKParamsAttachment.h" #import "RKLog.h" #import "NSData+RKAdditions.h" #import "FileMD5Hash.h" #import "NSString+RKAdditions.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetwork /** * The multi-part boundary. See RKParams.m */ extern NSString* const kRKStringBoundary; @implementation RKParamsAttachment @synthesize filePath = _filePath; @synthesize fileName = _fileName; @synthesize MIMEType = _MIMEType; @synthesize name = _name; @synthesize value = _value; - (id)initWithName:(NSString *)name { self = [self init]; if (self) { self.name = name; self.fileName = name; } return self; } - (id)initWithName:(NSString *)name value:(id<NSObject>)value { if ((self = [self initWithName:name])) { if ([value respondsToSelector:@selector(dataUsingEncoding:)]) { _body = [[(NSString*)value dataUsingEncoding:NSUTF8StringEncoding] retain]; } else { _body = [[[NSString stringWithFormat:@"%@", value] dataUsingEncoding:NSUTF8StringEncoding] retain]; } _bodyStream = [[NSInputStream alloc] initWithData:_body]; _bodyLength = [_body length]; _value = [value retain]; } return self; } - (id)initWithName:(NSString*)name data:(NSData*)data { self = [self initWithName:name]; if (self) { _body = [data retain]; _bodyStream = [[NSInputStream alloc] initWithData:data]; _bodyLength = [data length]; } return self; } - (id)initWithName:(NSString*)name file:(NSString*)filePath { self = [self initWithName:name]; if (self) { NSAssert1([[NSFileManager defaultManager] fileExistsAtPath:filePath], @"Expected file to exist at path: %@", filePath); _filePath = [filePath retain]; _fileName = [[filePath lastPathComponent] retain]; NSString *MIMEType = [filePath MIMETypeForPathExtension]; if (! MIMEType) MIMEType = @"application/octet-stream"; _MIMEType = [MIMEType retain]; _bodyStream = [[NSInputStream alloc] initWithFileAtPath:filePath]; NSError* error; NSDictionary* attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error]; if (attributes) { _bodyLength = [[attributes objectForKey:NSFileSize] unsignedIntegerValue]; } else { RKLogError(@"Encountered an error while determining file size: %@", error); } } return self; } - (void)dealloc { [_value release]; [_name release]; [_body release]; [_filePath release]; [_fileName release]; [_MIMEType release]; [_MIMEHeader release]; _MIMEHeader = nil; [_bodyStream close]; [_bodyStream release]; _bodyStream = nil; [super dealloc]; } - (NSString*)MIMEBoundary { return kRKStringBoundary; } #pragma mark NSStream methods - (void)open { // Generate the MIME header for this part if (self.fileName && self.MIMEType) { // Typical for file attachments _MIMEHeader = [[[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; " @"filename=\"%@\"\r\nContent-Type: %@\r\n\r\n", [self MIMEBoundary], self.name, self.fileName, self.MIMEType] dataUsingEncoding:NSUTF8StringEncoding] retain]; } else if (self.MIMEType) { // Typical for data values _MIMEHeader = [[[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n" @"Content-Type: %@\r\n\r\n", [self MIMEBoundary], self.name, self.MIMEType] dataUsingEncoding:NSUTF8StringEncoding] retain]; } else { // Typical for raw values _MIMEHeader = [[[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n", [self MIMEBoundary], self.name] dataUsingEncoding:NSUTF8StringEncoding] retain]; } // Calculate lengths _MIMEHeaderLength = [_MIMEHeader length]; _length = _MIMEHeaderLength + _bodyLength + 2; // \r\n is the + 2 // Open the stream [_bodyStream open]; } - (NSUInteger)length { return _length; } - (NSUInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)maxLength { NSUInteger sent = 0, read; // We are done with the read if (_delivered >= _length) { return 0; } // First we send back the MIME headers if (_delivered < _MIMEHeaderLength && sent < maxLength) { NSUInteger headerBytesRemaining, bytesRemainingInBuffer; headerBytesRemaining = _MIMEHeaderLength - _delivered; bytesRemainingInBuffer = maxLength; // Send the entire header if there is room read = (headerBytesRemaining < bytesRemainingInBuffer) ? headerBytesRemaining : bytesRemainingInBuffer; [_MIMEHeader getBytes:buffer range:NSMakeRange(_delivered, read)]; sent += read; _delivered += sent; } // Read the attachment body out of our underlying stream while (_delivered >= _MIMEHeaderLength && _delivered < (_length - 2) && sent < maxLength) { if ((read = [_bodyStream read:(buffer + sent) maxLength:(maxLength - sent)]) == 0) { break; } sent += read; _delivered += read; } // Append the \r\n if (_delivered >= (_length - 2) && sent < maxLength) { if (_delivered == (_length - 2)) { *(buffer + sent) = '\r'; sent ++; _delivered ++; } *(buffer + sent) = '\n'; sent ++; _delivered ++; } return sent; } - (NSString *)MD5 { if (_body) { return [_body MD5]; } else if (_filePath) { CFStringRef fileAttachmentMD5 = FileMD5HashCreateWithPath((CFStringRef)_filePath, FileHashDefaultChunkSizeForReadingData); return [(NSString *)fileAttachmentMD5 autorelease]; } else { RKLogWarning(@"Failed to generate MD5 for attachment: unknown data type."); return nil; } } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKParamsAttachment.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKReachabilityObserver.h
// // RKReachabilityObserver.h // RestKit // // Created by Blake Watters on 9/14/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> #import <SystemConfiguration/SystemConfiguration.h> ///----------------------------------------------------------------------------- /// @name Constants ///----------------------------------------------------------------------------- /** Posted when the network state has changed */ extern NSString * const RKReachabilityDidChangeNotification; /** User Info key for accessing the SCNetworkReachabilityFlags from a RKReachabilityDidChangeNotification */ extern NSString * const RKReachabilityFlagsUserInfoKey; /** Posted when network state has been initially determined */ extern NSString * const RKReachabilityWasDeterminedNotification; typedef enum { /** Network reachability not yet known */ RKReachabilityIndeterminate, /** Network is not reachable */ RKReachabilityNotReachable, /** Network is reachable via a WiFi connection */ RKReachabilityReachableViaWiFi, /** Network is reachable via a "wireless wide area network" (WWAN). i.e. GPRS, Edge, 3G, etc. */ RKReachabilityReachableViaWWAN } RKReachabilityNetworkStatus; /** Provides a notification based interface for monitoring changes to network status. When initialized, creates an SCReachabilityReg and schedules it for callback notifications on the main dispatch queue. As notifications are intercepted from SystemConfiguration, the observer will update its state and emit `[RKReachabilityDidChangeNotifications](RKReachabilityDidChangeNotification)` to inform listeners about state changes. Portions of this software are derived from the Apple Reachability code sample: http://developer.apple.com/library/ios/#samplecode/Reachability/Listings/Classes_Reachability_m.html */ @interface RKReachabilityObserver : NSObject { NSString *_host; SCNetworkReachabilityRef _reachabilityRef; BOOL _reachabilityDetermined; BOOL _monitoringLocalWiFi; SCNetworkReachabilityFlags _reachabilityFlags; } ///----------------------------------------------------------------------------- /// @name Creating a Reachability Observer ///----------------------------------------------------------------------------- /** Creates and returns a RKReachabilityObserver instance observing reachability changes to the hostname or IP address referenced in a given string. The observer will monitor the ability to reach the specified remote host and emit notifications when its reachability status changes. The hostNameOrIPAddress will be introspected to determine if it contains an IP address encoded into a string or a DNS name. The observer will be configured appropriately based on the contents of the string. @bug Note that iOS 5 has known issues with hostname based reachability @param hostNameOrIPAddress An NSString containing a hostname or IP address to be observed. @return A reachability observer targeting the given hostname/IP address or nil if it could not be observed. */ + (RKReachabilityObserver *)reachabilityObserverForHost:(NSString *)hostNameOrIPAddress; /** Creates and returns a reachabilityObserverForInternet instance observing the reachability to the Internet in general. @return A reachability observer targeting INADDR_ANY or nil if it could not be observed. */ + (RKReachabilityObserver *)reachabilityObserverForInternet; /** Creates and returns a reachabilityObserverForInternet instance observing the reachability to the Internet via the local WiFi interface. Internet access available via the WWAN (3G, Edge, etc) will not be considered reachable. @return A reachability observer targeting IN_LINKLOCALNETNUM or nil if it could not be observed. */ + (RKReachabilityObserver *)reachabilityObserverForLocalWifi; /** Creates and returns a RKReachabilityObserver instance observing reachability changes to the sockaddr address provided. @param address A socket address to determine reachability for. @return A reachability observer targeting the given socket address or nil if it could not be observed. */ + (RKReachabilityObserver *)reachabilityObserverForAddress:(const struct sockaddr *)address; /** Creates and returns a RKReachabilityObserver instance observing reachability changes to the IP address provided. @param internetAddress A 32-bit integer representation of an IP address @return A reachability observer targeting the given IP address or nil if it could not be observed. */ + (RKReachabilityObserver *)reachabilityObserverForInternetAddress:(in_addr_t)internetAddress; /** Returns a RKReachabilityObserver instance observing reachability changes to the hostname or IP address referenced in a given string. The observer will monitor the ability to reach the specified remote host and emit notifications when its reachability status changes. The hostNameOrIPAddress will be introspected to determine if it contains an IP address encoded into a string or a DNS name. The observer will be configured appropriately based on the contents of the string. @bug Note that iOS 5 has known issues with hostname based reachability @param hostNameOrIPAddress An NSString containing a hostname or IP address to be observed. @return A reachability observer targeting the given hostname/IP address or nil if it could not be observed. */ - (id)initWithHost:(NSString *)hostNameOrIPAddress; /** Returns a RKReachabilityObserver instance observing reachability changes to the sockaddr address provided. @param address A socket address to determine reachability for. @return A reachability observer targeting the given socket address or nil if it could not be observed. */ - (id)initWithAddress:(const struct sockaddr *)address; ///----------------------------------------------------------------------------- /// @name Determining the Host ///----------------------------------------------------------------------------- /** The remote hostname or IP address being observed for reachability. */ @property (nonatomic, readonly) NSString *host; ///----------------------------------------------------------------------------- /// @name Managing Reachability States ///----------------------------------------------------------------------------- /** Current state of determining reachability When initialized, RKReachabilityObserver instances are in an indeterminate state to indicate that reachability status has not been yet established. After the first callback is processed by the observer, the observer will answer YES for reachabilityDetermined and networkStatus will return a determinate response. @return YES if reachability has been determined */ @property (nonatomic, readonly, getter=isReachabilityDetermined) BOOL reachabilityDetermined; /** Current network status as determined by examining the state of the currently cached reachabilityFlags @return Status of the network as RKReachabilityNetworkStatus */ @property (nonatomic, readonly) RKReachabilityNetworkStatus networkStatus; /** Current state of the local WiFi interface's reachability When the local WiFi interface is being monitored, only three reachability states are possible: - RKReachabilityIndeterminate - RKReachabilityNotReachable - RKReachabilityReachableViaWiFi If the device has connectivity through a WWAN connection only it will consider the network not reachable. @see reachabilityObserverForLocalWifi @return YES if the reachability observer is monitoring the local WiFi interface */ @property (nonatomic, readonly, getter=isMonitoringLocalWiFi) BOOL monitoringLocalWiFi; /** The reachability flags as of the last invocation of the reachability callback Each time the reachability callback is invoked with an asynchronous update of reachability status the flags are cached and made accessible via the reachabilityFlags method. Flags can also be directly obtained via [RKReachabilityObserver getFlags] @see getFlags @return The most recently cached reachability flags reflecting current network status. */ @property (nonatomic, readonly) SCNetworkReachabilityFlags reachabilityFlags; /** Acquires the current network reachability flags, answering YES if successfully acquired; answering NO otherwise. Beware! The System Configuration framework operates synchronously by default. See Technical Q&A QA1693, Synchronous Networking On The Main Thread. Asking for flags blocks the current thread and potentially kills your iOS application if the reachability enquiry does not respond before the watchdog times out. */ - (BOOL)getFlags; ///----------------------------------------------------------------------------- /// @name Reachability Introspection ///----------------------------------------------------------------------------- /** Returns YES when the Internet is reachable (via WiFi or WWAN) @exception NSInternalInconsistencyException Raises an NSInternalInconsistencyException if called before reachability is determined */ - (BOOL)isNetworkReachable; /** Returns YES when we the network is reachable via WWAN @exception NSInternalInconsistencyException Raises an NSInternalInconsistencyException if called before reachability is determined */ - (BOOL)isReachableViaWWAN; /** Returns YES when we the network is reachable via WiFi @exception NSInternalInconsistencyException Raises an NSInternalInconsistencyException if called before reachability is determined */ - (BOOL)isReachableViaWiFi; /** Returns YES when WWAN may be available, but not active until a connection has been established. @exception NSInternalInconsistencyException Raises an NSInternalInconsistencyException if called before reachability is determined */ - (BOOL)isConnectionRequired; /** Returns YES if a dynamic, on-demand connection is available @exception NSInternalInconsistencyException Raises an NSInternalInconsistencyException if called before reachability is determined */ - (BOOL)isConnectionOnDemand; /** Returns YES if user intervention is required to initiate a connection @exception NSInternalInconsistencyException Raises an NSInternalInconsistencyException if called before reachability is determined */ - (BOOL)isInterventionRequired; /** Returns a string representation of the currently cached reachabilityFlags for inspection @return A string containing single character representations of the bits in an SCNetworkReachabilityFlags */ - (NSString *)reachabilityFlagsDescription; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKReachabilityObserver.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKReachabilityObserver.m
// // RKReachabilityObserver.m // RestKit // // Created by Blake Watters on 9/14/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #if TARGET_OS_IPHONE #import <UIKit/UIKit.h> #endif #import "RKReachabilityObserver.h" #include <netdb.h> #include <arpa/inet.h> #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetworkReachability @interface RKReachabilityObserver (Private) @property (nonatomic, assign) SCNetworkReachabilityFlags reachabilityFlags; // Internal initializer - (id)initWithReachabilityRef:(SCNetworkReachabilityRef)reachabilityRef; - (void)scheduleObserver; - (void)unscheduleObserver; @end // Constants NSString* const RKReachabilityDidChangeNotification = @"RKReachabilityDidChangeNotification"; NSString* const RKReachabilityFlagsUserInfoKey = @"RKReachabilityFlagsUserInfoKey"; NSString* const RKReachabilityWasDeterminedNotification = @"RKReachabilityWasDeterminedNotification"; static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; RKReachabilityObserver *observer = (RKReachabilityObserver *) info; observer.reachabilityFlags = flags; [pool release]; } #pragma mark - @implementation RKReachabilityObserver @synthesize host = _host; @synthesize reachabilityFlags = _reachabilityFlags; @synthesize reachabilityDetermined = _reachabilityDetermined; @synthesize monitoringLocalWiFi = _monitoringLocalWiFi; + (RKReachabilityObserver *)reachabilityObserverForAddress:(const struct sockaddr *)address { return [[[self alloc] initWithAddress:address] autorelease]; } + (RKReachabilityObserver *)reachabilityObserverForInternetAddress:(in_addr_t)internetAddress { struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_len = sizeof(address); address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(internetAddress); return [self reachabilityObserverForAddress:(struct sockaddr *)&address]; } + (RKReachabilityObserver *)reachabilityObserverForInternet { return [self reachabilityObserverForInternetAddress:INADDR_ANY]; } + (RKReachabilityObserver *)reachabilityObserverForLocalWifi { return [self reachabilityObserverForInternetAddress:IN_LINKLOCALNETNUM]; } + (RKReachabilityObserver *)reachabilityObserverForHost:(NSString *)hostNameOrIPAddress { return [[[self alloc] initWithHost:hostNameOrIPAddress] autorelease]; } - (id)initWithAddress:(const struct sockaddr *)address { self = [super init]; if (self) { _reachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, address); if (_reachabilityRef == NULL) { RKLogWarning(@"Unable to initialize reachability reference"); [self release]; self = nil; } else { // For technical details regarding link-local connections, please // see the following source file at Apple's open-source site. // // http://www.opensource.apple.com/source/bootp/bootp-89/IPConfiguration.bproj/linklocal.c // _monitoringLocalWiFi = address->sa_len == sizeof(struct sockaddr_in) && address->sa_family == AF_INET && IN_LINKLOCAL(ntohl(((const struct sockaddr_in *)address)->sin_addr.s_addr)); // Save the IP address char str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &((const struct sockaddr_in *)address)->sin_addr, str, INET_ADDRSTRLEN); _host = [[NSString alloc] initWithCString:str encoding:NSUTF8StringEncoding]; if (_monitoringLocalWiFi) { RKLogInfo(@"Reachability observer initialized for Local Wifi"); } else if (address->sa_len == sizeof(struct sockaddr_in) && address->sa_family == AF_INET) { RKLogInfo(@"Reachability observer initialized with IP address: %@.", _host); } // We can immediately determine reachability to an IP address dispatch_async(dispatch_get_main_queue(), ^{ // Obtain the flags after giving other objects a chance to observe us [self getFlags]; }); // Schedule the observer [self scheduleObserver]; } } return self; } - (id)initWithHost:(NSString *)hostNameOrIPAddress { // Determine if the string contains a hostname or IP address struct sockaddr_in sa; char *hostNameOrIPAddressCString = (char *) [hostNameOrIPAddress UTF8String]; int result = inet_pton(AF_INET, hostNameOrIPAddressCString, &(sa.sin_addr)); if (result != 0) { // IP Address struct sockaddr_in remote_saddr; bzero(&remote_saddr, sizeof(struct sockaddr_in)); remote_saddr.sin_len = sizeof(struct sockaddr_in); remote_saddr.sin_family = AF_INET; inet_aton(hostNameOrIPAddressCString, &(remote_saddr.sin_addr)); return [self initWithAddress:(struct sockaddr *) &remote_saddr]; } // Hostname self = [self init]; if (self) { _host = [hostNameOrIPAddress retain]; _reachabilityRef = SCNetworkReachabilityCreateWithName(CFAllocatorGetDefault(), hostNameOrIPAddressCString); RKLogInfo(@"Reachability observer initialized with hostname %@", hostNameOrIPAddress); if (_reachabilityRef == NULL) { RKLogWarning(@"Unable to initialize reachability reference"); [self release]; self = nil; } else { [self scheduleObserver]; } } return self; } - (void)dealloc { RKLogTrace(@"Deallocating reachability observer %@", self); [[NSNotificationCenter defaultCenter] removeObserver:self]; [self unscheduleObserver]; if (_reachabilityRef) { CFRelease(_reachabilityRef); } [_host release]; [super dealloc]; } - (BOOL)getFlags { SCNetworkReachabilityFlags flags = 0; BOOL result = SCNetworkReachabilityGetFlags(_reachabilityRef, &flags); if (result) self.reachabilityFlags = flags; return result; } - (NSString *)stringFromNetworkStatus:(RKReachabilityNetworkStatus)status { switch (status) { case RKReachabilityIndeterminate: return @"RKReachabilityIndeterminate"; break; case RKReachabilityNotReachable: return @"RKReachabilityNotReachable"; break; case RKReachabilityReachableViaWiFi: return @"RKReachabilityReachableViaWiFi"; break; case RKReachabilityReachableViaWWAN: return @"RKReachabilityReachableViaWWAN"; break; default: break; } return nil; } - (NSString *)reachabilityFlagsDescription { return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c", #if TARGET_OS_IPHONE (_reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', #else // If we are not on iOS, always output a dash for WWAN '-', #endif (_reachabilityFlags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', (_reachabilityFlags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', (_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', (_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', (_reachabilityFlags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', (_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', (_reachabilityFlags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', (_reachabilityFlags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-']; } - (RKReachabilityNetworkStatus)networkStatus { NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef"); RKReachabilityNetworkStatus status = RKReachabilityNotReachable; if (!self.reachabilityDetermined) { RKLogTrace(@"Reachability observer %@ has not yet established reachability. networkStatus = %@", self, @"RKReachabilityIndeterminate"); return RKReachabilityIndeterminate; } RKLogTrace(@"Reachability Flags: %@\n", [self reachabilityFlagsDescription]); // If we are observing WiFi, we are only reachable via WiFi when flags are direct if (self.isMonitoringLocalWiFi) { if ((_reachabilityFlags & kSCNetworkReachabilityFlagsReachable) && (_reachabilityFlags & kSCNetworkReachabilityFlagsIsDirect)) { // <-- reachable AND direct status = RKReachabilityReachableViaWiFi; } else { // <-- NOT reachable OR NOT direct status = RKReachabilityNotReachable; } } else { if ((_reachabilityFlags & kSCNetworkReachabilityFlagsReachable)) { // <-- reachable #if TARGET_OS_IPHONE if ((_reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN)) { // <-- reachable AND is wireless wide-area network (iOS only) status = RKReachabilityReachableViaWWAN; } else { #endif // <-- reachable AND is NOT wireless wide-area network (iOS only) if ((_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionOnTraffic) || (_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionOnDemand)) { // <-- reachable, on-traffic OR on-demand connection if ((_reachabilityFlags & kSCNetworkReachabilityFlagsInterventionRequired)) { // <-- reachable, on-traffic OR on-demand connection, intervention required status = (_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionRequired) ? RKReachabilityNotReachable : RKReachabilityReachableViaWiFi; } else { // <-- reachable, on-traffic OR on-demand connection, intervention NOT required status = RKReachabilityReachableViaWiFi; } } else { // <-- reachable, NOT on-traffic OR on-demand connection status = (_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionRequired) ? RKReachabilityNotReachable : RKReachabilityReachableViaWiFi; } #if TARGET_OS_IPHONE } #endif } else { // <-- NOT reachable status = RKReachabilityNotReachable; } } RKLogTrace(@"Reachability observer %@ determined networkStatus = %@", self, [self stringFromNetworkStatus:status]); return status; } #pragma Reachability Flag Introspection - (void)validateIntrospection { NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); NSAssert(self.isReachabilityDetermined, @"Cannot inspect reachability state: no reachabilityFlags available. Be sure to check isReachabilityDetermined"); } - (BOOL)isNetworkReachable { [self validateIntrospection]; BOOL reachable = (RKReachabilityNotReachable != [self networkStatus]); RKLogDebug(@"Reachability observer %@ determined isNetworkReachable = %d", self, reachable); return reachable; } - (BOOL)isConnectionRequired { [self validateIntrospection]; BOOL required = (_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionRequired); RKLogDebug(@"Reachability observer %@ determined isConnectionRequired = %d", self, required); return required; } - (BOOL)isReachableViaWWAN { [self validateIntrospection]; return self.networkStatus == RKReachabilityReachableViaWWAN; } - (BOOL)isReachableViaWiFi { [self validateIntrospection]; return self.networkStatus == RKReachabilityReachableViaWiFi; } - (BOOL)isConnectionOnDemand { [self validateIntrospection]; return ((_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionRequired) && (_reachabilityFlags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand))); } - (BOOL)isInterventionRequired { [self validateIntrospection]; return ((_reachabilityFlags & kSCNetworkReachabilityFlagsConnectionRequired) && (_reachabilityFlags & kSCNetworkReachabilityFlagsInterventionRequired)); } #pragma mark Observer scheduling - (void)scheduleObserver { SCNetworkReachabilityContext context = { .info = self }; RKLogDebug(@"Scheduling reachability observer %@ in main dispatch queue", self); if (! SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) { RKLogWarning(@"%@: SCNetworkReachabilitySetCallback() failed: %s", self, SCErrorString(SCError())); return; } if (! SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, dispatch_get_main_queue())) { RKLogWarning("%@: SCNetworkReachabilitySetDispatchQueue() failed: %s", self, SCErrorString(SCError())); return; } } - (void)unscheduleObserver { if (_reachabilityRef) { RKLogDebug(@"%@: Unscheduling reachability observer from main dispatch queue", self); if (! SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, NULL)) { RKLogWarning("%@: SCNetworkReachabilitySetDispatchQueue() failed: %s\n", self, SCErrorString(SCError())); return; } } else { RKLogDebug(@"%@: Failed to unschedule reachability observer %@: reachability reference is nil.", self, _reachabilityRef); } } - (void)setReachabilityFlags:(SCNetworkReachabilityFlags)reachabilityFlags { // Save the reachability flags _reachabilityFlags = reachabilityFlags; NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:reachabilityFlags] forKey:RKReachabilityFlagsUserInfoKey]; if (! self.reachabilityDetermined) { _reachabilityDetermined = YES; RKLogInfo(@"Network availability has been determined for reachability observer %@", self); [[NSNotificationCenter defaultCenter] postNotificationName:RKReachabilityWasDeterminedNotification object:self userInfo:userInfo]; } // Post a notification to notify the client that the network reachability changed. [[NSNotificationCenter defaultCenter] postNotificationName:RKReachabilityDidChangeNotification object:self userInfo:userInfo]; } - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p host=%@ isReachabilityDetermined=%@ isMonitoringLocalWiFi=%d reachabilityFlags=%@>", NSStringFromClass([self class]), self, self.host, self.isReachabilityDetermined ? @"YES" : @"NO", self.isMonitoringLocalWiFi ? @"YES" : @"NO", [self reachabilityFlagsDescription]]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKReachabilityObserver.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequest.h
// // RKRequest.h // RestKit // // Created by Jeremy Ellison on 7/27/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #if TARGET_OS_IPHONE #import <UIKit/UIKit.h> #endif #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> #import "RKRequestSerializable.h" @class RKRequestCache; /** HTTP methods for requests */ typedef enum RKRequestMethod { RKRequestMethodInvalid = -1, RKRequestMethodGET, RKRequestMethodPOST, RKRequestMethodPUT, RKRequestMethodDELETE, RKRequestMethodHEAD } RKRequestMethod; NSString *RKRequestMethodNameFromType(RKRequestMethod); RKRequestMethod RKRequestMethodTypeFromName(NSString *); /** Cache policy for determining how to use RKCache */ typedef enum { /** Never use the cache */ RKRequestCachePolicyNone = 0, /** Load from the cache when we are offline */ RKRequestCachePolicyLoadIfOffline = 1 << 0, /** Load from the cache if we encounter an error */ RKRequestCachePolicyLoadOnError = 1 << 1, /** Load from the cache if we have data stored and the server returns a 304 (not modified) response */ RKRequestCachePolicyEtag = 1 << 2, /** Load from the cache if we have data stored */ RKRequestCachePolicyEnabled = 1 << 3, /** Load from the cache if we are within the timeout window */ RKRequestCachePolicyTimeout = 1 << 4, /** The default cache policy is etag and timeout support */ RKRequestCachePolicyDefault = RKRequestCachePolicyEtag | RKRequestCachePolicyTimeout } RKRequestCachePolicy; #if TARGET_OS_IPHONE /** Background Request Policy On iOS 4.x and higher, UIKit provides support for continuing activities for a limited amount of time in the background. RestKit provides simple support for continuing a request when in the background. */ typedef enum RKRequestBackgroundPolicy { /** Take no action with regards to backgrounding */ RKRequestBackgroundPolicyNone = 0, /** Cancel the request on transition to the background */ RKRequestBackgroundPolicyCancel, /** Continue the request in the background until time expires */ RKRequestBackgroundPolicyContinue, /** Stop the request and place it back on the queue. It will fire when the app reopens. */ RKRequestBackgroundPolicyRequeue } RKRequestBackgroundPolicy; #endif /** Authentication type for the request Based on the authentication type that is selected, authentication functionality is triggered and other options may be required. */ typedef enum { /** Disable the use of authentication */ RKRequestAuthenticationTypeNone = 0, /** Use NSURLConnection's HTTP AUTH auto-negotiation */ RKRequestAuthenticationTypeHTTP, /** Force the use of HTTP Basic authentication. This will supress AUTH challenges as RestKit will add an Authorization header establishing login via HTTP basic. This is an optimization that skips the challenge portion of the request. */ RKRequestAuthenticationTypeHTTPBasic, /** Enable the use of OAuth 1.0 authentication. OAuth1ConsumerKey, OAuth1ConsumerSecret, OAuth1AccessToken, and OAuth1AccessTokenSecret must be set when using this type. */ RKRequestAuthenticationTypeOAuth1, /** Enable the use of OAuth 2.0 authentication. OAuth2AccessToken must be set when using this type. */ RKRequestAuthenticationTypeOAuth2 } RKRequestAuthenticationType; @class RKRequest, RKResponse, RKRequestQueue, RKReachabilityObserver; @protocol RKRequestDelegate, RKConfigurationDelegate; ///----------------------------------------------------------------------------- /// @name Block Declarations ///----------------------------------------------------------------------------- typedef void(^RKRequestDidLoadResponseBlock)(RKResponse *response); typedef void(^RKRequestDidFailLoadWithErrorBlock)(NSError *error); /** Models the request portion of an HTTP request/response cycle. */ @interface RKRequest : NSObject { BOOL _sentSynchronously; NSURLConnection *_connection; id<RKRequestDelegate> _delegate; NSTimer *_timeoutTimer; RKRequestCachePolicy _cachePolicy; RKRequestDidLoadResponseBlock _onDidLoadResponse; RKRequestDidFailLoadWithErrorBlock _onDidFailLoadWithError; #if TARGET_OS_IPHONE RKRequestBackgroundPolicy _backgroundPolicy; UIBackgroundTaskIdentifier _backgroundTaskIdentifier; #endif } ///----------------------------------------------------------------------------- /// @name Creating a Request ///----------------------------------------------------------------------------- /** Creates and returns a RKRequest object initialized to load content from a provided URL. @param URL The remote URL to load @return An autoreleased RKRequest object initialized with URL. */ + (RKRequest *)requestWithURL:(NSURL *)URL; /** Initializes a RKRequest object to load from a provided URL @param URL The remote URL to load @return An RKRequest object initialized with URL. */ - (id)initWithURL:(NSURL *)URL; /** Creates and returns a RKRequest object initialized to load content from a provided URL with a specified delegate. @bug **DEPRECATED** in v0.10.0: Use [RKRequest requestWithURL:] instead @param URL The remote URL to load @param delegate The delegate that will handle the response callbacks. @return An autoreleased RKRequest object initialized with URL. */ + (RKRequest *)requestWithURL:(NSURL *)URL delegate:(id)delegate DEPRECATED_ATTRIBUTE; /** Initializes a RKRequest object to load from a provided URL @bug **DEPRECATED** in v0.10.0: Use [RKRequest initWithURL:] instead @param URL The remote URL to load @param delegate The delegate that will handle the response callbacks. @return An RKRequest object initialized with URL. */ - (id)initWithURL:(NSURL *)URL delegate:(id)delegate DEPRECATED_ATTRIBUTE; ///----------------------------------------------------------------------------- /// @name Setting Properties ///----------------------------------------------------------------------------- /** The URL this request is loading */ @property (nonatomic, retain) NSURL *URL; /** The resourcePath portion of the request's URL */ @property (nonatomic, retain) NSString *resourcePath; /** The HTTP verb in which the request is sent **Default**: RKRequestMethodGET */ @property (nonatomic, assign) RKRequestMethod method; /** Returns HTTP method as a string used for this request. This should be set through the method property using an RKRequestMethod type. @see [RKRequest method] */ @property (nonatomic, readonly) NSString *HTTPMethod; /** The response returned when the receiver was sent. */ @property (nonatomic, retain, readonly) RKResponse *response; /** A serializable collection of parameters sent as the HTTP body of the request */ @property (nonatomic, retain) NSObject<RKRequestSerializable> *params; /** A dictionary of additional HTTP Headers to send with the request */ @property (nonatomic, retain) NSDictionary *additionalHTTPHeaders; /** The run loop mode under which the underlying NSURLConnection is performed *Default*: NSRunLoopCommonModes */ @property (nonatomic, copy) NSString *runLoopMode; /** * An opaque pointer to associate user defined data with the request. */ @property (nonatomic, retain) id userData; /** The underlying NSMutableURLRequest sent for this request */ @property (nonatomic, readonly) NSMutableURLRequest *URLRequest; /** The default value used to decode HTTP body content when HTTP headers received do not provide information on the content. This encoding will be used by the RKResponse when creating the body content */ @property (nonatomic, assign) NSStringEncoding defaultHTTPEncoding; ///----------------------------------------------------------------------------- /// @name Working with the HTTP Body ///----------------------------------------------------------------------------- /** Sets the request body using the provided NSDictionary after passing the NSDictionary through serialization using the currently configured parser for the provided MIMEType. @param body An NSDictionary of key/value pairs to be serialized and sent as the HTTP body. @param MIMEType The MIMEType for the parser to use for the dictionary. */ - (void)setBody:(NSDictionary *)body forMIMEType:(NSString *)MIMEType; /** The HTTP body as a NSData used for this request */ @property (nonatomic, retain) NSData *HTTPBody; /** The HTTP body as a string used for this request */ @property (nonatomic, retain) NSString *HTTPBodyString; ///----------------------------------------------------------------------------- /// @name Delegates ///----------------------------------------------------------------------------- /** The delegate to inform when the request is completed If the object implements the RKRequestDelegate protocol, it will receive request lifecycle event messages. */ @property (nonatomic, assign) id<RKRequestDelegate> delegate; /** A delegate responsible for configuring the request. Centralizes common configuration data (such as HTTP headers, authentication information, etc) for re-use. RKClient and RKObjectManager conform to the RKConfigurationDelegate protocol. Request and object loader instances built through these objects will have a reference to their parent client/object manager assigned as the configuration delegate. **Default**: nil @see RKClient @see RKObjectManager */ @property (nonatomic, assign) id<RKConfigurationDelegate> configurationDelegate; ///----------------------------------------------------------------------------- /// @name Handling Blocks ///----------------------------------------------------------------------------- /** A block to invoke when the receiver has loaded a response. @see [RKRequestDelegate request:didLoadResponse:] */ @property (nonatomic, copy) RKRequestDidLoadResponseBlock onDidLoadResponse; /** A block to invoke when the receuver has failed loading due to an error. @see [RKRequestDelegate request:didFailLoadWithError:] */ @property (nonatomic, copy) RKRequestDidFailLoadWithErrorBlock onDidFailLoadWithError; /** Whether this request should follow server redirects or not. @default YES */ @property (nonatomic, assign) BOOL followRedirect; #if TARGET_OS_IPHONE ///----------------------------------------------------------------------------- /// @name Background Tasks ///----------------------------------------------------------------------------- /** The policy to take on transition to the background (iOS 4.x and higher only) **Default:** RKRequestBackgroundPolicyCancel */ @property (nonatomic, assign) RKRequestBackgroundPolicy backgroundPolicy; /** Returns the identifier of the task that has been sent to the background. */ @property (nonatomic, readonly) UIBackgroundTaskIdentifier backgroundTaskIdentifier; #endif ///----------------------------------------------------------------------------- /// @name Authentication ///----------------------------------------------------------------------------- /** The type of authentication to use for this request. This must be assigned one of the following: - `RKRequestAuthenticationTypeNone`: Disable the use of authentication - `RKRequestAuthenticationTypeHTTP`: Use NSURLConnection's HTTP AUTH auto-negotiation - `RKRequestAuthenticationTypeHTTPBasic`: Force the use of HTTP Basic authentication. This will supress AUTH challenges as RestKit will add an Authorization header establishing login via HTTP basic. This is an optimization that skips the challenge portion of the request. - `RKRequestAuthenticationTypeOAuth1`: Enable the use of OAuth 1.0 authentication. OAuth1ConsumerKey, OAuth1ConsumerSecret, OAuth1AccessToken, and OAuth1AccessTokenSecret must be set. - `RKRequestAuthenticationTypeOAuth2`: Enable the use of OAuth 2.0 authentication. OAuth2AccessToken must be set. **Default**: RKRequestAuthenticationTypeNone */ @property (nonatomic, assign) RKRequestAuthenticationType authenticationType; /** The username to use for authentication via HTTP AUTH. Used to respond to an authentication challenge when authenticationType is RKRequestAuthenticationTypeHTTP or RKRequestAuthenticationTypeHTTPBasic. @see authenticationType */ @property (nonatomic, retain) NSString *username; /** The password to use for authentication via HTTP AUTH. Used to respond to an authentication challenge when authenticationType is RKRequestAuthenticationTypeHTTP or RKRequestAuthenticationTypeHTTPBasic. @see authenticationType */ @property (nonatomic, retain) NSString *password; ///----------------------------------------------------------------------------- /// @name OAuth1 Secrets ///----------------------------------------------------------------------------- /** The OAuth 1.0 consumer key Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1ConsumerKey; /** The OAuth 1.0 consumer secret Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1ConsumerSecret; /** The OAuth 1.0 access token Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1AccessToken; /** The OAuth 1.0 access token secret Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1AccessTokenSecret; ///----------------------------------------------------------------------------- /// @name OAuth2 Secrets ///----------------------------------------------------------------------------- /** The OAuth 2.0 access token Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth2 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth2AccessToken; /** The OAuth 2.0 refresh token Used to retrieve a new access token before expiration and to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth2 @bug **NOT IMPLEMENTED**: This functionality is not yet implemented. @see authenticationType */ @property (nonatomic, retain) NSString *OAuth2RefreshToken; ///----------------------------------------------------------------------------- /// @name Caching ///----------------------------------------------------------------------------- /** Returns the cache key for getting/setting the cache entry for this request in the cache. The cacheKey is an MD5 value computed by hashing a combination of the destination URL, the HTTP verb, and the request body (when possible). */ @property (nonatomic, readonly) NSString *cacheKey; /** The cache policy used when storing this request into the request cache */ @property (nonatomic, assign) RKRequestCachePolicy cachePolicy; /** The request cache to store and load responses for this request. Generally configured by the RKClient instance that minted this request This must be assigned one of the following: - `RKRequestCachePolicyNone`: Never use the cache. - `RKRequestCachePolicyLoadIfOffline`: Load from the cache when offline. - `RKRequestCachePolicyLoadOnError`: Load from the cache if an error is encountered. - `RKRequestCachePolicyEtag`: Load from the cache if there is data stored and the server returns a 304 (Not Modified) response. - `RKRequestCachePolicyEnabled`: Load from the cache whenever data has been stored. - `RKRequestCachePolicyTimeout`: Load from the cache if the cacheTimeoutInterval is reached before the server responds. */ @property (nonatomic, retain) RKRequestCache *cache; /** Returns YES if the request is cacheable Only GET requests are considered cacheable (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html). */ - (BOOL)isCacheable; /** The timeout interval within which the request should not be sent and the cached response should be used. Used if the cache policy includes RKRequestCachePolicyTimeout. */ @property (nonatomic, assign) NSTimeInterval cacheTimeoutInterval; ///----------------------------------------------------------------------------- /// @name Handling SSL Validation ///----------------------------------------------------------------------------- /** Flag for disabling SSL certificate validation. When YES, SSL certificates will not be validated. *Default*: NO @warning **WARNING**: This is a potential security exposure and should be used **ONLY while debugging** in a controlled environment. */ @property (nonatomic, assign) BOOL disableCertificateValidation; /** A set of additional certificates to be used in evaluating server SSL certificates. */ @property (nonatomic, retain) NSSet *additionalRootCertificates; ///----------------------------------------------------------------------------- /// @name Sending and Managing the Request ///----------------------------------------------------------------------------- /** Setup the NSURLRequest. The request must be prepared right before dispatching. @return A boolean for the success of the URL preparation. */ - (BOOL)prepareURLRequest; /** The request queue that this request belongs to */ @property (nonatomic, assign) RKRequestQueue *queue; /** Send the request asynchronously. It will be added to the queue and dispatched as soon as possible. */ - (void)send; /** Immediately dispatch a request asynchronously, skipping the request queue. */ - (void)sendAsynchronously; /** Send the request synchronously and return a hydrated response object. @return An RKResponse object with the result of the request. */ - (RKResponse *)sendSynchronously; /** Returns a Boolean value indicating whether the request has been cancelled. @return YES if the request was sent a cancel message, otherwise NO. */ @property(nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled; /** Cancels the underlying URL connection. This will call the requestDidCancel: delegate method if your delegate responds to it. This does not subsequently set the the request's delegate to nil. However, it's good practice to cancel the RKRequest and immediately set the delegate property to nil within the delegate's dealloc method. @see NSURLConnection:cancel */ - (void)cancel; /** The reachability observer to consult for network status. Used for performing offline cache loads. Generally configured by the RKClient instance that minted this request. */ @property (nonatomic, retain) RKReachabilityObserver *reachabilityObserver; ///----------------------------------------------------------------------------- /// @name Resetting the State ///----------------------------------------------------------------------------- /** Resets the state of an RKRequest so that it can be re-sent. */ - (void)reset; ///----------------------------------------------------------------------------- /// @name Callbacks ///----------------------------------------------------------------------------- /** Callback performed to notify the request that the underlying NSURLConnection has failed with an error. @param error An NSError object containing the RKRestKitError that triggered the callback. */ - (void)didFailLoadWithError:(NSError *)error; /** Callback performed to notify the request that the underlying NSURLConnection has completed with a response. @param response An RKResponse object with the result of the request. */ - (void)didFinishLoad:(RKResponse *)response; ///----------------------------------------------------------------------------- /// @name Timing Out the Request ///----------------------------------------------------------------------------- /** The timeout interval within which the request should be cancelled if no data has been received. The timeout timer is cancelled as soon as we start receiving data and are expecting the request to finish. **Default**: 120.0 seconds */ @property (nonatomic, assign) NSTimeInterval timeoutInterval; /** Creates a timeoutTimer to trigger the timeout method This is mainly used so we can test that the timer is only being created once. */ - (void)createTimeoutTimer; /** Cancels request due to connection timeout exceeded. This method is invoked by the timeoutTimer upon its expiration and will return an RKRequestConnectionTimeoutError via didFailLoadWithError: */ - (void)timeout; /** Invalidates the timeout timer. Called by RKResponse when the NSURLConnection begins receiving data. */ - (void)invalidateTimeoutTimer; ///----------------------------------------------------------------------------- /// @name Determining the Request Type and State ///----------------------------------------------------------------------------- /** Returns YES when this is a GET request */ - (BOOL)isGET; /** Returns YES when this is a POST request */ - (BOOL)isPOST; /** Returns YES when this is a PUT request */ - (BOOL)isPUT; /** Returns YES when this is a DELETE request */ - (BOOL)isDELETE; /** Returns YES when this is a HEAD request */ - (BOOL)isHEAD; /** Returns YES when this request is in-progress */ @property (nonatomic, assign, readonly, getter = isLoading) BOOL loading; /** Returns YES when this request has been completed */ @property (nonatomic, assign, readonly, getter = isLoaded) BOOL loaded; /** Returns YES when this request has not yet been sent */ - (BOOL)isUnsent; /** Returns YES when the request was sent to the specified resource path @param resourcePath A string of the resource path that we want to check against */ - (BOOL)wasSentToResourcePath:(NSString *)resourcePath; /** Returns YES when the receiver was sent to the specified resource path with a given request method. @param resourcePath A string of the resource path that we want to check against @param method The HTTP method to confirm the request was sent with. */ - (BOOL)wasSentToResourcePath:(NSString *)resourcePath method:(RKRequestMethod)method; @end /** Lifecycle events for an RKRequest object */ @protocol RKRequestDelegate <NSObject> @optional ///----------------------------------------------------------------------------- /// @name Observing Request Progress ///----------------------------------------------------------------------------- /** Tells the delegate the request is about to be prepared for sending to the remote host. @param request The RKRequest object that is about to be sent. */ - (void)requestWillPrepareForSend:(RKRequest *)request; /** Sent when a request has received a response from the remote host. @param request The RKRequest object that received a response. @param response The RKResponse object for the HTTP response that was received. */ - (void)request:(RKRequest *)request didReceiveResponse:(RKResponse *)response; /** Sent when a request has started loading @param request The RKRequest object that has begun loading. */ - (void)requestDidStartLoad:(RKRequest *)request; /** Sent when a request has uploaded data to the remote site @param request The RKRequest object that is handling the loading. @param bytesWritten An integer of the bytes of the chunk just sent to the remote site. @param totalBytesWritten An integer of the total bytes that have been sent to the remote site. @param totalBytesExpectedToWrite An integer of the total bytes that will be sent to the remote site. */ - (void)request:(RKRequest *)request didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; /** Sent when request has received data from remote site @param request The RKRequest object that is handling the loading. @param bytesReceived An integer of the bytes of the chunk just received from the remote site. @param totalBytesReceived An integer of the total bytes that have been received from the remote site. @param totalBytesExpectedToReceive An integer of the total bytes that will be received from the remote site. */ - (void)request:(RKRequest *)request didReceiveData:(NSInteger)bytesReceived totalBytesReceived:(NSInteger)totalBytesReceived totalBytesExpectedToReceive:(NSInteger)totalBytesExpectedToReceive; ///----------------------------------------------------------------------------- /// @name Handling Successful Requests ///----------------------------------------------------------------------------- /** Sent when a request has finished loading @param request The RKRequest object that was handling the loading. @param response The RKResponse object containing the result of the request. */ - (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response; ///----------------------------------------------------------------------------- /// @name Handling Failed Requests ///----------------------------------------------------------------------------- /** Sent when a request has failed due to an error @param request The RKRequest object that was handling the loading. @param error An NSError object containing the RKRestKitError that triggered the callback. */ - (void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error; /** Sent to the delegate when a request was cancelled @param request The RKRequest object that was cancelled. */ - (void)requestDidCancelLoad:(RKRequest *)request; /** Sent to the delegate when a request has timed out. This is sent when a backgrounded request expired before completion. @param request The RKRequest object that timed out. */ - (void)requestDidTimeout:(RKRequest *)request; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequest.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequest.m
// // RKRequest.m // RestKit // // Created by Jeremy Ellison on 7/27/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKRequest.h" #import "RKResponse.h" #import "NSDictionary+RKRequestSerialization.h" #import "RKNotifications.h" #import "Support.h" #import "RKURL.h" #import "NSData+RKAdditions.h" #import "NSString+RKAdditions.h" #import "RKLog.h" #import "RKRequestCache.h" #import "GCOAuth.h" #import "NSURL+RKAdditions.h" #import "RKReachabilityObserver.h" #import "RKRequestQueue.h" #import "RKParams.h" #import "RKParserRegistry.h" #import "RKRequestSerialization.h" NSString *RKRequestMethodNameFromType(RKRequestMethod method) { switch (method) { case RKRequestMethodGET: return @"GET"; break; case RKRequestMethodPOST: return @"POST"; break; case RKRequestMethodPUT: return @"PUT"; break; case RKRequestMethodDELETE: return @"DELETE"; break; case RKRequestMethodHEAD: return @"HEAD"; break; default: break; } return nil; } RKRequestMethod RKRequestMethodTypeFromName(NSString *methodName) { if ([methodName isEqualToString:@"GET"]) { return RKRequestMethodGET; } else if ([methodName isEqualToString:@"POST"]) { return RKRequestMethodPOST; } else if ([methodName isEqualToString:@"PUT"]) { return RKRequestMethodPUT; } else if ([methodName isEqualToString:@"DELETE"]) { return RKRequestMethodDELETE; } else if ([methodName isEqualToString:@"HEAD"]) { return RKRequestMethodHEAD; } return RKRequestMethodInvalid; } // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetwork @interface RKRequest () @property (nonatomic, assign, readwrite, getter = isLoaded) BOOL loaded; @property (nonatomic, assign, readwrite, getter = isLoading) BOOL loading; @property (nonatomic, assign, readwrite, getter = isCancelled) BOOL cancelled; @property (nonatomic, retain, readwrite) RKResponse *response; @end @implementation RKRequest @class GCOAuth; @synthesize URL = _URL; @synthesize URLRequest = _URLRequest; @synthesize delegate = _delegate; @synthesize additionalHTTPHeaders = _additionalHTTPHeaders; @synthesize params = _params; @synthesize userData = _userData; @synthesize authenticationType = _authenticationType; @synthesize username = _username; @synthesize password = _password; @synthesize method = _method; @synthesize cachePolicy = _cachePolicy; @synthesize cache = _cache; @synthesize cacheTimeoutInterval = _cacheTimeoutInterval; @synthesize OAuth1ConsumerKey = _OAuth1ConsumerKey; @synthesize OAuth1ConsumerSecret = _OAuth1ConsumerSecret; @synthesize OAuth1AccessToken = _OAuth1AccessToken; @synthesize OAuth1AccessTokenSecret = _OAuth1AccessTokenSecret; @synthesize OAuth2AccessToken = _OAuth2AccessToken; @synthesize OAuth2RefreshToken = _OAuth2RefreshToken; @synthesize queue = _queue; @synthesize timeoutInterval = _timeoutInterval; @synthesize reachabilityObserver = _reachabilityObserver; @synthesize defaultHTTPEncoding = _defaultHTTPEncoding; @synthesize configurationDelegate = _configurationDelegate; @synthesize onDidLoadResponse; @synthesize onDidFailLoadWithError; @synthesize additionalRootCertificates = _additionalRootCertificates; @synthesize disableCertificateValidation = _disableCertificateValidation; @synthesize followRedirect = _followRedirect; @synthesize runLoopMode = _runLoopMode; @synthesize loaded = _loaded; @synthesize loading = _loading; @synthesize response = _response; @synthesize cancelled = _cancelled; #if TARGET_OS_IPHONE @synthesize backgroundPolicy = _backgroundPolicy; @synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier; #endif + (RKRequest*)requestWithURL:(NSURL*)URL { return [[[RKRequest alloc] initWithURL:URL] autorelease]; } - (id)initWithURL:(NSURL*)URL { self = [self init]; if (self) { _URL = [URL retain]; [self reset]; _authenticationType = RKRequestAuthenticationTypeNone; _cachePolicy = RKRequestCachePolicyDefault; _cacheTimeoutInterval = 0; _timeoutInterval = 120.0; _defaultHTTPEncoding = NSUTF8StringEncoding; _followRedirect = YES; } return self; } - (id)init { self = [super init]; if (self) { self.runLoopMode = NSRunLoopCommonModes; #if TARGET_OS_IPHONE _backgroundPolicy = RKRequestBackgroundPolicyNone; _backgroundTaskIdentifier = 0; BOOL backgroundOK = &UIBackgroundTaskInvalid != NULL; if (backgroundOK) { _backgroundTaskIdentifier = UIBackgroundTaskInvalid; } #endif } return self; } - (void)reset { if (self.isLoading) { RKLogWarning(@"Request was reset while loading: %@. Canceling.", self); [self cancel]; } [_URLRequest release]; _URLRequest = [[NSMutableURLRequest alloc] initWithURL:_URL]; [_URLRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData]; [_connection release]; _connection = nil; self.loading = NO; self.loaded = NO; self.cancelled = NO; } - (void)cleanupBackgroundTask { #if TARGET_OS_IPHONE BOOL backgroundOK = &UIBackgroundTaskInvalid != NULL; if (backgroundOK && UIBackgroundTaskInvalid == self.backgroundTaskIdentifier) { return; } UIApplication* app = [UIApplication sharedApplication]; if ([app respondsToSelector:@selector(beginBackgroundTaskWithExpirationHandler:)]) { [app endBackgroundTask:_backgroundTaskIdentifier]; _backgroundTaskIdentifier = UIBackgroundTaskInvalid; } #endif } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; self.delegate = nil; if (_onDidLoadResponse) Block_release(_onDidLoadResponse); if (_onDidFailLoadWithError) Block_release(_onDidFailLoadWithError); _delegate = nil; _configurationDelegate = nil; [_reachabilityObserver release]; _reachabilityObserver = nil; [_connection cancel]; [_connection release]; _connection = nil; [_response release]; _response = nil; [_userData release]; _userData = nil; [_URL release]; _URL = nil; [_URLRequest release]; _URLRequest = nil; [_params release]; _params = nil; [_additionalHTTPHeaders release]; _additionalHTTPHeaders = nil; [_username release]; _username = nil; [_password release]; _password = nil; [_cache release]; _cache = nil; [_OAuth1ConsumerKey release]; _OAuth1ConsumerKey = nil; [_OAuth1ConsumerSecret release]; _OAuth1ConsumerSecret = nil; [_OAuth1AccessToken release]; _OAuth1AccessToken = nil; [_OAuth1AccessTokenSecret release]; _OAuth1AccessTokenSecret = nil; [_OAuth2AccessToken release]; _OAuth2AccessToken = nil; [_OAuth2RefreshToken release]; _OAuth2RefreshToken = nil; [onDidFailLoadWithError release]; onDidFailLoadWithError = nil; [onDidLoadResponse release]; onDidLoadResponse = nil; [self invalidateTimeoutTimer]; [_timeoutTimer release]; _timeoutTimer = nil; [_runLoopMode release]; _runLoopMode = nil; // Cleanup a background task if there is any [self cleanupBackgroundTask]; [super dealloc]; } - (BOOL)shouldSendParams { return (_params && (_method != RKRequestMethodGET && _method != RKRequestMethodHEAD)); } - (void)setRequestBody { if ([self shouldSendParams]) { // Prefer the use of a stream over a raw body if ([_params respondsToSelector:@selector(HTTPBodyStream)]) { // NOTE: This causes the stream to be retained. For RKParams, this will // cause a leak unless the stream is released. See [RKParams close] [_URLRequest setHTTPBodyStream:[_params HTTPBodyStream]]; } else { [_URLRequest setHTTPBody:[_params HTTPBody]]; } } } - (NSData*)HTTPBody { return self.URLRequest.HTTPBody; } - (void)setHTTPBody:(NSData *)HTTPBody { [self.URLRequest setHTTPBody:HTTPBody]; } - (NSString*)HTTPBodyString { return [[[NSString alloc] initWithData:self.URLRequest.HTTPBody encoding:NSASCIIStringEncoding] autorelease]; } - (void)setHTTPBodyString:(NSString *)HTTPBodyString { [self.URLRequest setHTTPBody:[HTTPBodyString dataUsingEncoding:NSASCIIStringEncoding]]; } - (void)addHeadersToRequest { NSString *header = nil; for (header in _additionalHTTPHeaders) { [_URLRequest setValue:[_additionalHTTPHeaders valueForKey:header] forHTTPHeaderField:header]; } if ([self shouldSendParams]) { // Temporarily support older RKRequestSerializable implementations if ([_params respondsToSelector:@selector(HTTPHeaderValueForContentType)]) { [_URLRequest setValue:[_params HTTPHeaderValueForContentType] forHTTPHeaderField:@"Content-Type"]; } else if ([_params respondsToSelector:@selector(ContentTypeHTTPHeader)]) { [_URLRequest setValue:[_params performSelector:@selector(ContentTypeHTTPHeader)] forHTTPHeaderField:@"Content-Type"]; } if ([_params respondsToSelector:@selector(HTTPHeaderValueForContentLength)]) { [_URLRequest setValue:[NSString stringWithFormat:@"%d", [_params HTTPHeaderValueForContentLength]] forHTTPHeaderField:@"Content-Length"]; } } else { [_URLRequest setValue:@"0" forHTTPHeaderField:@"Content-Length"]; } // Add authentication headers so we don't have to deal with an extra cycle for each message requiring basic auth. if (self.authenticationType == RKRequestAuthenticationTypeHTTPBasic && _username && _password) { CFHTTPMessageRef dummyRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)[self HTTPMethod], (CFURLRef)[self URL], kCFHTTPVersion1_1); if (dummyRequest) { CFHTTPMessageAddAuthentication(dummyRequest, nil, (CFStringRef)_username, (CFStringRef)_password,kCFHTTPAuthenticationSchemeBasic, FALSE); CFStringRef authorizationString = CFHTTPMessageCopyHeaderFieldValue(dummyRequest, CFSTR("Authorization")); if (authorizationString) { [_URLRequest setValue:(NSString *)authorizationString forHTTPHeaderField:@"Authorization"]; CFRelease(authorizationString); } CFRelease(dummyRequest); } } // Add OAuth headers if necessary // OAuth 1 if(self.authenticationType == RKRequestAuthenticationTypeOAuth1){ NSURLRequest *echo = nil; // use the suitable parameters dict NSDictionary *parameters = nil; if ([self.params isKindOfClass:[RKParams class]]) parameters = [(RKParams *)self.params dictionaryOfPlainTextParams]; else parameters = [_URL queryParameters]; if (self.method == RKRequestMethodPUT) echo = [GCOAuth URLRequestForPath:[_URL path] PUTParameters:parameters scheme:[_URL scheme] host:[_URL hostAndPort] consumerKey:self.OAuth1ConsumerKey consumerSecret:self.OAuth1ConsumerSecret accessToken:self.OAuth1AccessToken tokenSecret:self.OAuth1AccessTokenSecret]; else if (self.method == RKRequestMethodPOST) echo = [GCOAuth URLRequestForPath:[_URL path] POSTParameters:parameters scheme:[_URL scheme] host:[_URL hostAndPort] consumerKey:self.OAuth1ConsumerKey consumerSecret:self.OAuth1ConsumerSecret accessToken:self.OAuth1AccessToken tokenSecret:self.OAuth1AccessTokenSecret]; else echo = [GCOAuth URLRequestForPath:[_URL path] GETParameters:[_URL queryParameters] scheme:[_URL scheme] host:[_URL hostAndPort] consumerKey:self.OAuth1ConsumerKey consumerSecret:self.OAuth1ConsumerSecret accessToken:self.OAuth1AccessToken tokenSecret:self.OAuth1AccessTokenSecret]; [_URLRequest setValue:[echo valueForHTTPHeaderField:@"Authorization"] forHTTPHeaderField:@"Authorization"]; [_URLRequest setValue:[echo valueForHTTPHeaderField:@"Accept-Encoding"] forHTTPHeaderField:@"Accept-Encoding"]; [_URLRequest setValue:[echo valueForHTTPHeaderField:@"User-Agent"] forHTTPHeaderField:@"User-Agent"]; } // OAuth 2 valid request if(self.authenticationType == RKRequestAuthenticationTypeOAuth2) { NSString *authorizationString = [NSString stringWithFormat:@"OAuth2 %@",self.OAuth2AccessToken]; [_URLRequest setValue:authorizationString forHTTPHeaderField:@"Authorization"]; } if (self.cachePolicy & RKRequestCachePolicyEtag) { NSString* etag = [self.cache etagForRequest:self]; if (etag) { RKLogTrace(@"Setting If-None-Match header to '%@'", etag); [_URLRequest setValue:etag forHTTPHeaderField:@"If-None-Match"]; } } } // Setup the NSURLRequest. The request must be prepared right before dispatching - (BOOL)prepareURLRequest { [_URLRequest setHTTPMethod:[self HTTPMethod]]; if ([self.delegate respondsToSelector:@selector(requestWillPrepareForSend:)]) { [self.delegate requestWillPrepareForSend:self]; } [self setRequestBody]; [self addHeadersToRequest]; NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding]; RKLogTrace(@"Prepared %@ URLRequest '%@'. HTTP Headers: %@. HTTP Body: %@.", [self HTTPMethod], _URLRequest, [_URLRequest allHTTPHeaderFields], body); [body release]; return YES; } - (void)cancelAndInformDelegate:(BOOL)informDelegate { self.cancelled = YES; [_connection cancel]; [_connection release]; _connection = nil; [self invalidateTimeoutTimer]; self.loading = NO; if (informDelegate && [_delegate respondsToSelector:@selector(requestDidCancelLoad:)]) { [_delegate requestDidCancelLoad:self]; } } - (NSString *)HTTPMethod { return RKRequestMethodNameFromType(self.method); } // NOTE: We could factor the knowledge about the queue out of RKRequest entirely, but it will break behavior. - (void)send { NSAssert(NO == self.isLoading || NO == self.isLoaded, @"Cannot send a request that is loading or loaded without resetting it first."); if (self.queue) { [self.queue addRequest:self]; } else { [self sendAsynchronously]; } } - (void)fireAsynchronousRequest { RKLogDebug(@"Sending asynchronous %@ request to URL %@.", [self HTTPMethod], [[self URL] absoluteString]); if (![self prepareURLRequest]) { RKLogWarning(@"Failed to send request asynchronously: prepareURLRequest returned NO."); return; } self.loading = YES; if ([self.delegate respondsToSelector:@selector(requestDidStartLoad:)]) { [self.delegate requestDidStartLoad:self]; } RKResponse* response = [[[RKResponse alloc] initWithRequest:self] autorelease]; _connection = [[[[NSURLConnection alloc] initWithRequest:_URLRequest delegate:response startImmediately:NO] autorelease] retain]; [_connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:self.runLoopMode]; [_connection start]; [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestSentNotification object:self userInfo:nil]; } - (BOOL)shouldLoadFromCache { // if RKRequestCachePolicyEnabled or if RKRequestCachePolicyTimeout and we are in the timeout if ([self.cache hasResponseForRequest:self]) { if (self.cachePolicy & RKRequestCachePolicyEnabled) { return YES; } else if (self.cachePolicy & RKRequestCachePolicyTimeout) { NSDate* date = [self.cache cacheDateForRequest:self]; NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:date]; return interval <= self.cacheTimeoutInterval; } } return NO; } - (RKResponse*)loadResponseFromCache { RKLogDebug(@"Found cached content, loading..."); return [self.cache responseForRequest:self]; } - (BOOL)shouldDispatchRequest { if (nil == self.reachabilityObserver || NO == [self.reachabilityObserver isReachabilityDetermined]) { return YES; } return [self.reachabilityObserver isNetworkReachable]; } - (void)sendAsynchronously { NSAssert(NO == self.loading || NO == self.loaded, @"Cannot send a request that is loading or loaded without resetting it first."); _sentSynchronously = NO; if ([self shouldLoadFromCache]) { RKResponse* response = [self loadResponseFromCache]; self.loading = YES; [self performSelector:@selector(didFinishLoad:) withObject:response afterDelay:0]; } else if ([self shouldDispatchRequest]) { [self createTimeoutTimer]; #if TARGET_OS_IPHONE // Background Request Policy support UIApplication* app = [UIApplication sharedApplication]; if (self.backgroundPolicy == RKRequestBackgroundPolicyNone || NO == [app respondsToSelector:@selector(beginBackgroundTaskWithExpirationHandler:)]) { // No support for background (iOS 3.x) or the policy is none -- just fire the request [self fireAsynchronousRequest]; } else if (self.backgroundPolicy == RKRequestBackgroundPolicyCancel || self.backgroundPolicy == RKRequestBackgroundPolicyRequeue) { // For cancel or requeue behaviors, we watch for background transition notifications [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackgroundNotification:) name:UIApplicationDidEnterBackgroundNotification object:nil]; [self fireAsynchronousRequest]; } else if (self.backgroundPolicy == RKRequestBackgroundPolicyContinue) { RKLogInfo(@"Beginning background task to perform processing..."); // Fork a background task for continueing a long-running request __block RKRequest* weakSelf = self; __block id<RKRequestDelegate> weakDelegate = _delegate; _backgroundTaskIdentifier = [app beginBackgroundTaskWithExpirationHandler:^{ RKLogInfo(@"Background request time expired, canceling request."); [weakSelf cancelAndInformDelegate:NO]; [weakSelf cleanupBackgroundTask]; if ([weakDelegate respondsToSelector:@selector(requestDidTimeout:)]) { [weakDelegate requestDidTimeout:weakSelf]; } }]; // Start the potentially long-running request [self fireAsynchronousRequest]; } #else [self fireAsynchronousRequest]; #endif } else { RKLogTrace(@"Declined to dispatch request %@: reachability observer reported the network is not available.", self); if (_cachePolicy & RKRequestCachePolicyLoadIfOffline && [self.cache hasResponseForRequest:self]) { self.loading = YES; [self didFinishLoad:[self loadResponseFromCache]]; } else { self.loading = YES; RKLogError(@"Failed to send request to %@ due to unreachable network. Reachability observer = %@", [[self URL] absoluteString], self.reachabilityObserver); NSString* errorMessage = [NSString stringWithFormat:@"The client is unable to contact the resource at %@", [[self URL] absoluteString]]; NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: errorMessage, NSLocalizedDescriptionKey, nil]; NSError* error = [NSError errorWithDomain:RKErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo]; [self performSelector:@selector(didFailLoadWithError:) withObject:error afterDelay:0]; } } } - (RKResponse*)sendSynchronously { NSAssert(NO == self.loading || NO == self.loaded, @"Cannot send a request that is loading or loaded without resetting it first."); NSHTTPURLResponse* URLResponse = nil; NSError* error; NSData* payload = nil; RKResponse* response = nil; _sentSynchronously = YES; if ([self shouldLoadFromCache]) { response = [self loadResponseFromCache]; self.loading = YES; [self didFinishLoad:response]; } else if ([self shouldDispatchRequest]) { RKLogDebug(@"Sending synchronous %@ request to URL %@.", [self HTTPMethod], [[self URL] absoluteString]); if (![self prepareURLRequest]) { RKLogWarning(@"Failed to send request synchronously: prepareURLRequest returned NO."); return nil; } [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestSentNotification object:self userInfo:nil]; self.loading = YES; if ([self.delegate respondsToSelector:@selector(requestDidStartLoad:)]) { [self.delegate requestDidStartLoad:self]; } _URLRequest.timeoutInterval = _timeoutInterval; payload = [NSURLConnection sendSynchronousRequest:_URLRequest returningResponse:&URLResponse error:&error]; if (payload != nil) error = nil; response = [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease]; if (error.code == NSURLErrorTimedOut) { [self timeout]; } else if (payload == nil) { [self didFailLoadWithError:error]; } else { [self didFinishLoad:response]; } } else { if (_cachePolicy & RKRequestCachePolicyLoadIfOffline && [self.cache hasResponseForRequest:self]) { response = [self loadResponseFromCache]; } else { NSString* errorMessage = [NSString stringWithFormat:@"The client is unable to contact the resource at %@", [[self URL] absoluteString]]; NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: errorMessage, NSLocalizedDescriptionKey, nil]; error = [NSError errorWithDomain:RKErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo]; [self didFailLoadWithError:error]; response = [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease]; } } return response; } - (void)cancel { [self cancelAndInformDelegate:YES]; } - (void)createTimeoutTimer { _timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:self.timeoutInterval target:self selector:@selector(timeout) userInfo:nil repeats:NO]; } - (void)timeout { [self cancelAndInformDelegate:NO]; RKLogError(@"Failed to send request to %@ due to connection timeout. Timeout interval = %f", [[self URL] absoluteString], self.timeoutInterval); NSString* errorMessage = [NSString stringWithFormat:@"The client timed out connecting to the resource at %@", [[self URL] absoluteString]]; NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys: errorMessage, NSLocalizedDescriptionKey, nil]; NSError* error = [NSError errorWithDomain:RKErrorDomain code:RKRequestConnectionTimeoutError userInfo:userInfo]; [self didFailLoadWithError:error]; } - (void)invalidateTimeoutTimer { [_timeoutTimer invalidate]; _timeoutTimer = nil; } - (void)didFailLoadWithError:(NSError*)error { if (_cachePolicy & RKRequestCachePolicyLoadOnError && [self.cache hasResponseForRequest:self]) { [self didFinishLoad:[self loadResponseFromCache]]; } else { self.loaded = YES; self.loading = NO; if ([_delegate respondsToSelector:@selector(request:didFailLoadWithError:)]) { [_delegate request:self didFailLoadWithError:error]; } if (self.onDidFailLoadWithError) { self.onDidFailLoadWithError(error); } NSDictionary* userInfo = [NSDictionary dictionaryWithObject:error forKey:RKRequestDidFailWithErrorNotificationUserInfoErrorKey]; [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidFailWithErrorNotification object:self userInfo:userInfo]; } // NOTE: This notification must be posted last as the request queue releases the request when it // receives the notification [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidFinishLoadingNotification object:self]; } - (void)updateInternalCacheDate { NSDate* date = [NSDate date]; RKLogInfo(@"Updating cache date for request %@ to %@", self, date); [self.cache setCacheDate:date forRequest:self]; } - (void)didFinishLoad:(RKResponse *)response { self.loading = NO; self.loaded = YES; RKLogInfo(@"Status Code: %ld", (long) [response statusCode]); RKLogDebug(@"Body: %@", [response bodyAsString]); self.response = response; if ((_cachePolicy & RKRequestCachePolicyEtag) && [response isNotModified]) { self.response = [self loadResponseFromCache]; [self updateInternalCacheDate]; } if (![response wasLoadedFromCache] && [response isSuccessful] && (_cachePolicy != RKRequestCachePolicyNone)) { [self.cache storeResponse:response forRequest:self]; } if ([_delegate respondsToSelector:@selector(request:didLoadResponse:)]) { [_delegate request:self didLoadResponse:self.response]; } if (self.onDidLoadResponse) { self.onDidLoadResponse(self.response); } if ([response isServiceUnavailable]) { [[NSNotificationCenter defaultCenter] postNotificationName:RKServiceDidBecomeUnavailableNotification object:self]; } NSDictionary* userInfo = [NSDictionary dictionaryWithObject:self.response forKey:RKRequestDidLoadResponseNotificationUserInfoResponseKey]; [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidLoadResponseNotification object:self userInfo:userInfo]; // NOTE: This notification must be posted last as the request queue releases the request when it // receives the notification [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidFinishLoadingNotification object:self]; } - (BOOL)isGET { return _method == RKRequestMethodGET; } - (BOOL)isPOST { return _method == RKRequestMethodPOST; } - (BOOL)isPUT { return _method == RKRequestMethodPUT; } - (BOOL)isDELETE { return _method == RKRequestMethodDELETE; } - (BOOL)isHEAD { return _method == RKRequestMethodHEAD; } - (BOOL)isUnsent { return self.loading == NO && self.loaded == NO; } - (NSString*)resourcePath { NSString* resourcePath = nil; if ([self.URL isKindOfClass:[RKURL class]]) { RKURL* url = (RKURL*)self.URL; resourcePath = url.resourcePath; } return resourcePath; } - (void)setURL:(NSURL *)URL { [URL retain]; [_URL release]; _URL = URL; _URLRequest.URL = URL; } - (void)setResourcePath:(NSString *)resourcePath { if ([self.URL isKindOfClass:[RKURL class]]) { self.URL = [(RKURL *)self.URL URLByReplacingResourcePath:resourcePath]; } else { self.URL = [RKURL URLWithBaseURL:self.URL resourcePath:resourcePath]; } } - (BOOL)wasSentToResourcePath:(NSString*)resourcePath { return [[self resourcePath] isEqualToString:resourcePath]; } - (BOOL)wasSentToResourcePath:(NSString *)resourcePath method:(RKRequestMethod)method { return (self.method == method && [self wasSentToResourcePath:resourcePath]); } - (void)appDidEnterBackgroundNotification:(NSNotification*)notification { #if TARGET_OS_IPHONE [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil]; if (self.backgroundPolicy == RKRequestBackgroundPolicyCancel) { [self cancel]; } else if (self.backgroundPolicy == RKRequestBackgroundPolicyRequeue) { // Cancel the existing request [self cancelAndInformDelegate:NO]; [self send]; } #endif } - (BOOL)isCacheable { return _method == RKRequestMethodGET; } - (NSString*)cacheKey { if (! [self isCacheable]) { return nil; } // Use [_params HTTPBody] because the URLRequest body may not have been set up yet. NSString* compositeCacheKey = nil; if (_params) { if ([_params respondsToSelector:@selector(HTTPBody)]) { compositeCacheKey = [NSString stringWithFormat:@"%@-%d-%@", self.URL, _method, [_params HTTPBody]]; } else if ([_params isKindOfClass:[RKParams class]]) { compositeCacheKey = [NSString stringWithFormat:@"%@-%d-%@", self.URL, _method, [(RKParams *)_params MD5]]; } } else { compositeCacheKey = [NSString stringWithFormat:@"%@-%d", self.URL, _method]; } NSAssert(compositeCacheKey, @"Expected a cacheKey to be generated for request %@, but got nil", compositeCacheKey); return [compositeCacheKey MD5]; } - (void)setBody:(NSDictionary *)body forMIMEType:(NSString *)MIMEType { id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:MIMEType]; NSError *error = nil; NSString* parsedValue = [parser stringFromObject:body error:&error]; RKLogTrace(@"parser=%@, error=%@, parsedValue=%@", parser, error, parsedValue); if (error == nil && parsedValue) { self.params = [RKRequestSerialization serializationWithData:[parsedValue dataUsingEncoding:NSUTF8StringEncoding] MIMEType:MIMEType]; } } // Deprecations + (RKRequest*)requestWithURL:(NSURL*)URL delegate:(id)delegate { return [[[RKRequest alloc] initWithURL:URL delegate:delegate] autorelease]; } - (id)initWithURL:(NSURL*)URL delegate:(id)delegate { self = [self initWithURL:URL]; if (self) { _delegate = delegate; } return self; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequest.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequest_Internals.h
// // RKRequest_Internals.h // RestKit // // Created by Blake Watters on 5/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // @interface RKRequest (Internals) - (BOOL)prepareURLRequest; - (void)didFailLoadWithError:(NSError*)error; - (void)finalizeLoad:(BOOL)successful; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequest_Internals.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequestCache.h
// // RKRequestCache.h // RestKit // // Created by Jeff Arena on 4/4/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKRequest.h" #import "RKResponse.h" #import "RKCache.h" /** Cache storage policy used to determines how long we keep a specific cache for. */ typedef enum { /** The cache is disabled. Attempts to store data will silently fail. */ RKRequestCacheStoragePolicyDisabled, /** Cache data for the length of the session and clear when the app exits. */ RKRequestCacheStoragePolicyForDurationOfSession, /** Cache data permanently until explicitly expired or flushed. */ RKRequestCacheStoragePolicyPermanently } RKRequestCacheStoragePolicy; /** Location of session specific cache files within the Caches path. */ extern NSString * const RKRequestCacheSessionCacheDirectory; /** Location of permanent cache files within the Caches path. */ extern NSString * const RKRequestCachePermanentCacheDirectory; /** @constant RKRequestCache Header Keys Constants for accessing cache specific X-RESTKIT headers used to store cache metadata within the cache entry. */ /** The key for accessing the date the entry was cached. **/ extern NSString * const RKRequestCacheDateHeaderKey; /** The key for accessing the status code of the cached request. **/ extern NSString * const RKRequestCacheStatusCodeHeadersKey; /** The key for accessing the MIME Type of the cached request. **/ extern NSString * const RKRequestCacheMIMETypeHeadersKey; /** The key for accessing the URL of the cached request. **/ extern NSString * const RKRequestCacheURLHeadersKey; /** Stores and retrieves cache entries for RestKit request objects. */ @interface RKRequestCache : NSObject { RKRequestCacheStoragePolicy _storagePolicy; RKCache *_cache; } ///----------------------------------------------------------------------------- /// @name Initializating the Cache ///----------------------------------------------------------------------------- /** Initializes the receiver with a cache at a given path and storage policy. @param cachePath The path to store cached data in. @param storagePolicy The storage policy to use for cached data. @return An initialized request cache object. */ - (id)initWithPath:(NSString *)cachePath storagePolicy:(RKRequestCacheStoragePolicy)storagePolicy; ///----------------------------------------------------------------------------- /// @name Locating the Cache ///----------------------------------------------------------------------------- /** Returns the full pathname to the cache. */ @property (nonatomic, readonly) NSString *path; /** Returns the cache path for the specified request. @param request An RKRequest object to determine the cache path. @return A string of the cache path for the specified request. */ - (NSString *)pathForRequest:(RKRequest *)request; /** Determine if a response exists for a request. @param request An RKRequest object that is looking for cached content. @return A boolean value for if a response exists in the cache. */ - (BOOL)hasResponseForRequest:(RKRequest *)request; ///----------------------------------------------------------------------------- /// @name Populating the Cache ///----------------------------------------------------------------------------- /** Store a request's response in the cache. @param response The response to be stored in the cache. @param request The request that retrieved the response. */ - (void)storeResponse:(RKResponse *)response forRequest:(RKRequest *)request; /** Set the cache date for a request. @param date The date the response for a request was cached. @param request The request to store the cache date for. */ - (void)setCacheDate:(NSDate *)date forRequest:(RKRequest *)request; ///----------------------------------------------------------------------------- /// @name Preparing Requests and Responses ///----------------------------------------------------------------------------- /** Returns a dictionary of cached headers for a cached request. @param request The request to retrieve cached headers for. @return An NSDictionary of the cached headers that were stored for the specified request. */ - (NSDictionary *)headersForRequest:(RKRequest *)request; /** Returns an ETag for a request if it is stored in the cached headers. @param request The request that an ETag is to be determined for. @return A string of the ETag value stored for the specified request. */ - (NSString *)etagForRequest:(RKRequest *)request; /** Returns the date of the cached request. @param request The request that needs a cache date returned. @return A date object for the cached request. */ - (NSDate *)cacheDateForRequest:(RKRequest *)request; /** Returns the cached response for a given request. @param request The request used to find the cached response. @return An RKResponse object that was cached for a given request. */ - (RKResponse *)responseForRequest:(RKRequest *)request; ///----------------------------------------------------------------------------- /// @name Invalidating the Cache ///----------------------------------------------------------------------------- /** The storage policy for the cache. */ @property (nonatomic, assign) RKRequestCacheStoragePolicy storagePolicy; /** Invalidate the cache for a given request. @param request The request that needs its cache invalidated. */ - (void)invalidateRequest:(RKRequest *)request; /** Invalidate any caches that fall under the given storage policy. @param storagePolicy The RKRequestCacheStorePolicy used to determine which caches need to be invalidated. */ - (void)invalidateWithStoragePolicy:(RKRequestCacheStoragePolicy)storagePolicy; /** Invalidate all caches on disk. */ - (void)invalidateAll; ///----------------------------------------------------------------------------- /// @name Helpers ///----------------------------------------------------------------------------- /** The date formatter used to generate the cache date for the HTTP header. */ + (NSDateFormatter *)rfc1123DateFormatter; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequestCache.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequestCache.m
// // RKRequestCache.m // RestKit // // Created by Jeff Arena on 4/4/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKRequestCache.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetworkCache NSString * const RKRequestCacheSessionCacheDirectory = @"SessionStore"; NSString * const RKRequestCachePermanentCacheDirectory = @"PermanentStore"; NSString * const RKRequestCacheHeadersExtension = @"headers"; NSString * const RKRequestCacheDateHeaderKey = @"X-RESTKIT-CACHEDATE"; NSString * const RKRequestCacheStatusCodeHeadersKey = @"X-RESTKIT-CACHED-RESPONSE-CODE"; NSString * const RKRequestCacheMIMETypeHeadersKey = @"X-RESTKIT-CACHED-MIME-TYPE"; NSString * const RKRequestCacheURLHeadersKey = @"X-RESTKIT-CACHED-URL"; static NSDateFormatter* __rfc1123DateFormatter; @implementation RKRequestCache @synthesize storagePolicy = _storagePolicy; + (NSDateFormatter*)rfc1123DateFormatter { if (__rfc1123DateFormatter == nil) { __rfc1123DateFormatter = [[NSDateFormatter alloc] init]; [__rfc1123DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; [__rfc1123DateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss 'GMT'"]; } return __rfc1123DateFormatter; } - (id)initWithPath:(NSString*)cachePath storagePolicy:(RKRequestCacheStoragePolicy)storagePolicy { self = [super init]; if (self) { _cache = [[RKCache alloc] initWithPath:cachePath subDirectories: [NSArray arrayWithObjects:RKRequestCacheSessionCacheDirectory, RKRequestCachePermanentCacheDirectory, nil]]; self.storagePolicy = storagePolicy; } return self; } - (void)dealloc { [_cache release]; _cache = nil; [super dealloc]; } - (NSString*)path { return _cache.cachePath; } - (NSString*)pathForRequest:(RKRequest*)request { NSString* pathForRequest = nil; NSString* requestCacheKey = [request cacheKey]; if (requestCacheKey) { if (_storagePolicy == RKRequestCacheStoragePolicyForDurationOfSession) { pathForRequest = [RKRequestCacheSessionCacheDirectory stringByAppendingPathComponent:requestCacheKey]; } else if (_storagePolicy == RKRequestCacheStoragePolicyPermanently) { pathForRequest = [RKRequestCachePermanentCacheDirectory stringByAppendingPathComponent:requestCacheKey]; } RKLogTrace(@"Found cacheKey '%@' for %@", pathForRequest, request); } else { RKLogTrace(@"Failed to find cacheKey for %@ due to nil cacheKey", request); } return pathForRequest; } - (BOOL)hasResponseForRequest:(RKRequest*)request { BOOL hasEntryForRequest = NO; NSString* cacheKey = [self pathForRequest:request]; if (cacheKey) { hasEntryForRequest = ([_cache hasEntry:cacheKey] && [_cache hasEntry:[cacheKey stringByAppendingPathExtension:RKRequestCacheHeadersExtension]]); } RKLogTrace(@"Determined hasResponseForRequest: %@ => %@", request, hasEntryForRequest ? @"YES" : @"NO"); return hasEntryForRequest; } - (void)storeResponse:(RKResponse*)response forRequest:(RKRequest*)request { if ([self hasResponseForRequest:request]) { [self invalidateRequest:request]; } if (_storagePolicy != RKRequestCacheStoragePolicyDisabled) { NSString* cacheKey = [self pathForRequest:request]; if (cacheKey) { [_cache writeData:response.body withCacheKey:cacheKey]; NSMutableDictionary* headers = [response.allHeaderFields mutableCopy]; if (headers) { // TODO: expose this? NSHTTPURLResponse* urlResponse = [response valueForKey:@"_httpURLResponse"]; // Cache Loaded Time [headers setObject:[[RKRequestCache rfc1123DateFormatter] stringFromDate:[NSDate date]] forKey:RKRequestCacheDateHeaderKey]; // Cache status code [headers setObject:[NSNumber numberWithInteger:urlResponse.statusCode] forKey:RKRequestCacheStatusCodeHeadersKey]; // Cache MIME Type [headers setObject:urlResponse.MIMEType forKey:RKRequestCacheMIMETypeHeadersKey]; // Cache URL [headers setObject:[urlResponse.URL absoluteString] forKey:RKRequestCacheURLHeadersKey]; // Save [_cache writeDictionary:headers withCacheKey:[cacheKey stringByAppendingPathExtension:RKRequestCacheHeadersExtension]]; } [headers release]; } } } - (RKResponse*)responseForRequest:(RKRequest*)request { RKResponse* response = nil; NSString* cacheKey = [self pathForRequest:request]; if (cacheKey) { NSData* responseData = [_cache dataForCacheKey:cacheKey]; NSDictionary* responseHeaders = [_cache dictionaryForCacheKey:[cacheKey stringByAppendingPathExtension:RKRequestCacheHeadersExtension]]; response = [[[RKResponse alloc] initWithRequest:request body:responseData headers:responseHeaders] autorelease]; } RKLogDebug(@"Found cached RKResponse '%@' for '%@'", response, request); return response; } - (NSDictionary*)headersForRequest:(RKRequest*)request { NSDictionary* headers = nil; NSString* cacheKey = [self pathForRequest:request]; if (cacheKey) { NSString* headersCacheKey = [cacheKey stringByAppendingPathExtension:RKRequestCacheHeadersExtension]; headers = [_cache dictionaryForCacheKey:headersCacheKey]; if (headers) { RKLogDebug(@"Read cached headers '%@' from headersCacheKey '%@' for '%@'", headers, headersCacheKey, request); } else { RKLogDebug(@"Read nil cached headers from headersCacheKey '%@' for '%@'", headersCacheKey, request); } } else { RKLogDebug(@"Unable to read cached headers for '%@': cacheKey not found", request); } return headers; } - (NSString*)etagForRequest:(RKRequest*)request { NSString* etag = nil; NSDictionary* responseHeaders = [self headersForRequest:request]; if (responseHeaders) { for (NSString* responseHeader in responseHeaders) { if ([[responseHeader uppercaseString] isEqualToString:[@"ETag" uppercaseString]]) { etag = [responseHeaders objectForKey:responseHeader]; } } } RKLogDebug(@"Found cached ETag '%@' for '%@'", etag, request); return etag; } - (void)setCacheDate:(NSDate*)date forRequest:(RKRequest*)request { NSString* cacheKey = [self pathForRequest:request]; if (cacheKey) { NSMutableDictionary* responseHeaders = [[self headersForRequest:request] mutableCopy]; [responseHeaders setObject:[[RKRequestCache rfc1123DateFormatter] stringFromDate:date] forKey:RKRequestCacheDateHeaderKey]; [_cache writeDictionary:responseHeaders withCacheKey:[cacheKey stringByAppendingPathExtension:RKRequestCacheHeadersExtension]]; [responseHeaders release]; } } - (NSDate*)cacheDateForRequest:(RKRequest*)request { NSDate* date = nil; NSString* dateString = nil; NSDictionary* responseHeaders = [self headersForRequest:request]; if (responseHeaders) { for (NSString* responseHeader in responseHeaders) { if ([[responseHeader uppercaseString] isEqualToString:[RKRequestCacheDateHeaderKey uppercaseString]]) { dateString = [responseHeaders objectForKey:responseHeader]; } } } date = [[RKRequestCache rfc1123DateFormatter] dateFromString:dateString]; RKLogDebug(@"Found cached date '%@' for '%@'", date, request); return date; } - (void)invalidateRequest:(RKRequest*)request { RKLogDebug(@"Invalidating cache entry for '%@'", request); NSString* cacheKey = [self pathForRequest:request]; if (cacheKey) { [_cache invalidateEntry:cacheKey]; [_cache invalidateEntry:[cacheKey stringByAppendingPathExtension:RKRequestCacheHeadersExtension]]; RKLogTrace(@"Removed cache entry at path '%@' for '%@'", cacheKey, request); } } - (void)invalidateWithStoragePolicy:(RKRequestCacheStoragePolicy)storagePolicy { if (storagePolicy != RKRequestCacheStoragePolicyDisabled) { if (storagePolicy == RKRequestCacheStoragePolicyForDurationOfSession) { [_cache invalidateSubDirectory:RKRequestCacheSessionCacheDirectory]; } else { [_cache invalidateSubDirectory:RKRequestCachePermanentCacheDirectory]; } } } - (void)invalidateAll { RKLogInfo(@"Invalidating all cache entries..."); [_cache invalidateSubDirectory:RKRequestCacheSessionCacheDirectory]; [_cache invalidateSubDirectory:RKRequestCachePermanentCacheDirectory]; } - (void)setStoragePolicy:(RKRequestCacheStoragePolicy)storagePolicy { [self invalidateWithStoragePolicy:RKRequestCacheStoragePolicyForDurationOfSession]; if (storagePolicy == RKRequestCacheStoragePolicyDisabled) { [self invalidateWithStoragePolicy:RKRequestCacheStoragePolicyPermanently]; } _storagePolicy = storagePolicy; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequestCache.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequestQueue.h
// // RKRequestQueue.h // RestKit // // Created by Blake Watters on 12/1/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> #import "RKRequest.h" @protocol RKRequestQueueDelegate; /** A lightweight queue implementation responsible for dispatching and managing RKRequest objects. */ @interface RKRequestQueue : NSObject { NSString *_name; NSMutableArray *_requests; NSMutableSet *_loadingRequests; NSObject<RKRequestQueueDelegate> *_delegate; NSUInteger _concurrentRequestsLimit; NSUInteger _requestTimeout; NSTimer *_queueTimer; BOOL _suspended; BOOL _showsNetworkActivityIndicatorWhenBusy; } ///----------------------------------------------------------------------------- /// @name Creating a Request Queue ///----------------------------------------------------------------------------- /** Creates and returns a new request queue. @return An autoreleased RKRequestQueue object. */ + (id)requestQueue; /** Returns a new retained request queue with the given name. If there is already an existing queue with the given name, nil will be returned. @param name A symbolic name for the queue. @return A new retained RKRequestQueue with the given name or nil if one already exists with the given name. */ + (id)newRequestQueueWithName:(NSString *)name; ///----------------------------------------------------------------------------- /// @name Retrieving an Existing Queue ///----------------------------------------------------------------------------- /** Returns queue with the specified name. If no queue is found with the name provided, a new queue will be initialized and returned. @param name A symbolic name for the queue. @return An existing RKRequestQueue with the given name or a new queue if none currently exist. */ + (id)requestQueueWithName:(NSString *)name; ///----------------------------------------------------------------------------- /// @name Naming Queues ///----------------------------------------------------------------------------- /** A symbolic name for the queue. Used to return existing queue references via [RKRequestQueue requestQueueWithName:] */ @property (nonatomic, retain, readonly) NSString *name; /** Determine if a queue exists with a given name. @param name The queue name to search against. @return YES when there is a queue with the given name. */ + (BOOL)requestQueueExistsWithName:(NSString *)name; ///----------------------------------------------------------------------------- /// @name Monitoring State Changes ///----------------------------------------------------------------------------- /** The delegate to inform when the request queue state machine changes. If the object implements the RKRequestQueueDelegate protocol, it will receive request lifecycle event messages. */ @property (nonatomic, assign) id<RKRequestQueueDelegate> delegate; ///----------------------------------------------------------------------------- /// @name Managing the Queue ///----------------------------------------------------------------------------- /** The number of concurrent requests supported by this queue. **Default**: 5 concurrent requests */ @property (nonatomic) NSUInteger concurrentRequestsLimit; /** Request timeout value used by the queue. **Default**: 5 minutes (300 seconds) */ @property (nonatomic, assign) NSUInteger requestTimeout; /** Returns the total number of requests in the queue. */ @property (nonatomic, readonly) NSUInteger count; /** Add an asynchronous request to the queue and send it as as soon as possible. @param request The request to be added to the queue. */ - (void)addRequest:(RKRequest *)request; /** Cancel a request that is in progress. @param request The request to be cancelled. */ - (void)cancelRequest:(RKRequest *)request; /** Cancel all requests with a given delegate. @param delegate The delegate assigned to the requests to be cancelled. */ - (void)cancelRequestsWithDelegate:(id<RKRequestDelegate>)delegate; /** Aborts all requests with a given delegate by nullifying the delegate reference and canceling the request. Useful when an object that acts as the delegate for one or more requests is being deallocated and all outstanding requests should be cancelled without generating any further delegate callbacks. @param delegate The object acting as the delegate for all enqueued requests that are to be aborted. */ - (void)abortRequestsWithDelegate:(id<RKRequestDelegate>)delegate; /** Cancel all active or pending requests. */ - (void)cancelAllRequests; /** Determine if a given request is currently in this queue. @param request The request to check the queue for. @return YES if the specified request is in this queue. */ - (BOOL)containsRequest:(RKRequest *)request; ///----------------------------------------------------------------------------- /// @name Processing Queued Requests ///----------------------------------------------------------------------------- /** Start checking for and processing requests. */ - (void)start; /** Sets the flag that determines if new load requests are allowed to reach the network. Because network requests tend to slow down performance, this property can be used to temporarily delay them. All requests made while suspended are queued, and when suspended becomes false again they are executed. */ @property (nonatomic) BOOL suspended; /** Returns the total number of requests that are currently loading. */ @property (nonatomic, readonly) NSUInteger loadingCount; #if TARGET_OS_IPHONE /** Sets the flag for showing the network activity indicatory. When YES, this queue will spin the network activity in the menu bar when it is processing requests. **Default**: NO */ @property (nonatomic) BOOL showsNetworkActivityIndicatorWhenBusy; #endif ///----------------------------------------------------------------------------- /// @name Global Queues (Deprecated) ///----------------------------------------------------------------------------- /** Returns the global queue @bug **DEPRECATED** in v0.10.0: All RKClient instances now own their own individual request queues. @see [RKClient requestQueue] @return Global request queue. */ + (RKRequestQueue *)sharedQueue DEPRECATED_ATTRIBUTE; /** Sets the global queue @bug **DEPRECATED** in v0.10.0: All RKClient instances now own their own individual request queues. @see [RKClient requestQueue] @param requestQueue The request queue to assign as the global queue. */ + (void)setSharedQueue:(RKRequestQueue *)requestQueue DEPRECATED_ATTRIBUTE; @end /** Lifecycle events for an RKRequestQueue */ @protocol RKRequestQueueDelegate <NSObject> @optional ///----------------------------------------------------------------------------- /// @name Starting and Stopping the Queue ///----------------------------------------------------------------------------- /** Sent when the queue transitions from an empty state to processing requests. @param queue The queue that began processing requests. */ - (void)requestQueueDidBeginLoading:(RKRequestQueue *)queue; /** Sent when queue transitions from a processing state to an empty start. @param queue The queue that finished processing requests. */ - (void)requestQueueDidFinishLoading:(RKRequestQueue *)queue; /** Sent when the queue has been suspended and request processing has been halted. @param queue The request queue that has been suspended. */ - (void)requestQueueWasSuspended:(RKRequestQueue *)queue; /** Sent when the queue has been unsuspended and request processing has resumed. @param queue The request queue that has resumed processing. */ - (void)requestQueueWasUnsuspended:(RKRequestQueue *)queue; ///----------------------------------------------------------------------------- /// @name Processing Requests ///----------------------------------------------------------------------------- /** Sent before queue sends a request. @param queue The queue that will process the request. @param request The request to be processed. */ - (void)requestQueue:(RKRequestQueue *)queue willSendRequest:(RKRequest *)request; /** Sent after queue has sent a request. @param queue The queue that processed the request. @param request The processed request. */ - (void)requestQueue:(RKRequestQueue *)queue didSendRequest:(RKRequest *)request; /** Sent when queue received a response for a request. @param queue The queue that received the response. @param response The response that was received. */ - (void)requestQueue:(RKRequestQueue *)queue didLoadResponse:(RKResponse *)response; /** Sent when queue has cancelled a request. @param queue The queue that cancelled the request. @param request The cancelled request. */ - (void)requestQueue:(RKRequestQueue *)queue didCancelRequest:(RKRequest *)request; /** Sent when an attempted request fails. @param queue The queue in which the request failed from. @param request The failed request. @param error An NSError object containing the RKRestKitError that caused the request to fail. */ - (void)requestQueue:(RKRequestQueue *)queue didFailRequest:(RKRequest *)request withError:(NSError *)error; @end #if TARGET_OS_IPHONE /** A category on UIApplication to allow for jointly managing the network activity indicator. Adopted from 'iOS Recipes' book: http://pragprog.com/book/cdirec/ios-recipes */ @interface UIApplication (RKNetworkActivity) /** Returns the number of network activity requests. */ @property (nonatomic, assign, readonly) NSInteger networkActivityCount; /** Push a network activity request onto the stack. */ - (void)pushNetworkActivity; /** Pop a network activity request off the stack. */ - (void)popNetworkActivity; /** Reset the network activity stack. */ - (void)resetNetworkActivity; @end #endif
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequestQueue.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequestQueue.m
// // RKRequestQueue.m // RestKit // // Created by Blake Watters on 12/1/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #if TARGET_OS_IPHONE #import <UIKit/UIKit.h> #endif #import "RKClient.h" #import "RKRequestQueue.h" #import "RKResponse.h" #import "RKNotifications.h" #import "RKLog.h" #import "RKFixCategoryBug.h" RK_FIX_CATEGORY_BUG(UIApplication_RKNetworkActivity) // Constants static NSMutableArray* RKRequestQueueInstances = nil; static const NSTimeInterval kFlushDelay = 0.3; // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetworkQueue @interface RKRequestQueue () @property (nonatomic, retain, readwrite) NSString* name; @end @implementation RKRequestQueue @synthesize name = _name; @synthesize delegate = _delegate; @synthesize concurrentRequestsLimit = _concurrentRequestsLimit; @synthesize requestTimeout = _requestTimeout; @synthesize suspended = _suspended; #if TARGET_OS_IPHONE @synthesize showsNetworkActivityIndicatorWhenBusy = _showsNetworkActivityIndicatorWhenBusy; #endif + (RKRequestQueue*)sharedQueue { RKLogWarning(@"Deprecated invocation of [RKRequestQueue sharedQueue]. Returning [RKClient sharedClient].requestQueue. Update your code to reference the queue you want explicitly."); return [RKClient sharedClient].requestQueue; } + (void)setSharedQueue:(RKRequestQueue*)requestQueue { RKLogWarning(@"Deprecated access to [RKRequestQueue setSharedQueue:]. Invoking [[RKClient sharedClient] setRequestQueue:]. Update your code to reference the specific queue instance you want."); [RKClient sharedClient].requestQueue = requestQueue; } + (id)requestQueue { return [[self new] autorelease]; } + (id)newRequestQueueWithName:(NSString*)name { if (RKRequestQueueInstances == nil) { RKRequestQueueInstances = [NSMutableArray new]; } if ([self requestQueueExistsWithName:name]) { return nil; } RKRequestQueue* queue = [self new]; queue.name = name; [RKRequestQueueInstances addObject:[NSValue valueWithNonretainedObject:queue]]; return queue; } + (id)requestQueueWithName:(NSString *)name { if (RKRequestQueueInstances == nil) { RKRequestQueueInstances = [NSMutableArray new]; } // Find existing reference NSArray *requestQueueInstances = [RKRequestQueueInstances copy]; RKRequestQueue *namedQueue = nil; for (NSValue* value in requestQueueInstances) { RKRequestQueue* queue = (RKRequestQueue*) [value nonretainedObjectValue]; if ([queue.name isEqualToString:name]) { namedQueue = queue; break; } } [requestQueueInstances release]; if (namedQueue == nil) { namedQueue = [self requestQueue]; namedQueue.name = name; [RKRequestQueueInstances addObject:[NSValue valueWithNonretainedObject:namedQueue]]; } return namedQueue; } + (BOOL)requestQueueExistsWithName:(NSString*)name { BOOL queueExists = NO; if (RKRequestQueueInstances) { NSArray *requestQueueInstances = [RKRequestQueueInstances copy]; for (NSValue* value in requestQueueInstances) { RKRequestQueue* queue = (RKRequestQueue*) [value nonretainedObjectValue]; if ([queue.name isEqualToString:name]) { queueExists = YES; break; } } [requestQueueInstances release]; } return queueExists; } - (id)init { if ((self = [super init])) { _requests = [[NSMutableArray alloc] init]; _loadingRequests = [[NSMutableSet alloc] init]; _suspended = YES; _concurrentRequestsLimit = 5; _requestTimeout = 300; _showsNetworkActivityIndicatorWhenBusy = NO; #if TARGET_OS_IPHONE BOOL backgroundOK = &UIApplicationDidEnterBackgroundNotification != NULL; if (backgroundOK) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willTransitionToBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willTransitionToForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; } #endif } return self; } - (void)removeFromNamedQueues { if (self.name) { for (NSValue* value in RKRequestQueueInstances) { RKRequestQueue* queue = (RKRequestQueue*) [value nonretainedObjectValue]; if ([queue.name isEqualToString:self.name]) { [RKRequestQueueInstances removeObject:value]; return; } } } } - (void)dealloc { RKLogDebug(@"Queue instance is being deallocated: %@", self); [[NSNotificationCenter defaultCenter] removeObserver:self]; [self removeFromNamedQueues]; [_queueTimer invalidate]; [_loadingRequests release]; _loadingRequests = nil; [_requests release]; _requests = nil; [super dealloc]; } - (NSUInteger)count { return [_requests count]; } - (NSString*)description { return [NSString stringWithFormat:@"<%@: %p name=%@ suspended=%@ requestCount=%d loadingCount=%d/%d>", NSStringFromClass([self class]), self, self.name, self.suspended ? @"YES" : @"NO", self.count, self.loadingCount, self.concurrentRequestsLimit]; } - (NSUInteger)loadingCount { return [_loadingRequests count]; } - (void)addLoadingRequest:(RKRequest*)request { if (self.loadingCount == 0) { RKLogTrace(@"Loading count increasing from 0 to 1. Firing requestQueueDidBeginLoading"); // Transitioning from empty to processing if ([_delegate respondsToSelector:@selector(requestQueueDidBeginLoading:)]) { [_delegate requestQueueDidBeginLoading:self]; } #if TARGET_OS_IPHONE if (self.showsNetworkActivityIndicatorWhenBusy) { [[UIApplication sharedApplication] pushNetworkActivity]; } #endif } @synchronized(self) { [_loadingRequests addObject:request]; } RKLogTrace(@"Loading count now %ld for queue %@", (long) self.loadingCount, self); } - (void)removeLoadingRequest:(RKRequest*)request { if (self.loadingCount == 1 && [_loadingRequests containsObject:request]) { RKLogTrace(@"Loading count decreasing from 1 to 0. Firing requestQueueDidFinishLoading"); // Transition from processing to empty if ([_delegate respondsToSelector:@selector(requestQueueDidFinishLoading:)]) { [_delegate requestQueueDidFinishLoading:self]; } #if TARGET_OS_IPHONE if (self.showsNetworkActivityIndicatorWhenBusy) { [[UIApplication sharedApplication] popNetworkActivity]; } #endif } @synchronized(self) { [_loadingRequests removeObject:request]; } RKLogTrace(@"Loading count now %ld for queue %@", (long) self.loadingCount, self); } - (void)loadNextInQueueDelayed { if (!_queueTimer) { _queueTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushDelay target:self selector:@selector(loadNextInQueue) userInfo:nil repeats:NO]; RKLogTrace(@"Timer initialized with delay %f for queue %@", kFlushDelay, self); } } - (RKRequest*)nextRequest { for (NSUInteger i = 0; i < [_requests count]; i++) { RKRequest* request = [_requests objectAtIndex:i]; if ([request isUnsent]) { return request; } } return nil; } - (void)loadNextInQueue { // We always want to dispatch requests from the main thread so the current thread does not terminate // and cause us to lose the delegate callbacks if (! [NSThread isMainThread]) { [self performSelectorOnMainThread:@selector(loadNextInQueue) withObject:nil waitUntilDone:NO]; return; } // Make sure that the Request Queue does not fire off any requests until the Reachability state has been determined. if (self.suspended) { _queueTimer = nil; [self loadNextInQueueDelayed]; RKLogTrace(@"Deferring request loading for queue %@ due to suspension", self); return; } NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; _queueTimer = nil; @synchronized(self) { RKRequest* request = [self nextRequest]; while (request && self.loadingCount < _concurrentRequestsLimit) { RKLogTrace(@"Processing request %@ in queue %@", request, self); if ([_delegate respondsToSelector:@selector(requestQueue:willSendRequest:)]) { [_delegate requestQueue:self willSendRequest:request]; } [self addLoadingRequest:request]; RKLogDebug(@"Sent request %@ from queue %@. Loading count = %ld of %ld", request, self, (long) self.loadingCount, (long) _concurrentRequestsLimit); [request sendAsynchronously]; if ([_delegate respondsToSelector:@selector(requestQueue:didSendRequest:)]) { [_delegate requestQueue:self didSendRequest:request]; } request = [self nextRequest]; } } if (_requests.count && !_suspended) { [self loadNextInQueueDelayed]; } [pool drain]; } - (void)setSuspended:(BOOL)isSuspended { if (_suspended != isSuspended) { if (isSuspended) { RKLogDebug(@"Queue %@ has been suspended", self); // Becoming suspended if ([_delegate respondsToSelector:@selector(requestQueueWasSuspended:)]) { [_delegate requestQueueWasSuspended:self]; } } else { RKLogDebug(@"Queue %@ has been unsuspended", self); // Becoming unsupended if ([_delegate respondsToSelector:@selector(requestQueueWasUnsuspended:)]) { [_delegate requestQueueWasUnsuspended:self]; } } } _suspended = isSuspended; if (!_suspended) { [self loadNextInQueue]; } else if (_queueTimer) { [_queueTimer invalidate]; _queueTimer = nil; } } - (void)addRequest:(RKRequest*)request { RKLogTrace(@"Request %@ added to queue %@", request, self); NSAssert(![self containsRequest:request], @"Attempting to add the same request multiple times"); @synchronized(self) { [_requests addObject:request]; request.queue = self; } [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processRequestDidFinishLoadingNotification:) name:RKRequestDidFinishLoadingNotification object:request]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processRequestDidLoadResponseNotification:) name:RKRequestDidLoadResponseNotification object:request]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processRequestDidFailWithErrorNotification:) name:RKRequestDidFailWithErrorNotification object:request]; [self loadNextInQueue]; } - (BOOL)removeRequest:(RKRequest*)request { if ([self containsRequest:request]) { RKLogTrace(@"Removing request %@ from queue %@", request, self); @synchronized(self) { [self removeLoadingRequest:request]; [_requests removeObject:request]; request.queue = nil; } [[NSNotificationCenter defaultCenter] removeObserver:self name:RKRequestDidLoadResponseNotification object:request]; [[NSNotificationCenter defaultCenter] removeObserver:self name:RKRequestDidFailWithErrorNotification object:request]; [[NSNotificationCenter defaultCenter] removeObserver:self name:RKRequestDidFinishLoadingNotification object:request]; return YES; } RKLogWarning(@"Failed to remove request %@ from queue %@: it is not in the queue.", request, self); return NO; } - (BOOL)containsRequest:(RKRequest*)request { @synchronized(self) { return [_requests containsObject:request]; } } - (void)cancelRequest:(RKRequest*)request loadNext:(BOOL)loadNext { if ([request isUnsent]) { RKLogDebug(@"Cancelled undispatched request %@ and removed from queue %@", request, self); [self removeRequest:request]; request.delegate = nil; if ([_delegate respondsToSelector:@selector(requestQueue:didCancelRequest:)]) { [_delegate requestQueue:self didCancelRequest:request]; } } else if ([self containsRequest:request] && [request isLoading]) { RKLogDebug(@"Cancelled loading request %@ and removed from queue %@", request, self); [request cancel]; request.delegate = nil; if ([_delegate respondsToSelector:@selector(requestQueue:didCancelRequest:)]) { [_delegate requestQueue:self didCancelRequest:request]; } [self removeRequest:request]; if (loadNext) { [self loadNextInQueue]; } } } - (void)cancelRequest:(RKRequest*)request { [self cancelRequest:request loadNext:YES]; } - (void)cancelRequestsWithDelegate:(NSObject<RKRequestDelegate>*)delegate { RKLogDebug(@"Cancelling all request in queue %@ with delegate %p", self, delegate); NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSArray* requestsCopy = [NSArray arrayWithArray:_requests]; for (RKRequest* request in requestsCopy) { if (request.delegate && request.delegate == delegate) { [self cancelRequest:request]; } } [pool drain]; } - (void)abortRequestsWithDelegate:(NSObject<RKRequestDelegate>*)delegate { RKLogDebug(@"Aborting all request in queue %@ with delegate %p", self, delegate); NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSArray* requestsCopy = [NSArray arrayWithArray:_requests]; for (RKRequest* request in requestsCopy) { if (request.delegate && request.delegate == delegate) { request.delegate = nil; [self cancelRequest:request]; } } [pool drain]; } - (void)cancelAllRequests { RKLogDebug(@"Cancelling all request in queue %@", self); NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSArray* requestsCopy = [NSArray arrayWithArray:_requests]; for (RKRequest* request in requestsCopy) { [self cancelRequest:request loadNext:NO]; } [pool drain]; } - (void)start { RKLogDebug(@"Started queue %@", self); [self setSuspended:NO]; } - (void)processRequestDidLoadResponseNotification:(NSNotification *)notification { NSAssert([notification.object isKindOfClass:[RKRequest class]], @"Notification expected to contain an RKRequest, got a %@", NSStringFromClass([notification.object class])); RKLogTrace(@"Received notification: %@", notification); RKRequest* request = (RKRequest*)notification.object; NSDictionary* userInfo = [notification userInfo]; // We successfully loaded a response RKLogDebug(@"Received response for request %@, removing from queue. (Now loading %ld of %ld)", request, (long) self.loadingCount, (long) _concurrentRequestsLimit); RKResponse* response = [userInfo objectForKey:RKRequestDidLoadResponseNotificationUserInfoResponseKey]; if ([_delegate respondsToSelector:@selector(requestQueue:didLoadResponse:)]) { [_delegate requestQueue:self didLoadResponse:response]; } [self removeLoadingRequest:request]; [self loadNextInQueue]; } - (void)processRequestDidFailWithErrorNotification:(NSNotification *)notification { NSAssert([notification.object isKindOfClass:[RKRequest class]], @"Notification expected to contain an RKRequest, got a %@", NSStringFromClass([notification.object class])); RKLogTrace(@"Received notification: %@", notification); RKRequest* request = (RKRequest*)notification.object; NSDictionary* userInfo = [notification userInfo]; // We failed with an error NSError* error = nil; if (userInfo) { error = [userInfo objectForKey:RKRequestDidFailWithErrorNotificationUserInfoErrorKey]; RKLogDebug(@"Request %@ failed loading in queue %@ with error: %@.(Now loading %ld of %ld)", request, self, [error localizedDescription], (long) self.loadingCount, (long) _concurrentRequestsLimit); } else { RKLogWarning(@"Received RKRequestDidFailWithErrorNotification without a userInfo, something is amiss..."); } if ([_delegate respondsToSelector:@selector(requestQueue:didFailRequest:withError:)]) { [_delegate requestQueue:self didFailRequest:request withError:error]; } [self removeLoadingRequest:request]; [self loadNextInQueue]; } /* Invoked via observation when a request has loaded a response or failed with an error. Remove the completed request from the queue and continue processing */ - (void)processRequestDidFinishLoadingNotification:(NSNotification *)notification { NSAssert([notification.object isKindOfClass:[RKRequest class]], @"Notification expected to contain an RKRequest, got a %@", NSStringFromClass([notification.object class])); RKLogTrace(@"Received notification: %@", notification); RKRequest* request = (RKRequest*)notification.object; if ([self containsRequest:request]) { [self removeRequest:request]; // Load the next request [self loadNextInQueue]; } else { RKLogWarning(@"Request queue %@ received unexpected lifecycle notification %@ for request %@: Request not found in queue.", [notification name], self, request); } } #pragma mark - Background Request Support - (void)willTransitionToBackground { RKLogDebug(@"App is transitioning into background, suspending queue"); // Suspend the queue so background requests do not trigger additional requests on state changes self.suspended = YES; } - (void)willTransitionToForeground { RKLogDebug(@"App returned from background, unsuspending queue"); self.suspended = NO; } @end #if TARGET_OS_IPHONE @implementation UIApplication (RKNetworkActivity) static NSInteger networkActivityCount; - (NSInteger)networkActivityCount { @synchronized(self) { return networkActivityCount; } } - (void)refreshActivityIndicator { if(![NSThread isMainThread]) { SEL sel_refresh = @selector(refreshActivityIndicator); [self performSelectorOnMainThread:sel_refresh withObject:nil waitUntilDone:NO]; return; } BOOL active = (self.networkActivityCount > 0); self.networkActivityIndicatorVisible = active; } - (void)pushNetworkActivity { @synchronized(self) { networkActivityCount++; } [self refreshActivityIndicator]; } - (void)popNetworkActivity { @synchronized(self) { if (networkActivityCount > 0) { networkActivityCount--; } else { networkActivityCount = 0; RKLogError(@"Unbalanced network activity: count already 0."); } } [self refreshActivityIndicator]; } - (void)resetNetworkActivity { @synchronized(self) { networkActivityCount = 0; } [self refreshActivityIndicator]; } @end #endif
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequestQueue.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequestSerializable.h
// // RKRequestSerializable.h // RestKit // // Created by Blake Watters on 8/3/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // /** This protocol is implemented by objects that can be serialized into a representation suitable for transmission over a REST request. Suitable serializations are x-www-form-urlencoded and multipart/form-data. @warning One of the following methods MUST be implemented for your serializable implementation to be complete: - (NSData *)HTTPBody - If you are allowing serialization of a small in-memory data structure, implement HTTPBody as it is much simpler. - (NSInputStream *)HTTPBodyStream - This provides support for streaming a large payload from disk instead of memory. */ @protocol RKRequestSerializable <NSObject> ///----------------------------------------------------------------------------- /// @name HTTP Headers ///----------------------------------------------------------------------------- /** The value of the Content-Type header for the HTTP Body representation of the serialization. @return A string value of the Content-Type header for the HTTP body. */ - (NSString *)HTTPHeaderValueForContentType; @optional ///----------------------------------------------------------------------------- /// @name Body Implementation ///----------------------------------------------------------------------------- /** An NSData representing the HTTP Body serialization of the object implementing the protocol. @return An NSData object respresenting the HTTP body serialization. */ - (NSData *)HTTPBody; /** Returns an input stream for reading the serialization as a stream used to provide support for handling large HTTP payloads. @return An input stream for reading the serialization as a stream. */ - (NSInputStream *)HTTPBodyStream; ///----------------------------------------------------------------------------- /// @name Optional HTTP Headers ///----------------------------------------------------------------------------- /** Returns the length of the HTTP Content-Length header. @return Unsigned integer length of the HTTP Content-Length header. */ - (NSUInteger)HTTPHeaderValueForContentLength; /** The value of the Content-Type header for the HTTP Body representation of the serialization. @bug **DEPRECATED** in v0.10.0: Implement [RKRequestSerializable HTTPHeaderValueForContentType] instead. @return A string value of the Content-Type header for the HTTP body. */ - (NSString *)ContentTypeHTTPHeader DEPRECATED_ATTRIBUTE; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequestSerializable.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequestSerialization.h
// // RKRequestSerialization.h // RestKit // // Created by Blake Watters on 5/18/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKRequestSerializable.h" /** A simple implementation of the RKRequestSerializable protocol suitable for wrapping a MIME Type string and HTTP Body into a format that can be sent as the params of an RKRequest. @see RKRequestSerializable */ @interface RKRequestSerialization : NSObject <RKRequestSerializable> { NSData *_data; NSString *_MIMEType; } ///----------------------------------------------------------------------------- /// @name Creating a Serialization ///----------------------------------------------------------------------------- /** Creates and returns a new serialization enclosing an NSData object with the specified MIME type. @param data An NSData object to initialize the serialization with. @param MIMEType A string of the MIME type of the provided data. @return An autoreleased RKRequestSerialization object with the data and MIME type set. */ + (id)serializationWithData:(NSData *)data MIMEType:(NSString *)MIMEType; /** Returns a new serialization enclosing an NSData object with the specified MIME type. @param data An NSData object to initialize the serialization with. @param MIMEType A string of the MIME type of the provided data. @return An RKRequestSerialization object with the data and MIME type set. */ - (id)initWithData:(NSData *)data MIMEType:(NSString *)MIMEType; ///----------------------------------------------------------------------------- /// @name Properties ///----------------------------------------------------------------------------- /** Returns the data enclosed in this serialization. */ @property (nonatomic, readonly) NSData *data; /** Returns the MIME type of the data in this serialization. */ @property (nonatomic, readonly) NSString *MIMEType; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequestSerialization.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKRequestSerialization.m
// // RKRequestSerialization.m // RestKit // // Created by Blake Watters on 5/18/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKRequestSerialization.h" @implementation RKRequestSerialization @synthesize data = _data; @synthesize MIMEType = _MIMEType; - (id)initWithData:(NSData *)data MIMEType:(NSString *)MIMEType { NSAssert(data, @"Cannot create a request serialization without Data"); NSAssert(MIMEType, @"Cannot create a request serialization without a MIME Type"); self = [super init]; if (self) { _data = [data retain]; _MIMEType = [MIMEType retain]; } return self; } + (id)serializationWithData:(NSData *)data MIMEType:(NSString *)MIMEType { return [[[RKRequestSerialization alloc] initWithData:data MIMEType:MIMEType] autorelease]; } - (void)dealloc { [_data release]; [_MIMEType release]; [super dealloc]; } - (NSString *)HTTPHeaderValueForContentType { return self.MIMEType; } - (NSData *)HTTPBody { return self.data; } - (NSUInteger)HTTPHeaderValueForContentLength { return [self.data length]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKRequestSerialization.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKResponse.h
// // RKResponse.h // RestKit // // Created by Blake Watters on 7/28/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> #import "RKRequest.h" /** Models the response portion of an HTTP request/response cycle */ @interface RKResponse : NSObject { RKRequest *_request; NSHTTPURLResponse *_httpURLResponse; NSMutableData *_body; NSError *_failureError; BOOL _loading; NSDictionary *_responseHeaders; } ///----------------------------------------------------------------------------- /// @name Creating a Response ///----------------------------------------------------------------------------- /** Initializes a new response object for a REST request. @param request The request that the response being created belongs to. @return An RKResponse object with the request parameter set. */ - (id)initWithRequest:(RKRequest *)request; /** Initializes a new response object from a cached request. @param request The request that the response being created belongs to. @param body The data of the body of the response. @param headers A dictionary of the response's headers. @return An RKResponse object with the request, body, and header parameters set. */ - (id)initWithRequest:(RKRequest *)request body:(NSData *)body headers:(NSDictionary *)headers; /** Initializes a response object from the results of a synchronous request. @param request The request that the response being created belongs to. @param URLResponse The response from the NSURLConnection call containing the headers and HTTP status code. @param body The data of the body of the response. @param error The error returned from the NSURLConnection call, if any. @return An RKResponse object with the results of the synchronous request derived from the NSHTTPURLResponse and body passed. */ - (id)initWithSynchronousRequest:(RKRequest *)request URLResponse:(NSHTTPURLResponse *)URLResponse body:(NSData *)body error:(NSError *)error; ///----------------------------------------------------------------------------- /// @name Accessing the Request ///----------------------------------------------------------------------------- /** The request that generated this response. */ @property (nonatomic, assign, readonly) RKRequest *request; /** The URL the response was loaded from. */ @property (nonatomic, readonly) NSURL *URL; ///----------------------------------------------------------------------------- /// @name Accessing the Response Components ///----------------------------------------------------------------------------- /** The status code of the HTTP response. */ @property (nonatomic, readonly) NSInteger statusCode; /** Return a dictionary of headers sent with the HTTP response. */ @property (nonatomic, readonly) NSDictionary *allHeaderFields; /** An NSArray of NSHTTPCookie objects associated with the response. */ @property (nonatomic, readonly) NSArray *cookies; /** Returns the localized human readable representation of the HTTP Status Code returned. */ - (NSString *)localizedStatusCodeString; ///----------------------------------------------------------------------------- /// @name Accessing Common Headers ///----------------------------------------------------------------------------- /** Returns the value of 'Content-Type' HTTP header */ - (NSString *)contentType; /** Returns the value of the 'Content-Length' HTTP header */ - (NSString *)contentLength; /** Returns the value of the 'Location' HTTP Header */ - (NSString *)location; ///----------------------------------------------------------------------------- /// @name Reading the Body Content ///----------------------------------------------------------------------------- /** The data returned as the response body. */ @property (nonatomic, readonly) NSData *body; /** Returns the response body as an NSString */ - (NSString *)bodyAsString; /** Returns the response body parsed as JSON into an object @bug **DEPRECATED** in v0.10.0 */ - (id)bodyAsJSON DEPRECATED_ATTRIBUTE; /** Returns the response body parsed as JSON into an object @param error An NSError to populate if something goes wrong while parsing the body JSON into an object. */ - (id)parsedBody:(NSError **)error; ///----------------------------------------------------------------------------- /// @name Handling Errors ///----------------------------------------------------------------------------- /** The error returned if the URL connection fails. */ @property (nonatomic, readonly) NSError *failureError; /** Determines if there is an error object and uses it's localized message @return A string of the localized error message. */ - (NSString *)failureErrorDescription; /** Indicates whether the response was loaded from RKCache @return YES if the response was loaded from the cache */ - (BOOL)wasLoadedFromCache; ///----------------------------------------------------------------------------- /// @name Determining the Status Range of the Response ///----------------------------------------------------------------------------- /** Indicates that the connection failed to reach the remote server. The details of the failure are available on the failureError reader. @return YES if the connection failed to reach the remote server. */ - (BOOL)isFailure; /** Indicates an invalid HTTP response code less than 100 or greater than 600 @return YES if the HTTP response code is less than 100 or greater than 600 */ - (BOOL)isInvalid; /** Indicates an informational HTTP response code between 100 and 199 @return YES if the HTTP response code is between 100 and 199 */ - (BOOL)isInformational; /** Indicates an HTTP response code between 200 and 299. Confirms that the server received, understood, accepted and processed the request successfully. @return YES if the HTTP response code is between 200 and 299 */ - (BOOL)isSuccessful; /** Indicates an HTTP response code between 300 and 399. This class of status code indicates that further action needs to be taken by the user agent in order to fulfil the request. The action required may be carried out by the user agent without interaction with the user if and only if the method used in the second request is GET or HEAD. @return YES if the HTTP response code is between 300 and 399. */ - (BOOL)isRedirection; /** Indicates an HTTP response code between 400 and 499. This status code is indented for cases in which the client seems to have erred. @return YES if the HTTP response code is between 400 and 499. */ - (BOOL)isClientError; /** Indicates an HTTP response code between 500 and 599. This state code occurs when the server failed to fulfill an apparently valid request. @return YES if the HTTP response code is between 500 and 599. */ - (BOOL)isServerError; ///----------------------------------------------------------------------------- /// @name Determining Specific Statuses ///----------------------------------------------------------------------------- /** Indicates that the response is either a server or a client error. @return YES if the response is either a server or client error, with a response code between 400 and 599. */ - (BOOL)isError; /** Indicates an HTTP response code of 200. @return YES if the response is 200 OK. */ - (BOOL)isOK; /** Indicates an HTTP response code of 201. @return YES if the response is 201 Created. */ - (BOOL)isCreated; /** Indicates an HTTP response code of 204. @return YES if the response is 204 No Content. */ - (BOOL)isNoContent; /** Indicates an HTTP response code of 304. @return YES if the response is 304 Not Modified. */ - (BOOL)isNotModified; /** Indicates an HTTP response code of 401. @return YES if the response is 401 Unauthorized. */ - (BOOL)isUnauthorized; /** Indicates an HTTP response code of 403. @return YES if the response is 403 Forbidden. */ - (BOOL)isForbidden; /** Indicates an HTTP response code of 404. @return YES if the response is 404 Not Found. */ - (BOOL)isNotFound; /** Indicates an HTTP response code of 409. @return YES if the response is 409 Conflict. */ - (BOOL)isConflict; /** Indicates an HTTP response code of 410. @return YES if the response is 410 Gone. */ - (BOOL)isGone; /** Indicates an HTTP response code of 422. @return YES if the response is 422 Unprocessable Entity. */ - (BOOL)isUnprocessableEntity; /** Indicates an HTTP response code of 301, 302, 303 or 307. @return YES if the response requires a redirect to finish processing. */ - (BOOL)isRedirect; /** Indicates an empty HTTP response code of 201, 204, or 304 @return YES if the response body is empty. */ - (BOOL)isEmpty; /** Indicates an HTTP response code of 503 @return YES if the response is 503 Service Unavailable. */ - (BOOL)isServiceUnavailable; ///----------------------------------------------------------------------------- /// @name Accessing the Response's MIME Type and Encoding ///----------------------------------------------------------------------------- /** The MIME Type of the response body. */ @property (nonatomic, readonly) NSString *MIMEType; /** True when the server turned an HTML response. @return YES when the MIME type is text/html. */ - (BOOL)isHTML; /** True when the server turned an XHTML response @return YES when the MIME type is application/xhtml+xml. */ - (BOOL)isXHTML; /** True when the server turned an XML response @return YES when the MIME type is application/xml. */ - (BOOL)isXML; /** True when the server turned an JSON response @return YES when the MIME type is application/json. */ - (BOOL)isJSON; /** Returns the name of the string encoding used for the response body */ - (NSString *)bodyEncodingName; /** Returns the string encoding used for the response body */ - (NSStringEncoding)bodyEncoding; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKResponse.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKResponse.m
// // RKResponse.m // RestKit // // Created by Blake Watters on 7/28/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKResponse.h" #import "RKNotifications.h" #import "RKLog.h" #import "RKParserRegistry.h" #import "RKRequestCache.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetwork #define RKResponseIgnoreDelegateIfCancelled(...) \ if (self.request && [self.request isCancelled]) { \ RKLogDebug(@"%s: Ignoring NSURLConnection delegate message sent after cancel.", __PRETTY_FUNCTION__); \ return __VA_ARGS__; \ } @implementation RKResponse @synthesize body = _body; @synthesize request = _request; @synthesize failureError = _failureError; - (id)init { self = [super init]; if (self) { _body = [[NSMutableData alloc] init]; _failureError = nil; _loading = NO; _responseHeaders = nil; } return self; } - (id)initWithRequest:(RKRequest *)request { self = [self init]; if (self) { // We don't retain here as we're letting RKRequestQueue manage // request ownership _request = request; } return self; } - (id)initWithRequest:(RKRequest*)request body:(NSData*)body headers:(NSDictionary*)headers { self = [self initWithRequest:request]; if (self) { [_body release]; _body = [[NSMutableData dataWithData:body] retain]; _responseHeaders = [headers retain]; } return self; } - (id)initWithSynchronousRequest:(RKRequest*)request URLResponse:(NSHTTPURLResponse*)URLResponse body:(NSData*)body error:(NSError*)error { self = [super init]; if (self) { _request = request; _httpURLResponse = [URLResponse retain]; _failureError = [error retain]; _body = [[NSMutableData dataWithData:body] retain]; _loading = NO; } return self; } - (void)dealloc { _request = nil; [_httpURLResponse release]; _httpURLResponse = nil; [_body release]; _body = nil; [_failureError release]; _failureError = nil; [_responseHeaders release]; _responseHeaders = nil; [super dealloc]; } - (BOOL)hasCredentials { return _request.username && _request.password; } - (BOOL)isServerTrusted:(SecTrustRef)trust { BOOL proceed = NO; if (_request.disableCertificateValidation) { proceed = YES; } else if ([_request.additionalRootCertificates count] > 0 ) { CFArrayRef rootCerts = (CFArrayRef)[_request.additionalRootCertificates allObjects]; SecTrustResultType result; OSStatus returnCode; if (rootCerts && CFArrayGetCount(rootCerts)) { // this could fail, but the trust evaluation will proceed (it's likely to fail, of course) SecTrustSetAnchorCertificates(trust, rootCerts); } returnCode = SecTrustEvaluate(trust, &result); if (returnCode == errSecSuccess) { proceed = (result == kSecTrustResultProceed || result == kSecTrustResultConfirm || result == kSecTrustResultUnspecified); if (result == kSecTrustResultRecoverableTrustFailure) { // TODO: should try to recover here // call SecTrustGetCssmResult() for more information about the failure } } } return proceed; } // Handle basic auth & SSL certificate validation - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { RKResponseIgnoreDelegateIfCancelled(); RKLogDebug(@"Received authentication challenge"); if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustRef trust = [[challenge protectionSpace] serverTrust]; if ([self isServerTrusted:trust]) { [challenge.sender useCredential:[NSURLCredential credentialForTrust:trust] forAuthenticationChallenge:challenge]; } else { [[challenge sender] cancelAuthenticationChallenge:challenge]; } return; } if ([challenge previousFailureCount] == 0) { NSURLCredential *newCredential; newCredential=[NSURLCredential credentialWithUser:[NSString stringWithFormat:@"%@", _request.username] password:[NSString stringWithFormat:@"%@", _request.password] persistence:NSURLCredentialPersistenceNone]; [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge]; } else { RKLogWarning(@"Failed authentication challenge after %ld failures", (long) [challenge previousFailureCount]); [[challenge sender] cancelAuthenticationChallenge:challenge]; } } - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)space { RKResponseIgnoreDelegateIfCancelled(NO); RKLogDebug(@"Asked if canAuthenticateAgainstProtectionSpace: with authenticationMethod = %@", [space authenticationMethod]); if ([[space authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) { // server is using an SSL certificate that the OS can't validate // see whether the client settings allow validation here if (_request.disableCertificateValidation || [_request.additionalRootCertificates count] > 0) { return YES; } else { return NO; } } // Handle non-SSL challenges BOOL hasCredentials = [self hasCredentials]; if (! hasCredentials) { RKLogWarning(@"Received an authentication challenge without any credentials to satisfy the request."); } return hasCredentials; } - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { if (nil == response || _request.followRedirect) { RKLogDebug(@"Proceeding with request to %@", request); return request; } else { RKLogDebug(@"Not following redirect to %@", request); return nil; } } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { RKResponseIgnoreDelegateIfCancelled(); [_body appendData:data]; [_request invalidateTimeoutTimer]; if ([[_request delegate] respondsToSelector:@selector(request:didReceiveData:totalBytesReceived:totalBytesExpectedToReceive:)]) { [[_request delegate] request:_request didReceiveData:[data length] totalBytesReceived:[_body length] totalBytesExpectedToReceive:_httpURLResponse.expectedContentLength]; } } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { RKResponseIgnoreDelegateIfCancelled(); RKLogDebug(@"NSHTTPURLResponse Status Code: %ld", (long) [response statusCode]); RKLogDebug(@"Headers: %@", [response allHeaderFields]); _httpURLResponse = [response retain]; [_request invalidateTimeoutTimer]; if ([[_request delegate] respondsToSelector:@selector(request:didReceiveResponse:)]) { [[_request delegate] request:_request didReceiveResponse:self]; } } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { RKResponseIgnoreDelegateIfCancelled(); RKLogTrace(@"Read response body: %@", [self bodyAsString]); [_request didFinishLoad:self]; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { RKResponseIgnoreDelegateIfCancelled(); _failureError = [error retain]; [_request invalidateTimeoutTimer]; [_request didFailLoadWithError:_failureError]; } - (NSInputStream *)connection:(NSURLConnection *)connection needNewBodyStream:(NSURLRequest *)request { RKResponseIgnoreDelegateIfCancelled(nil); RKLogWarning(@"RestKit was asked to retransmit a new body stream for a request. Possible connection error or authentication challenge?"); return nil; } // In the event that the url request is a post, this delegate method will be called before // either connection:didReceiveData: or connection:didReceiveResponse: // However this method is only called if there is payload data to be sent. // Therefore, we ensure the delegate recieves the did start loading here and // in connection:didReceiveResponse: to ensure that the RKRequestDelegate // callbacks get called in the correct order. - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { RKResponseIgnoreDelegateIfCancelled(); [_request invalidateTimeoutTimer]; if ([[_request delegate] respondsToSelector:@selector(request:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:)]) { [[_request delegate] request:_request didSendBodyData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite]; } } - (NSString*)localizedStatusCodeString { return [NSHTTPURLResponse localizedStringForStatusCode:[self statusCode]]; } - (NSData *)body { return _body; } - (NSString *)bodyEncodingName { return [_httpURLResponse textEncodingName]; } - (NSStringEncoding)bodyEncoding { CFStringEncoding cfEncoding = kCFStringEncodingInvalidId; NSString *textEncodingName = [self bodyEncodingName]; if (textEncodingName) { cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef) textEncodingName); } return (cfEncoding == kCFStringEncodingInvalidId) ? self.request.defaultHTTPEncoding : CFStringConvertEncodingToNSStringEncoding(cfEncoding); } - (NSString *)bodyAsString { return [[[NSString alloc] initWithData:self.body encoding:[self bodyEncoding]] autorelease]; } - (id)bodyAsJSON { [NSException raise:nil format:@"Reimplemented as parsedBody"]; return nil; } - (id)parsedBody:(NSError**)error { id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:[self MIMEType]]; if (! parser) { RKLogWarning(@"Unable to parse response body: no parser registered for MIME Type '%@'", [self MIMEType]); return nil; } id object = [parser objectFromString:[self bodyAsString] error:error]; if (object == nil) { if (error && *error) { RKLogError(@"Unable to parse response body: %@", [*error localizedDescription]); } return nil; } return object; } - (NSString*)failureErrorDescription { if ([self isFailure]) { return [_failureError localizedDescription]; } else { return nil; } } - (BOOL)wasLoadedFromCache { return (_responseHeaders != nil); } - (NSURL*)URL { if ([self wasLoadedFromCache]) { return [NSURL URLWithString:[_responseHeaders valueForKey:RKRequestCacheURLHeadersKey]]; } return [_httpURLResponse URL]; } - (NSString*)MIMEType { if ([self wasLoadedFromCache]) { return [_responseHeaders valueForKey:RKRequestCacheMIMETypeHeadersKey]; } return [_httpURLResponse MIMEType]; } - (NSInteger)statusCode { if ([self wasLoadedFromCache]) { return [[_responseHeaders valueForKey:RKRequestCacheStatusCodeHeadersKey] intValue]; } return ([_httpURLResponse respondsToSelector:@selector(statusCode)] ? [_httpURLResponse statusCode] : 200); } - (NSDictionary*)allHeaderFields { if ([self wasLoadedFromCache]) { return _responseHeaders; } return ([_httpURLResponse respondsToSelector:@selector(allHeaderFields)] ? [_httpURLResponse allHeaderFields] : nil); } - (NSArray*)cookies { return [NSHTTPCookie cookiesWithResponseHeaderFields:self.allHeaderFields forURL:self.URL]; } - (BOOL)isFailure { return (nil != _failureError); } - (BOOL)isInvalid { return ([self statusCode] < 100 || [self statusCode] > 600); } - (BOOL)isInformational { return ([self statusCode] >= 100 && [self statusCode] < 200); } - (BOOL)isSuccessful { return (([self statusCode] >= 200 && [self statusCode] < 300) || ([self wasLoadedFromCache])); } - (BOOL)isRedirection { return ([self statusCode] >= 300 && [self statusCode] < 400); } - (BOOL)isClientError { return ([self statusCode] >= 400 && [self statusCode] < 500); } - (BOOL)isServerError { return ([self statusCode] >= 500 && [self statusCode] < 600); } - (BOOL)isError { return ([self isClientError] || [self isServerError]); } - (BOOL)isOK { return ([self statusCode] == 200); } - (BOOL)isCreated { return ([self statusCode] == 201); } - (BOOL)isNoContent { return ([self statusCode] == 204); } - (BOOL)isNotModified { return ([self statusCode] == 304); } - (BOOL)isUnauthorized { return ([self statusCode] == 401); } - (BOOL)isForbidden { return ([self statusCode] == 403); } - (BOOL)isNotFound { return ([self statusCode] == 404); } - (BOOL)isConflict { return ([self statusCode] == 409); } - (BOOL)isGone { return ([self statusCode] == 410); } - (BOOL)isUnprocessableEntity { return ([self statusCode] == 422); } - (BOOL)isRedirect { return ([self statusCode] == 301 || [self statusCode] == 302 || [self statusCode] == 303 || [self statusCode] == 307); } - (BOOL)isEmpty { return ([self statusCode] == 201 || [self statusCode] == 204 || [self statusCode] == 304); } - (BOOL)isServiceUnavailable { return ([self statusCode] == 503); } - (NSString*)contentType { return ([[self allHeaderFields] objectForKey:@"Content-Type"]); } - (NSString*)contentLength { return ([[self allHeaderFields] objectForKey:@"Content-Length"]); } - (NSString*)location { return ([[self allHeaderFields] objectForKey:@"Location"]); } - (BOOL)isHTML { NSString* contentType = [self contentType]; return (contentType && ([contentType rangeOfString:@"text/html" options:NSCaseInsensitiveSearch|NSAnchoredSearch].length > 0 || [self isXHTML])); } - (BOOL)isXHTML { NSString* contentType = [self contentType]; return (contentType && [contentType rangeOfString:@"application/xhtml+xml" options:NSCaseInsensitiveSearch|NSAnchoredSearch].length > 0); } - (BOOL)isXML { NSString* contentType = [self contentType]; return (contentType && [contentType rangeOfString:@"application/xml" options:NSCaseInsensitiveSearch|NSAnchoredSearch].length > 0); } - (BOOL)isJSON { NSString* contentType = [self contentType]; return (contentType && [contentType rangeOfString:@"application/json" options:NSCaseInsensitiveSearch|NSAnchoredSearch].length > 0); } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKResponse.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKURL.h
// // RKURL.h // RestKit // // Created by Jeff Arena on 10/18/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // /** RKURL extends the Cocoa NSURL base class to provide support for the concepts of base URL and resource path that are used extensively throughout the RestKit framework. RKURL is immutable, but provides numerous methods for constructing new RKURL instances where the received becomes the baseURL of the RKURL instance. Instances of RKURL are aware of: - the baseURL they were constructed against, if any - the resource path that was appended to that baseURL - any query parameters present in the URL ### Example NSDictionary *queryParams; queryParams = [NSDictionary dictionaryWithObjectsAndKeys:@"pitbull", @"username", @"pickles", @"password", nil]; RKURL *URL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:@"/test" queryParameters:queryParams]; */ @interface RKURL : NSURL ///----------------------------------------------------------------------------- /// @name Creating an RKURL ///----------------------------------------------------------------------------- /** Creates and returns an RKURL object intialized with a provided base URL. @param baseURL The URL object with which to initialize the RKURL object. @return An RKURL object initialized with baseURL. */ + (id)URLWithBaseURL:(NSURL *)baseURL; /** Creates and returns an RKURL object intialized with a provided base URL and resource path. @param baseURL The URL object with which to initialize the RKURL object. @param resourcePath The resource path for the RKURL object. @return An RKURL object initialized with baseURL and resourcePath. */ + (id)URLWithBaseURL:(NSURL *)baseURL resourcePath:(NSString *)resourcePath; /** Creates and returns an RKURL object intialized with a provided base URL, resource path, and a dictionary of query parameters. @param baseURL The URL object with which to initialize the RKURL object. @param resourcePath The resource path for the RKURL object. @param queryParameters The query parameters for the RKURL object. @return An RKURL object initialized with baseURL, resourcePath, and queryParameters. */ + (id)URLWithBaseURL:(NSURL *)baseURL resourcePath:(NSString *)resourcePath queryParameters:(NSDictionary *)queryParameters; /** Creates and returns an RKURL object intialized with a base URL constructed from the specified base URL string. @param baseURLString The string with which to initialize the RKURL object. @return An RKURL object initialized with baseURLString. */ + (id)URLWithBaseURLString:(NSString *)baseURLString; /** Creates and returns an RKURL object intialized with a base URL constructed from the specified base URL string and resource path. @param baseURLString The string with which to initialize the RKURL object. @param resourcePath The resource path for the RKURL object. @return An RKURL object initialized with baseURLString and resourcePath. */ + (id)URLWithBaseURLString:(NSString *)baseURLString resourcePath:(NSString *)resourcePath; /** Creates and returns an RKURL object intialized with a base URL constructed from the specified base URL string, resource path and a dictionary of query parameters. @param baseURLString The string with which to initialize the RKURL object. @param resourcePath The resource path for the RKURL object. @param queryParameters The query parameters for the RKURL object. @return An RKURL object initialized with baseURLString, resourcePath and queryParameters. */ + (id)URLWithBaseURLString:(NSString *)baseURLString resourcePath:(NSString *)resourcePath queryParameters:(NSDictionary *)queryParameters; /** Initializes an RKURL object with a base URL, a resource path string, and a dictionary of query parameters. `initWithBaseURL:resourcePath:queryParameters:` is the designated initializer. @param theBaseURL The NSURL with which to initialize the RKURL object. @param theResourcePath The resource path for the RKURL object. @param theQueryParameters The query parameters for the RKURL object. @return An RKURL object initialized with baseURL, resourcePath and queryParameters. */ - (id)initWithBaseURL:(NSURL *)theBaseURL resourcePath:(NSString *)theResourcePath queryParameters:(NSDictionary *)theQueryParameters; ///----------------------------------------------------------------------------- /// @name Accessing the URL parts ///----------------------------------------------------------------------------- /** Returns the base URL of the receiver. The base URL includes everything up to the resource path, typically the portion that is repeated in every API call. */ @property (nonatomic, copy, readonly) NSURL *baseURL; /** Returns the resource path of the receiver. The resource path is the path portion of the complete URL beyond that contained in the baseURL. */ @property (nonatomic, copy, readonly) NSString *resourcePath; /** Returns the query component of a URL conforming to RFC 1808 as a dictionary. If the receiver does not conform to RFC 1808, returns nil just as `NSURL query` does. */ @property (nonatomic, readonly) NSDictionary *queryParameters; ///----------------------------------------------------------------------------- /// @name Modifying the URL ///----------------------------------------------------------------------------- /** Returns a new RKURL object with a new resource path appended to its path. @param theResourcePath The resource path to append to the receiver's path. @return A new RKURL that refers to a new resource at theResourcePath. */ - (RKURL *)URLByAppendingResourcePath:(NSString *)theResourcePath; /** Returns a new RKURL object with a new resource path appended to its path and a dictionary of query parameters merged with the existing query component. @param theResourcePath The resource path to append to the receiver's path. @param theQueryParameters A dictionary of query parameters to merge with any existing query parameters. @return A new RKURL that refers to a new resource at theResourcePath with a new query component including the values from theQueryParameters. */ - (RKURL *)URLByAppendingResourcePath:(NSString *)theResourcePath queryParameters:(NSDictionary *)theQueryParameters; /** Returns a new RKURL object with a dictionary of query parameters merged with the existing query component. @param theQueryParameters A dictionary of query parameters to merge with any existing query parameters. @return A new RKURL that refers to the same resource as the receiver with a new query component including the values from theQueryParameters. */ - (RKURL *)URLByAppendingQueryParameters:(NSDictionary *)theQueryParameters; /** Returns a new RKURL object with the baseURL of the receiver and a new resourcePath. @param newResourcePath The resource path to replace the value of resourcePath in the new RKURL object. @return An RKURL object with newResourcePath appended to the receiver's baseURL. */ - (RKURL *)URLByReplacingResourcePath:(NSString *)newResourcePath; /** Returns a new RKURL object with its resource path processed as a pattern and evaluated against the specified object. Resource paths may contain pattern strings prefixed by colons (":") that refer to key-value coding accessible properties on the provided object. For example: // Given an RKURL initialized as: RKURL *myURL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:@"/paginate?per_page=:perPage&page=:page"]; // And a dictionary containing values: NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"25", @"perPage", @"5", @"page", nil]; // A new RKURL can be constructed by interpolating the dictionary with the original URL RKURL *interpolatedURL = [myURL URLByInterpolatingResourcePathWithObject:dictionary]; The absoluteString of this new URL would be: `http://restkit.org/paginate?per_page=25&page=5` @see RKPathMatcher @param object The object to call methods on for the pattern strings in the resource path. @return A new RKURL object with its resource path evaluated as a pattern and interpolated with properties of object. */ - (RKURL *)URLByInterpolatingResourcePathWithObject:(id)object; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKURL.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/RKURL.m
// // RKURL.m // RestKit // // Created by Jeff Arena on 10/18/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKURL.h" #import "RKClient.h" #import "NSURL+RKAdditions.h" #import "NSString+RKAdditions.h" #import "NSDictionary+RKAdditions.h" #import "RKLog.h" @interface RKURL () @property (nonatomic, copy, readwrite) NSURL *baseURL; @property (nonatomic, copy, readwrite) NSString *resourcePath; @end @implementation RKURL @synthesize baseURL; @synthesize resourcePath; + (id)URLWithBaseURL:(NSURL *)baseURL { return [self URLWithBaseURL:baseURL resourcePath:nil queryParameters:nil]; } + (id)URLWithBaseURL:(NSURL *)baseURL resourcePath:(NSString *)resourcePath { return [self URLWithBaseURL:baseURL resourcePath:resourcePath queryParameters:nil]; } + (id)URLWithBaseURL:(NSURL *)baseURL resourcePath:(NSString *)resourcePath queryParameters:(NSDictionary *)queryParameters { return [[[self alloc] initWithBaseURL:baseURL resourcePath:resourcePath queryParameters:queryParameters] autorelease]; } + (id)URLWithBaseURLString:(NSString *)baseURLString { return [self URLWithBaseURLString:baseURLString resourcePath:nil queryParameters:nil]; } + (id)URLWithBaseURLString:(NSString *)baseURLString resourcePath:(NSString *)resourcePath { return [self URLWithBaseURLString:baseURLString resourcePath:resourcePath queryParameters:nil]; } + (id)URLWithBaseURLString:(NSString *)baseURLString resourcePath:(NSString *)resourcePath queryParameters:(NSDictionary *)queryParameters { return [self URLWithBaseURL:[NSURL URLWithString:baseURLString] resourcePath:resourcePath queryParameters:queryParameters]; } // Designated initializer. Note this diverges from NSURL due to a bug in Cocoa. We can't // call initWithString:relativeToURL: from a subclass. - (id)initWithBaseURL:(NSURL *)theBaseURL resourcePath:(NSString *)theResourcePath queryParameters:(NSDictionary *)theQueryParameters { // Merge any existing query parameters with the incoming dictionary NSDictionary *resourcePathQueryParameters = [theResourcePath queryParameters]; NSMutableDictionary *mergedQueryParameters = [NSMutableDictionary dictionaryWithDictionary:[theBaseURL queryParameters]]; [mergedQueryParameters addEntriesFromDictionary:resourcePathQueryParameters]; [mergedQueryParameters addEntriesFromDictionary:theQueryParameters]; // Build the new URL path NSRange queryCharacterRange = [theResourcePath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"?"]]; NSString *resourcePathWithoutQueryString = (queryCharacterRange.location == NSNotFound) ? theResourcePath : [theResourcePath substringToIndex:queryCharacterRange.location]; NSString *baseURLPath = [[theBaseURL path] isEqualToString:@"/"] ? @"" : [[theBaseURL path] stringByStandardizingPath]; NSString *completePath = resourcePathWithoutQueryString ? [baseURLPath stringByAppendingString:resourcePathWithoutQueryString] : baseURLPath; NSString* completePathWithQuery = [completePath stringByAppendingQueryParameters:mergedQueryParameters]; // NOTE: You can't safely use initWithString:relativeToURL: in a NSURL subclass, see http://www.openradar.me/9729706 // So we unfortunately convert into an NSURL before going back into an NSString -> RKURL NSURL* completeURL = [NSURL URLWithString:completePathWithQuery relativeToURL:theBaseURL]; if (!completeURL) { RKLogError(@"Failed to build RKURL by appending resourcePath and query parameters '%@' to baseURL '%@'", theResourcePath, theBaseURL); [self release]; return nil; } self = [self initWithString:[completeURL absoluteString]]; if (self) { self.baseURL = theBaseURL; self.resourcePath = theResourcePath; } return self; } - (void)dealloc { [baseURL release]; baseURL = nil; [resourcePath release]; resourcePath = nil; [super dealloc]; } - (NSDictionary *)queryParameters { if (self.query) { return [NSDictionary dictionaryWithURLEncodedString:self.query]; } return nil; } - (RKURL *)URLByAppendingResourcePath:(NSString *)theResourcePath { return [RKURL URLWithBaseURL:self resourcePath:theResourcePath]; } - (RKURL *)URLByAppendingResourcePath:(NSString *)theResourcePath queryParameters:(NSDictionary *)theQueryParameters { return [RKURL URLWithBaseURL:self resourcePath:theResourcePath queryParameters:theQueryParameters]; } - (RKURL *)URLByAppendingQueryParameters:(NSDictionary *)theQueryParameters { return [RKURL URLWithBaseURL:self resourcePath:nil queryParameters:theQueryParameters]; } - (RKURL *)URLByReplacingResourcePath:(NSString *)newResourcePath { return [RKURL URLWithBaseURL:self.baseURL resourcePath:newResourcePath]; } - (RKURL *)URLByInterpolatingResourcePathWithObject:(id)object { return [self URLByReplacingResourcePath:[self.resourcePath interpolateWithObject:object]]; } #pragma mark - NSURL Overloads /* Overload implementations from NSURL. We consider a naked string to be initialized with a baseURL == self. Otherwise appending/replacing resourcePath will not work. */ + (id)URLWithString:(NSString *)URLString { return [self URLWithBaseURLString:URLString]; } - (id)initWithString:(NSString *)URLString { self = [super initWithString:URLString]; if (self) { self.baseURL = self; } return self; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/Network/._RKURL.m
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/._Network
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/ObjectMapping.h
// // ObjectMapping.h // RestKit // // Created by Blake Watters on 9/30/10. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectManager.h" #import "RKObjectLoader.h" #import "RKObjectMapping.h" #import "RKObjectSerializer.h" #import "RKObjectMappingProvider.h" #import "RKObjectMappingResult.h" #import "RKObjectMapper.h" #import "RKParserRegistry.h"
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._ObjectMapping.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKConfigurationDelegate.h
// // RKConfigurationDelegate.h // RestKit // // Created by Blake Watters on 1/7/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // @class RKRequest, RKObjectLoader; /** The RKConfigurationDelegate formal protocol defines methods enabling the centralization of RKRequest and RKObjectLoader configuration. An object conforming to the protocol can be used to set headers, authentication credentials, etc. RKClient and RKObjectManager conform to RKConfigurationDelegate to configure request and object loader instances they build. */ @protocol RKConfigurationDelegate <NSObject> @optional /** Configure a request before it is utilized @param request A request object being configured for dispatch */ - (void)configureRequest:(RKRequest *)request; /** Configure an object loader before it is utilized @param request An object loader being configured for dispatch */ - (void)configureObjectLoader:(RKObjectLoader *)objectLoader; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKConfigurationDelegate.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKDynamicObjectMapping.h
// // RKDynamicObjectMapping.h // RestKit // // Created by Blake Watters on 7/28/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectMappingDefinition.h" #import "RKObjectMapping.h" /** Return the appropriate object mapping given a mappable data */ @protocol RKDynamicObjectMappingDelegate <NSObject> @required - (RKObjectMapping *)objectMappingForData:(id)data; @end #ifdef NS_BLOCKS_AVAILABLE typedef RKObjectMapping *(^RKDynamicObjectMappingDelegateBlock)(id); #endif /** Defines a dynamic object mapping that determines the appropriate concrete object mapping to apply at mapping time. This allows you to map very similar payloads differently depending on the type of data contained therein. */ @interface RKDynamicObjectMapping : RKObjectMappingDefinition { NSMutableArray *_matchers; id<RKDynamicObjectMappingDelegate> _delegate; #ifdef NS_BLOCKS_AVAILABLE RKDynamicObjectMappingDelegateBlock _objectMappingForDataBlock; #endif } /** A delegate to call back to determine the appropriate concrete object mapping to apply to the mappable data. @see RKDynamicObjectMappingDelegate */ @property (nonatomic, assign) id<RKDynamicObjectMappingDelegate> delegate; #ifdef NS_BLOCKS_AVAILABLE /** A block to invoke to determine the appropriate concrete object mapping to apply to the mappable data. */ @property (nonatomic, copy) RKDynamicObjectMappingDelegateBlock objectMappingForDataBlock; #endif /** Return a new auto-released dynamic object mapping */ + (RKDynamicObjectMapping *)dynamicMapping; #if NS_BLOCKS_AVAILABLE /** Return a new auto-released dynamic object mapping after yielding it to the block for configuration */ + (RKDynamicObjectMapping *)dynamicMappingUsingBlock:(void(^)(RKDynamicObjectMapping *dynamicMapping))block; + (RKDynamicObjectMapping *)dynamicMappingWithBlock:(void(^)(RKDynamicObjectMapping *dynamicMapping))block DEPRECATED_ATTRIBUTE; #endif /** Defines a dynamic mapping rule stating that when the value of the key property matches the specified value, the objectMapping should be used. For example, suppose that we have a JSON fragment for a person that we want to map differently based on the gender of the person. When the gender is 'male', we want to use the Boy class and when then the gender is 'female' we want to use the Girl class. We might define our dynamic mapping like so: RKDynamicObjectMapping* mapping = [RKDynamicObjectMapping dynamicMapping]; [mapping setObjectMapping:boyMapping whenValueOfKeyPath:@"gender" isEqualTo:@"male"]; [mapping setObjectMapping:boyMapping whenValueOfKeyPath:@"gender" isEqualTo:@"female"]; */ - (void)setObjectMapping:(RKObjectMapping *)objectMapping whenValueOfKeyPath:(NSString *)keyPath isEqualTo:(id)value; /** Invoked by the RKObjectMapper and RKObjectMappingOperation to determine the appropriate RKObjectMapping to use when mapping the specified dictionary of mappable data. */ - (RKObjectMapping *)objectMappingForDictionary:(NSDictionary *)dictionary; @end /** Define an alias for the old class name for compatibility @deprecated */ @interface RKObjectDynamicMapping : RKDynamicObjectMapping @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKDynamicObjectMapping.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKDynamicObjectMapping.m
// // RKDynamicObjectMapping.m // RestKit // // Created by Blake Watters on 7/28/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKDynamicObjectMapping.h" #import "RKDynamicObjectMappingMatcher.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitObjectMapping @implementation RKDynamicObjectMapping @synthesize delegate = _delegate; @synthesize objectMappingForDataBlock = _objectMappingForDataBlock; + (RKDynamicObjectMapping*)dynamicMapping { return [[self new] autorelease]; } #if NS_BLOCKS_AVAILABLE + (RKDynamicObjectMapping *)dynamicMappingUsingBlock:(void(^)(RKDynamicObjectMapping *))block { RKDynamicObjectMapping* mapping = [self dynamicMapping]; block(mapping); return mapping; } + (RKDynamicObjectMapping*)dynamicMappingWithBlock:(void(^)(RKDynamicObjectMapping*))block { return [self dynamicMappingUsingBlock:block]; } #endif - (id)init { self = [super init]; if (self) { _matchers = [NSMutableArray new]; } return self; } - (void)dealloc { [_matchers release]; [super dealloc]; } - (void)setObjectMapping:(RKObjectMapping*)objectMapping whenValueOfKeyPath:(NSString*)keyPath isEqualTo:(id)value { RKLogDebug(@"Adding dynamic object mapping for key '%@' with value '%@' to destination class: %@", keyPath, value, NSStringFromClass(objectMapping.objectClass)); RKDynamicObjectMappingMatcher* matcher = [[RKDynamicObjectMappingMatcher alloc] initWithKey:keyPath value:value objectMapping:objectMapping]; [_matchers addObject:matcher]; [matcher release]; } - (RKObjectMapping*)objectMappingForDictionary:(NSDictionary*)data { NSAssert([data isKindOfClass:[NSDictionary class]], @"Dynamic object mapping can only be performed on NSDictionary mappables, got %@", NSStringFromClass([data class])); RKObjectMapping* mapping = nil; RKLogTrace(@"Performing dynamic object mapping for mappable data: %@", data); // Consult the declarative matchers first for (RKDynamicObjectMappingMatcher* matcher in _matchers) { if ([matcher isMatchForData:data]) { RKLogTrace(@"Found declarative match for data: %@.", [matcher matchDescription]); return matcher.objectMapping; } } // Otherwise consult the delegates if (self.delegate) { mapping = [self.delegate objectMappingForData:data]; if (mapping) { RKLogTrace(@"Found dynamic delegate match. Delegate = %@", self.delegate); return mapping; } } if (self.objectMappingForDataBlock) { mapping = self.objectMappingForDataBlock(data); if (mapping) { RKLogTrace(@"Found dynamic delegateBlock match. objectMappingForDataBlock = %@", self.objectMappingForDataBlock); } } return mapping; } @end // Compatibility alias... @implementation RKObjectDynamicMapping @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKDynamicObjectMapping.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKDynamicObjectMappingMatcher.h
// // RKDynamicObjectMappingMatcher.h // RestKit // // Created by Jeff Arena on 8/2/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <Foundation/Foundation.h> #import "RKObjectMapping.h" @interface RKDynamicObjectMappingMatcher : NSObject { NSString* _keyPath; id _value; RKObjectMapping* _objectMapping; NSString* _primaryKeyAttribute; BOOL (^_isMatchForDataBlock)(id data); } @property (nonatomic, readonly) RKObjectMapping* objectMapping; @property (nonatomic, readonly) NSString* primaryKeyAttribute; - (id)initWithKey:(NSString*)key value:(id)value objectMapping:(RKObjectMapping*)objectMapping; - (id)initWithKey:(NSString*)key value:(id)value primaryKeyAttribute:(NSString*)primaryKeyAttribute; - (id)initWithPrimaryKeyAttribute:(NSString*)primaryKeyAttribute evaluationBlock:(BOOL (^)(id data))block; - (BOOL)isMatchForData:(id)data; - (NSString*)matchDescription; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKDynamicObjectMappingMatcher.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKDynamicObjectMappingMatcher.m
// // RKDynamicObjectMappingMatcher.m // RestKit // // Created by Jeff Arena on 8/2/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKDynamicObjectMappingMatcher.h" // Implemented in RKObjectMappingOperation BOOL RKObjectIsValueEqualToValue(id sourceValue, id destinationValue); /////////////////////////////////////////////////////////////////////////////////////////////////// @implementation RKDynamicObjectMappingMatcher @synthesize objectMapping = _objectMapping; @synthesize primaryKeyAttribute = _primaryKeyAttribute; - (id)initWithKey:(NSString*)key value:(id)value objectMapping:(RKObjectMapping*)objectMapping { self = [super init]; if (self) { _keyPath = [key retain]; _value = [value retain]; _objectMapping = [objectMapping retain]; } return self; } - (id)initWithKey:(NSString*)key value:(id)value primaryKeyAttribute:(NSString*)primaryKeyAttribute { self = [super init]; if (self) { _keyPath = [key retain]; _value = [value retain]; _primaryKeyAttribute = [primaryKeyAttribute retain]; } return self; } - (id)initWithPrimaryKeyAttribute:(NSString*)primaryKeyAttribute evaluationBlock:(BOOL (^)(id data))block { self = [super init]; if (self) { _primaryKeyAttribute = [primaryKeyAttribute retain]; _isMatchForDataBlock = Block_copy(block); } return self; } - (void)dealloc { [_keyPath release]; [_value release]; [_objectMapping release]; [_primaryKeyAttribute release]; if (_isMatchForDataBlock) { Block_release(_isMatchForDataBlock); } [super dealloc]; } - (BOOL)isMatchForData:(id)data { if (_isMatchForDataBlock) { return _isMatchForDataBlock(data); } return RKObjectIsValueEqualToValue([data valueForKeyPath:_keyPath], _value); } - (NSString*)matchDescription { if (_isMatchForDataBlock) { return @"No description available. Using block to perform match."; } return [NSString stringWithFormat:@"%@ == %@", _keyPath, _value]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKDynamicObjectMappingMatcher.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKErrorMessage.h
// // RKError.h // RestKit // // Created by Jeremy Ellison on 5/10/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> /** A destination class for mapping simple remote error messages. */ @interface RKErrorMessage : NSObject { NSString* _errorMessage; } /** The error message string mapped from the response payload */ @property (nonatomic, retain) NSString* errorMessage; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKErrorMessage.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKErrorMessage.m
// // RKError.m // RestKit // // Created by Jeremy Ellison on 5/10/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKErrorMessage.h" @implementation RKErrorMessage @synthesize errorMessage = _errorMessage; - (void)dealloc { [_errorMessage release]; [super dealloc]; } - (NSString*)description { return _errorMessage; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKErrorMessage.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKMappingOperationQueue.h
// // RKMappingOperationQueue.h // RestKit // // Created by Blake Watters on 9/20/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import <Foundation/Foundation.h> /** Provides a simple interface for deferring portion of an larger object mapping operation until the entire aggregate operation has completed. This is used by Core Data to connect all object relationships once the entire object graph has been mapped, rather than as each object is encountered. Designed as a lightweight workalike for NSOperationQueue, which was not usable do to its reliance on threading for concurrent operations. The threading was causing problems with managed objects due to MOC being thread specific. This class is not intended to be thread-safe and is used for queueing non-concurrent operations that will be executed within the object mapper only. It is not a general purpose work queue. */ @interface RKMappingOperationQueue : NSObject { @protected NSMutableArray *_operations; } /** Adds an NSOperation to the queue for later execution @param op The operation to enqueue */ - (void)addOperation:(NSOperation *)op; /** Adds an NSBlockOperation to the queue configured to executed the block passed @param block A block to wrap into an operation for later execution */ - (void)addOperationWithBlock:(void (^)(void))block; /** Returns the collection of operations in the queue @return A new aray containing the NSOperation objects in the order in which they were added to the queue */ - (NSArray *)operations; /** Returns the number of operations in the queue @return The number of operations in the queue. */ - (NSUInteger)operationCount; /** Starts the execution of all operations in the queue in the order in which they were added to the queue. The current threads execution will be blocked until all enqueued operations have returned. */ - (void)waitUntilAllOperationsAreFinished; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKMappingOperationQueue.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKMappingOperationQueue.m
// // RKMappingOperationQueue.m // RestKit // // Created by Blake Watters on 9/20/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKMappingOperationQueue.h" @implementation RKMappingOperationQueue - (id)init { self = [super init]; if (self) { _operations = [NSMutableArray new]; } return self; } - (void)dealloc { [_operations release]; [super dealloc]; } - (void)addOperation:(NSOperation *)op { [_operations addObject:op]; } - (void)addOperationWithBlock:(void (^)(void))block { NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:block]; [_operations addObject:blockOperation]; } - (NSArray *)operations { return [NSArray arrayWithArray:_operations]; } - (NSUInteger)operationCount { return [_operations count]; } - (void)waitUntilAllOperationsAreFinished { for (NSOperation *operation in _operations) { [operation start]; } } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKMappingOperationQueue.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectAttributeMapping.h
// // RKObjectElementMapping.h // RestKit // // Created by Blake Watters on 4/30/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> // Defines the rules for mapping a particular element @interface RKObjectAttributeMapping : NSObject <NSCopying> { NSString *_sourceKeyPath; NSString *_destinationKeyPath; } @property (nonatomic, retain) NSString *sourceKeyPath; @property (nonatomic, retain) NSString *destinationKeyPath; /** Defines a mapping from one keyPath to another within an object mapping */ + (RKObjectAttributeMapping *)mappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath; /** Returns YES if this attribute mapping targets the key of a nested dictionary. When an object mapping is configured to target mapping of nested content via [RKObjectMapping mapKeyOfNestedDictionaryToAttribute:], a special attribute mapping is defined that targets the key of the nested dictionary rather than a value within in. This method will return YES if this attribute mapping is configured in such a way. @see [RKObjectMapping mapKeyOfNestedDictionaryToAttribute:] @return YES if this attribute mapping targets a nesting key path */ - (BOOL)isMappingForKeyOfNestedDictionary; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectAttributeMapping.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectAttributeMapping.m
// // RKObjectElementMapping.m // RestKit // // Created by Blake Watters on 4/30/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectAttributeMapping.h" extern NSString* const RKObjectMappingNestingAttributeKeyName; @implementation RKObjectAttributeMapping @synthesize sourceKeyPath = _sourceKeyPath; @synthesize destinationKeyPath = _destinationKeyPath; /** @private */ - (id)initWithSourceKeyPath:(NSString *)sourceKeyPath andDestinationKeyPath:(NSString *)destinationKeyPath { NSAssert(sourceKeyPath != nil, @"Cannot define an element mapping an element name to map from"); NSAssert(destinationKeyPath != nil, @"Cannot define an element mapping without a property to apply the value to"); self = [super init]; if (self) { _sourceKeyPath = [sourceKeyPath retain]; _destinationKeyPath = [destinationKeyPath retain]; } return self; } - (id)copyWithZone:(NSZone *)zone { RKObjectAttributeMapping* copy = [[[self class] allocWithZone:zone] initWithSourceKeyPath:self.sourceKeyPath andDestinationKeyPath:self.destinationKeyPath]; return copy; } - (void)dealloc { [_sourceKeyPath release]; [_destinationKeyPath release]; [super dealloc]; } - (NSString *)description { return [NSString stringWithFormat:@"RKObjectKeyPathMapping: %@ => %@", self.sourceKeyPath, self.destinationKeyPath]; } + (RKObjectAttributeMapping *)mappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath { RKObjectAttributeMapping *mapping = [[self alloc] initWithSourceKeyPath:sourceKeyPath andDestinationKeyPath:destinationKeyPath]; return [mapping autorelease]; } - (BOOL)isMappingForKeyOfNestedDictionary { return ([self.sourceKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName]); } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectAttributeMapping.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectLoader.h
// // RKObjectLoader.h // RestKit // // Created by Blake Watters on 8/8/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "Network.h" #import "RKObjectMapping.h" #import "RKObjectMappingResult.h" #import "RKObjectMappingProvider.h" @class RKObjectMappingProvider; @class RKObjectLoader; // Block Types typedef void(^RKObjectLoaderBlock)(RKObjectLoader *loader); typedef void(^RKObjectLoaderDidFailWithErrorBlock)(NSError *error); typedef void(^RKObjectLoaderDidLoadObjectsBlock)(NSArray *objects); typedef void(^RKObjectLoaderDidLoadObjectBlock)(id object); typedef void(^RKObjectLoaderDidLoadObjectsDictionaryBlock)(NSDictionary *dictionary); /** The delegate of an RKObjectLoader object must adopt the RKObjectLoaderDelegate protocol. Optional methods of the protocol allow the delegate to handle asynchronous object mapping operations performed by the object loader. Also note that the RKObjectLoaderDelegate protocol incorporates the RKRequestDelegate protocol and the delegate may provide implementations of methods from RKRequestDelegate as well. @see RKRequestDelegate */ @protocol RKObjectLoaderDelegate <RKRequestDelegate> @required /** * Sent when an object loaded failed to load the collection due to an error */ - (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error; @optional /** When implemented, sent to the delegate when the object laoder has completed successfully and loaded a collection of objects. All objects mapped from the remote payload will be returned as a single array. */ - (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects; /** When implemented, sent to the delegate when the object loader has completed succesfully. If the load resulted in a collection of objects being mapped, only the first object in the collection will be sent with this delegate method. This method simplifies things when you know you are working with a single object reference. */ - (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObject:(id)object; /** When implemented, sent to the delegate when an object loader has completed successfully. The dictionary will be expressed as pairs of keyPaths and objects mapped from the payload. This method is useful when you have multiple root objects and want to differentiate them by keyPath. */ - (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjectDictionary:(NSDictionary *)dictionary; /** Invoked when the object loader has finished loading */ - (void)objectLoaderDidFinishLoading:(RKObjectLoader *)objectLoader; /** Informs the delegate that the object loader has serialized the source object into a serializable representation for sending to the remote system. The serialization can be modified to allow customization of the request payload independent of mapping. @param objectLoader The object loader performing the serialization. @param sourceObject The object that was serialized. @param serialization The serialization of sourceObject to be sent to the remote backend for processing. */ - (void)objectLoader:(RKObjectLoader *)objectLoader didSerializeSourceObject:(id)sourceObject toSerialization:(inout id<RKRequestSerializable> *)serialization; /** Sent when an object loader encounters a response status code or MIME Type that RestKit does not know how to handle. Response codes in the 2xx, 4xx, and 5xx range are all handled as you would expect. 2xx (successful) response codes are considered a successful content load and object mapping will be attempted. 4xx and 5xx are interpretted as errors and RestKit will attempt to object map an error out of the payload (provided the MIME Type is mappable) and will invoke objectLoader:didFailWithError: after constructing an NSError. Any other status code is considered unexpected and will cause objectLoaderDidLoadUnexpectedResponse: to be invoked provided that you have provided an implementation in your delegate class. RestKit will also invoke objectLoaderDidLoadUnexpectedResponse: in the event that content is loaded, but there is not a parser registered to handle the MIME Type of the payload. This often happens when the remote backend system RestKit is talking to generates an HTML error page on failure. If your remote system returns content in a MIME Type other than application/json or application/xml, you must register the MIME Type and an appropriate parser with the [RKParserRegistry sharedParser] instance. Also note that in the event RestKit encounters an unexpected status code or MIME Type response an error will be constructed and sent to the delegate via objectLoader:didFailsWithError: unless your delegate provides an implementation of objectLoaderDidLoadUnexpectedResponse:. It is recommended that you provide an implementation and attempt to handle common unexpected MIME types (particularly text/html and text/plain). @optional */ - (void)objectLoaderDidLoadUnexpectedResponse:(RKObjectLoader *)objectLoader; /** Invoked just after parsing has completed, but before object mapping begins. This can be helpful to extract data from the parsed payload that is not object mapped, but is interesting for one reason or another. The mappableData will be made mutable via mutableCopy before the delegate method is invoked. Note that the mappable data is a pointer to a pointer to allow you to replace the mappable data with a new object to be mapped. You must dereference it to access the value. */ - (void)objectLoader:(RKObjectLoader *)loader willMapData:(inout id *)mappableData; @end /** * Wraps a request/response cycle and loads a remote object representation into local domain objects * * NOTE: When Core Data is linked into the application, the object manager will return instances of * RKManagedObjectLoader instead of RKObjectLoader. RKManagedObjectLoader is a descendent class that * includes Core Data specific mapping logic. */ @interface RKObjectLoader : RKRequest { id _sourceObject; id _targetObject; dispatch_queue_t _mappingQueue; } /** The object that acts as the delegate of the receiving object loader. @see RKRequestDelegate */ @property (nonatomic, assign) id<RKObjectLoaderDelegate> delegate; /** The block to invoke when the object loader fails due to an error. @see [RKObjectLoaderDelegate objectLoader:didFailWithError:] */ @property (nonatomic, copy) RKObjectLoaderDidFailWithErrorBlock onDidFailWithError; /** The block to invoke when the object loader has completed object mapping and the consumer wishes to retrieve a single object from the mapping result. @see [RKObjectLoaderDelegate objectLoader:didLoadObject:] @see RKObjectMappingResult */ @property (nonatomic, copy) RKObjectLoaderDidLoadObjectBlock onDidLoadObject; /** The block to invoke when the object loader has completed object mapping and the consumer wishes to retrieve an collections of objects from the mapping result. @see [RKObjectLoaderDelegate objectLoader:didLoadObjects:] @see RKObjectMappingResult */ @property (nonatomic, copy) RKObjectLoaderDidLoadObjectsBlock onDidLoadObjects; /** The block to invoke when the object loader has completed object mapping and the consumer wishes to retrieve the entire mapping result as a dictionary. Each key within the dictionary will correspond to a mapped keyPath within the source JSON/XML and the value will be the object mapped result. @see [RKObjectLoaderDelegate objectLoader:didLoadObjects:] @see RKObjectMappingResult */ @property (nonatomic, copy) RKObjectLoaderDidLoadObjectsDictionaryBlock onDidLoadObjectsDictionary; /** * The object mapping to use when processing the response. If this is nil, * then RestKit will search the parsed response body for mappable keyPaths and * perform mapping on all available content. For instances where your target JSON * is not returned under a uniquely identifiable keyPath, you must specify the object * mapping directly for RestKit to know how to map it. * * @default nil * @see RKObjectMappingProvider */ @property (nonatomic, retain) RKObjectMapping *objectMapping; /** A mapping provider containing object mapping configurations for mapping remote object representations into local domain objects. @see RKObjectMappingProvider */ @property (nonatomic, retain) RKObjectMappingProvider *mappingProvider; /** * The underlying response object for this loader */ @property (nonatomic, retain, readonly) RKResponse *response; /** * The mapping result that was produced after the request finished loading and * object mapping has completed. Provides access to the final products of the * object mapper in a variety of formats. */ @property (nonatomic, readonly) RKObjectMappingResult *result; /////////////////////////////////////////////////////////////////////////////////////////// // Serialization /** * The object mapping to use when serializing a target object for transport * to the remote server. * * @see RKObjectMappingProvider */ @property (nonatomic, retain) RKObjectMapping *serializationMapping; /** * The MIME Type to serialize the targetObject into according to the mapping * rules in the serializationMapping. Typical MIME Types for serialization are * JSON (RKMIMETypeJSON) and URL Form Encoded (RKMIMETypeFormURLEncoded). * * @see RKMIMEType */ @property (nonatomic, retain) NSString *serializationMIMEType; /** The object being serialized for transport. This object will be transformed into a serialization in the serializationMIMEType using the serializationMapping. @see RKObjectSerializer */ @property (nonatomic, retain) NSObject *sourceObject; /** * The target object to map results back onto. If nil, a new object instance * for the appropriate mapping will be created. If not nil, the results will * be used to update the targetObject's attributes and relationships. */ @property (nonatomic, retain) NSObject *targetObject; /** The Grand Central Dispatch queue to perform our parsing and object mapping within. By default, object loaders will use the mappingQueue from the RKObjectManager that created the loader. You can override this on a per-loader basis as necessary. */ @property (nonatomic, assign) dispatch_queue_t mappingQueue; /////////////////////////////////////////////////////////////////////////////////////////// /** Initialize and return an autoreleased object loader targeting a remote URL using a mapping provider @param URL A RestKit RKURL targetting a particular baseURL and resourcePath @param mappingProvider A mapping provider containing object mapping configurations for processing loaded payloads */ + (id)loaderWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider; /** Initialize and return an autoreleased object loader targeting a remote URL using a mapping provider @param URL A RestKit RKURL targetting a particular baseURL and resourcePath @param mappingProvider A mapping provider containing object mapping configurations for processing loaded payloads */ - (id)initWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider; /** * Handle an error in the response preventing it from being mapped, called from -isResponseMappable */ - (void)handleResponseError; @end @class RKObjectManager; @interface RKObjectLoader (Deprecations) + (id)loaderWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; - (id)initWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectLoader.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectLoader.m
// // RKObjectLoader.m // RestKit // // Created by Blake Watters on 8/8/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectLoader.h" #import "RKObjectMapper.h" #import "RKObjectManager.h" #import "RKObjectMapperError.h" #import "RKObjectLoader_Internals.h" #import "RKParserRegistry.h" #import "RKRequest_Internals.h" #import "RKObjectMappingProvider+Contexts.h" #import "RKObjectSerializer.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitNetwork @interface RKRequest (Private) - (void)updateInternalCacheDate; - (void)postRequestDidFailWithErrorNotification:(NSError *)error; @end @interface RKObjectLoader () @property (nonatomic, assign, readwrite, getter = isLoaded) BOOL loaded; @property (nonatomic, assign, readwrite, getter = isLoading) BOOL loading; @property (nonatomic, retain, readwrite) RKResponse *response; @end @implementation RKObjectLoader @synthesize mappingProvider = _mappingProvider; @synthesize targetObject = _targetObject; @synthesize objectMapping = _objectMapping; @synthesize result = _result; @synthesize serializationMapping = _serializationMapping; @synthesize serializationMIMEType = _serializationMIMEType; @synthesize sourceObject = _sourceObject; @synthesize mappingQueue = _mappingQueue; @synthesize onDidFailWithError = _onDidFailWithError; @synthesize onDidLoadObject = _onDidLoadObject; @synthesize onDidLoadObjects = _onDidLoadObjects; @synthesize onDidLoadObjectsDictionary = _onDidLoadObjectsDictionary; @dynamic loaded; @dynamic loading; @dynamic response; + (id)loaderWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider { return [[[self alloc] initWithURL:URL mappingProvider:mappingProvider] autorelease]; } - (id)initWithURL:(RKURL *)URL mappingProvider:(RKObjectMappingProvider *)mappingProvider { self = [super initWithURL:URL]; if (self) { _mappingProvider = [mappingProvider retain]; _mappingQueue = [RKObjectManager defaultMappingQueue]; } return self; } - (void)dealloc { [_mappingProvider release]; _mappingProvider = nil; [_sourceObject release]; _sourceObject = nil; [_targetObject release]; _targetObject = nil; [_objectMapping release]; _objectMapping = nil; [_result release]; _result = nil; [_serializationMIMEType release]; _serializationMIMEType = nil; [_serializationMapping release]; _serializationMapping = nil; [_onDidFailWithError release]; _onDidFailWithError = nil; [_onDidLoadObject release]; _onDidLoadObject = nil; [_onDidLoadObjects release]; _onDidLoadObjects = nil; [_onDidLoadObjectsDictionary release]; _onDidLoadObjectsDictionary = nil; [super dealloc]; } - (void)reset { [super reset]; [_result release]; _result = nil; } - (void)informDelegateOfError:(NSError *)error { [(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoader:self didFailWithError:error]; if (self.onDidFailWithError) { self.onDidFailWithError(error); } } #pragma mark - Response Processing // NOTE: This method is significant because the notifications posted are used by // RKRequestQueue to remove requests from the queue. All requests need to be finalized. - (void)finalizeLoad:(BOOL)successful { self.loading = NO; self.loaded = successful; if ([self.delegate respondsToSelector:@selector(objectLoaderDidFinishLoading:)]) { [(NSObject<RKObjectLoaderDelegate>*)self.delegate performSelectorOnMainThread:@selector(objectLoaderDidFinishLoading:) withObject:self waitUntilDone:YES]; } [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidFinishLoadingNotification object:self]; } // Invoked on the main thread. Inform the delegate. - (void)informDelegateOfObjectLoadWithResultDictionary:(NSDictionary*)resultDictionary { NSAssert([NSThread isMainThread], @"RKObjectLoaderDelegate callbacks must occur on the main thread"); RKObjectMappingResult* result = [RKObjectMappingResult mappingResultWithDictionary:resultDictionary]; // Dictionary callback if ([self.delegate respondsToSelector:@selector(objectLoader:didLoadObjectDictionary:)]) { [(NSObject<RKObjectLoaderDelegate>*)self.delegate objectLoader:self didLoadObjectDictionary:[result asDictionary]]; } if (self.onDidLoadObjectsDictionary) { self.onDidLoadObjectsDictionary([result asDictionary]); } // Collection callback if ([self.delegate respondsToSelector:@selector(objectLoader:didLoadObjects:)]) { [(NSObject<RKObjectLoaderDelegate>*)self.delegate objectLoader:self didLoadObjects:[result asCollection]]; } if (self.onDidLoadObjects) { self.onDidLoadObjects([result asCollection]); } // Singular object callback if ([self.delegate respondsToSelector:@selector(objectLoader:didLoadObject:)]) { [(NSObject<RKObjectLoaderDelegate>*)self.delegate objectLoader:self didLoadObject:[result asObject]]; } if (self.onDidLoadObject) { self.onDidLoadObject([result asObject]); } [self finalizeLoad:YES]; } #pragma mark - Subclass Hooks /** Overloaded by RKManagedObjectLoader to serialize/deserialize managed objects at thread boundaries. @protected */ - (void)processMappingResult:(RKObjectMappingResult*)result { NSAssert(_sentSynchronously || ![NSThread isMainThread], @"Mapping result processing should occur on a background thread"); [self performSelectorOnMainThread:@selector(informDelegateOfObjectLoadWithResultDictionary:) withObject:[result asDictionary] waitUntilDone:YES]; } #pragma mark - Response Object Mapping - (RKObjectMappingResult*)mapResponseWithMappingProvider:(RKObjectMappingProvider*)mappingProvider toObject:(id)targetObject inContext:(RKObjectMappingProviderContext)context error:(NSError**)error { id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:self.response.MIMEType]; NSAssert1(parser, @"Cannot perform object load without a parser for MIME Type '%@'", self.response.MIMEType); // Check that there is actually content in the response body for mapping. It is possible to get back a 200 response // with the appropriate MIME Type with no content (such as for a successful PUT or DELETE). Make sure we don't generate an error // in these cases id bodyAsString = [self.response bodyAsString]; RKLogTrace(@"bodyAsString: %@", bodyAsString); if (bodyAsString == nil || [[bodyAsString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) { RKLogDebug(@"Mapping attempted on empty response body..."); if (self.targetObject) { return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionaryWithObject:self.targetObject forKey:@""]]; } return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionary]]; } id parsedData = [parser objectFromString:bodyAsString error:error]; if (parsedData == nil && error) { return nil; } // Allow the delegate to manipulate the data if ([self.delegate respondsToSelector:@selector(objectLoader:willMapData:)]) { parsedData = [[parsedData mutableCopy] autorelease]; [(NSObject<RKObjectLoaderDelegate>*)self.delegate objectLoader:self willMapData:&parsedData]; } RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:mappingProvider]; mapper.targetObject = targetObject; mapper.delegate = self; mapper.context = context; RKObjectMappingResult* result = [mapper performMapping]; // Log any mapping errors if (mapper.errorCount > 0) { RKLogError(@"Encountered errors during mapping: %@", [[mapper.errors valueForKey:@"localizedDescription"] componentsJoinedByString:@", "]); } // The object mapper will return a nil result if mapping failed if (nil == result) { // TODO: Construct a composite error that wraps up all the other errors. Should probably make it performMapping:&error when we have this? if (error) *error = [mapper.errors lastObject]; return nil; } return result; } - (RKObjectMappingDefinition *)configuredObjectMapping { if (self.objectMapping) { return self.objectMapping; } return [self.mappingProvider objectMappingForResourcePath:self.resourcePath]; } - (RKObjectMappingResult*)performMapping:(NSError**)error { NSAssert(_sentSynchronously || ![NSThread isMainThread], @"Mapping should occur on a background thread"); RKObjectMappingProvider* mappingProvider; RKObjectMappingDefinition *configuredObjectMapping = [self configuredObjectMapping]; if (configuredObjectMapping) { mappingProvider = [RKObjectMappingProvider mappingProvider]; NSString *rootKeyPath = configuredObjectMapping.rootKeyPath ? configuredObjectMapping.rootKeyPath : @""; [mappingProvider setMapping:configuredObjectMapping forKeyPath:rootKeyPath]; // Copy the error mapping from our configured mappingProvider mappingProvider.errorMapping = self.mappingProvider.errorMapping; } else { RKLogDebug(@"No object mapping provider, using mapping provider from parent object manager to perform KVC mapping"); mappingProvider = self.mappingProvider; } return [self mapResponseWithMappingProvider:mappingProvider toObject:self.targetObject inContext:RKObjectMappingProviderContextObjectsByKeyPath error:error]; } - (void)performMappingInDispatchQueue { NSAssert(self.mappingQueue, @"mappingQueue cannot be nil"); dispatch_async(self.mappingQueue, ^{ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; RKLogDebug(@"Beginning object mapping activities within GCD queue labeled: %s", dispatch_queue_get_label(self.mappingQueue)); NSError *error = nil; _result = [[self performMapping:&error] retain]; NSAssert(_result || error, @"Expected performMapping to return a mapping result or an error."); if (self.result) { [self processMappingResult:self.result]; } else if (error) { [self performSelectorOnMainThread:@selector(didFailLoadWithError:) withObject:error waitUntilDone:NO]; } [pool drain]; }); } - (BOOL)canParseMIMEType:(NSString*)MIMEType { if ([[RKParserRegistry sharedRegistry] parserForMIMEType:self.response.MIMEType]) { return YES; } RKLogWarning(@"Unable to find parser for MIME Type '%@'", MIMEType); return NO; } - (BOOL)isResponseMappable { if ([self.response isServiceUnavailable]) { [[NSNotificationCenter defaultCenter] postNotificationName:RKServiceDidBecomeUnavailableNotification object:self]; } if ([self.response isFailure]) { [self informDelegateOfError:self.response.failureError]; [self didFailLoadWithError:self.response.failureError]; return NO; } else if ([self.response isNoContent]) { // The No Content (204) response will never have a message body or a MIME Type. id resultDictionary = nil; if (self.targetObject) { resultDictionary = [NSDictionary dictionaryWithObject:self.targetObject forKey:@""]; } else if (self.sourceObject) { resultDictionary = [NSDictionary dictionaryWithObject:self.sourceObject forKey:@""]; } else { resultDictionary = [NSDictionary dictionary]; } [self informDelegateOfObjectLoadWithResultDictionary:resultDictionary]; return NO; } else if (NO == [self canParseMIMEType:[self.response MIMEType]]) { // We can't parse the response, it's unmappable regardless of the status code RKLogWarning(@"Encountered unexpected response with status code: %ld (MIME Type: %@ -> URL: %@)", (long) self.response.statusCode, self.response.MIMEType, self.URL); NSError* error = [NSError errorWithDomain:RKErrorDomain code:RKObjectLoaderUnexpectedResponseError userInfo:nil]; if ([_delegate respondsToSelector:@selector(objectLoaderDidLoadUnexpectedResponse:)]) { [(NSObject<RKObjectLoaderDelegate>*)_delegate objectLoaderDidLoadUnexpectedResponse:self]; } else { [self informDelegateOfError:error]; } // NOTE: We skip didFailLoadWithError: here so that we don't send the delegate // conflicting messages around unexpected response and failure with error [self finalizeLoad:NO]; return NO; } else if ([self.response isError]) { // This is an error and we can map the MIME Type of the response [self handleResponseError]; return NO; } return YES; } - (void)handleResponseError { // Since we are mapping what we know to be an error response, we don't want to map the result back onto our // target object NSError *error = nil; RKObjectMappingResult *result = [self mapResponseWithMappingProvider:self.mappingProvider toObject:nil inContext:RKObjectMappingProviderContextErrors error:&error]; if (result) { error = [result asError]; } else { RKLogError(@"Encountered an error while attempting to map server side errors from payload: %@", [error localizedDescription]); } [self informDelegateOfError:error]; [self finalizeLoad:NO]; } #pragma mark - RKRequest & RKRequestDelegate methods // Invoked just before request hits the network - (BOOL)prepareURLRequest { if ((self.sourceObject && self.params == nil) && (self.method == RKRequestMethodPOST || self.method == RKRequestMethodPUT)) { NSAssert(self.serializationMapping, @"You must provide a serialization mapping for objects of type '%@'", NSStringFromClass([self.sourceObject class])); RKLogDebug(@"POST or PUT request for source object %@, serializing to MIME Type %@ for transport...", self.sourceObject, self.serializationMIMEType); RKObjectSerializer* serializer = [RKObjectSerializer serializerWithObject:self.sourceObject mapping:self.serializationMapping]; NSError* error = nil; id params = [serializer serializationForMIMEType:self.serializationMIMEType error:&error]; if (error) { RKLogError(@"Serializing failed for source object %@ to MIME Type %@: %@", self.sourceObject, self.serializationMIMEType, [error localizedDescription]); [self didFailLoadWithError:error]; return NO; } if ([self.delegate respondsToSelector:@selector(objectLoader:didSerializeSourceObject:toSerialization:)]) { [self.delegate objectLoader:self didSerializeSourceObject:self.sourceObject toSerialization:¶ms]; } self.params = params; } // TODO: This is an informal protocol ATM. Maybe its not obvious enough? if (self.sourceObject) { if ([self.sourceObject respondsToSelector:@selector(willSendWithObjectLoader:)]) { [self.sourceObject performSelector:@selector(willSendWithObjectLoader:) withObject:self]; } } return [super prepareURLRequest]; } - (void)didFailLoadWithError:(NSError *)error { NSParameterAssert(error); NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; if (_cachePolicy & RKRequestCachePolicyLoadOnError && [self.cache hasResponseForRequest:self]) { [self didFinishLoad:[self.cache responseForRequest:self]]; } else { if ([_delegate respondsToSelector:@selector(request:didFailLoadWithError:)]) { [_delegate request:self didFailLoadWithError:error]; } if (self.onDidFailLoadWithError) { self.onDidFailLoadWithError(error); } // If we failed due to a transport error or before we have a response, the request itself failed if (!self.response || [self.response isFailure]) { NSDictionary* userInfo = [NSDictionary dictionaryWithObject:error forKey:RKRequestDidFailWithErrorNotificationUserInfoErrorKey]; [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidFailWithErrorNotification object:self userInfo:userInfo]; } if (! self.isCancelled) { [self informDelegateOfError:error]; } [self finalizeLoad:NO]; } [pool release]; } // NOTE: We do NOT call super here. We are overloading the default behavior from RKRequest - (void)didFinishLoad:(RKResponse*)response { NSAssert([NSThread isMainThread], @"RKObjectLoaderDelegate callbacks must occur on the main thread"); self.response = response; if ((_cachePolicy & RKRequestCachePolicyEtag) && [response isNotModified]) { self.response = [self.cache responseForRequest:self]; NSAssert(self.response, @"Unexpectedly loaded nil response from cache"); [self updateInternalCacheDate]; } if (![self.response wasLoadedFromCache] && [self.response isSuccessful] && (_cachePolicy != RKRequestCachePolicyNone)) { [self.cache storeResponse:self.response forRequest:self]; } if ([_delegate respondsToSelector:@selector(request:didLoadResponse:)]) { [_delegate request:self didLoadResponse:self.response]; } if (self.onDidLoadResponse) { self.onDidLoadResponse(self.response); } // Post the notification NSDictionary* userInfo = [NSDictionary dictionaryWithObject:self.response forKey:RKRequestDidLoadResponseNotificationUserInfoResponseKey]; [[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidLoadResponseNotification object:self userInfo:userInfo]; if ([self isResponseMappable]) { // Determine if we are synchronous here or not. if (_sentSynchronously) { NSError* error = nil; _result = [[self performMapping:&error] retain]; if (self.result) { [self processMappingResult:self.result]; } else { [self performSelectorInBackground:@selector(didFailLoadWithError:) withObject:error]; } } else { [self performMappingInDispatchQueue]; } } } - (void)setMappingQueue:(dispatch_queue_t)newMappingQueue { if (_mappingQueue) { dispatch_release(_mappingQueue); _mappingQueue = nil; } if (newMappingQueue) { dispatch_retain(newMappingQueue); _mappingQueue = newMappingQueue; } } // Proxy the delegate property back to our superclass implementation. The object loader should // really not be a subclass of RKRequest. - (void)setDelegate:(id<RKObjectLoaderDelegate>)delegate { [super setDelegate:delegate]; } - (id<RKObjectLoaderDelegate>)delegate { return (id<RKObjectLoaderDelegate>) [super delegate]; } @end @implementation RKObjectLoader (Deprecations) + (id)loaderWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)delegate { return [[[self alloc] initWithResourcePath:resourcePath objectManager:objectManager delegate:delegate] autorelease]; } - (id)initWithResourcePath:(NSString*)resourcePath objectManager:(RKObjectManager*)objectManager delegate:(id<RKObjectLoaderDelegate>)theDelegate { if ((self = [self initWithURL:[objectManager.baseURL URLByAppendingResourcePath:resourcePath] mappingProvider:objectManager.mappingProvider])) { [objectManager.client configureRequest:self]; _delegate = theDelegate; } return self; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectLoader.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectLoader_Internals.h
// // RKObjectLoader_Internals.h // RestKit // // Created by Blake Watters on 5/13/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> @interface RKObjectLoader (Internals) <RKObjectMapperDelegate> @property (nonatomic, readonly) RKClient* client; - (void)handleTargetObject; - (void)informDelegateOfObjectLoadWithResultDictionary:(NSDictionary*)dictionary; - (void)performMappingOnBackgroundThread; - (BOOL)isResponseMappable; - (void)finalizeLoad:(BOOL)successful error:(NSError*)error; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectLoader_Internals.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectManager.h
// // RKObjectManager.h // RestKit // // Created by Jeremy Ellison on 8/14/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "Network.h" #import "RKObjectLoader.h" #import "RKObjectRouter.h" #import "RKObjectMappingProvider.h" #import "RKConfigurationDelegate.h" #import "RKObjectPaginator.h" @protocol RKParser; /** Notifications */ /** Posted when the object managed has transitioned to the offline state */ extern NSString* const RKObjectManagerDidBecomeOfflineNotification; /** Posted when the object managed has transitioned to the online state */ extern NSString* const RKObjectManagerDidBecomeOnlineNotification; typedef enum { RKObjectManagerNetworkStatusUnknown, RKObjectManagerNetworkStatusOffline, RKObjectManagerNetworkStatusOnline } RKObjectManagerNetworkStatus; @class RKManagedObjectStore; /** The object manager is the primary interface for interacting with RESTful resources via HTTP. It is responsible for retrieving remote object representations via HTTP and transforming them into local domain objects via the RKObjectMapper. It is also capable of serializing local objects and sending them to a remote system for processing. The object manager strives to hide the developer from the details of configuring an RKRequest, processing an RKResponse, parsing any data returned by the remote system, and running the parsed data through the object mapper. <h3>Shared Manager Instance</h3> Multiple instances of RKObjectManager may be used in parallel, but the first instance initialized is automatically configured as the sharedManager instance. The shared instance can be changed at runtime if so desired. See sharedManager and setSharedManager for details. <h3>Configuring the Object Manager</h3> The object mapper must be configured before object can be loaded from or transmitted to your remote backend system. Configuration consists of specifying the desired MIME types to be used during loads and serialization, registering object mappings to use for mapping and serialization, registering routes, and optionally configuring an instance of the managed object store (for Core Data). <h4>MIME Types</h4> MIME Types are used for two purposes within RestKit: 1. Content Negotiation. RestKit leverages the HTTP Accept header to specify the desired representation of content when contacting a remote web service. You can specify the MIME Type to use via the acceptMIMEType method. The default MIME Type is RKMIMETypeJSON (application/json). If the remote web service responds with content in a different MIME Type than specified, RestKit will attempt to parse it by consulting the [parser registry][RKParserRegistry parserForMIMEType:]. Failure to find a parser for the returned content will result in an unexpected response invocation of [RKObjectLoaderDelegate objectLoaderDidLoadUnexpectedResponse]. 1. Serialization. RestKit can be used to transport local object representation back to the remote web server for processing by serializing them into an RKRequestSerializable representation. The desired serialization format is configured by setting the serializationMIMEType property. RestKit currently supports serialization to RKMIMETypeFormURLEncoded and RKMIMETypeJSON. The serialization rules themselves are expressed via an instance of RKObjectMapping. <h4>The Mapping Provider</h4> RestKit determines how to map and serialize objects by consulting the mappingProvider. The mapping provider is responsible for providing instances of RKObjectMapper with object mappings that should be used for transforming mappable data into object representations. When you ask the object manager to load or send objects for you, the mappingProvider instance will be used for the object mapping operations constructed for you. In this way, the mappingProvider is the central registry for the knowledge about how objects in your application are mapped. Mappings are registered by constructing instances of RKObjectMapping and registering them with the provider: ` RKObjectManager* manager = [RKObjectManager managerWithBaseURL:myBaseURL]; RKObjectMapping* articleMapping = [RKObjectMapping mappingForClass:[Article class]]; [mapping mapAttributes:@"title", @"body", @"publishedAt", nil]; [manager.mappingProvider setObjectMapping:articleMapping forKeyPath:@"article"]; // Generate an inverse mapping for transforming Article -> NSMutableDictionary. [manager.mappingProvider setSerializationMapping:[articleMapping inverseMapping] forClass:[Article class]];` <h4>Configuring Routes</h4> Routing is the process of transforming objects and actions (as defined by HTTP verbs) into resource paths. RestKit ships <h4>Initializing a Core Data Object Store</h4> <h3>Loading Remote Objects</h3> <h3>Routing & Object Serialization</h3> <h3>Default Error Mapping</h3> When an instance of RKObjectManager is configured, the RKObjectMappingProvider instance configured */ @interface RKObjectManager : NSObject <RKConfigurationDelegate> /// @name Configuring the Shared Manager Instance /** Return the shared instance of the object manager */ + (RKObjectManager *)sharedManager; /** Set the shared instance of the object manager */ + (void)setSharedManager:(RKObjectManager *)manager; /** @name Object Mapping Dispatch Queue */ /** Returns the global default Grand Central Dispatch queue used for object mapping operations executed by RKObjectLoaders. All object loaders perform their loading within a Grand Central Dispatch queue. This provides control over the number of loaders that are performing expensive operations such as JSON parsing, object mapping, and accessing Core Data concurrently. The defaultMappingQueue is configured as the mappingQueue for all RKObjectManager's created by RestKit, but can be overridden on a per manager and per object loader basis. By default, the defaultMappingQueue is configured as serial GCD queue. */ + (dispatch_queue_t)defaultMappingQueue; /** Sets a new global default Grand Central Dispatch queue for use in object mapping operations executed by RKObjectLoaders. */ + (void)setDefaultMappingQueue:(dispatch_queue_t)defaultMappingQueue; /// @name Initializing an Object Manager /** Create and initialize a new object manager. If this is the first instance created it will be set as the shared instance */ + (id)managerWithBaseURLString:(NSString *)baseURLString; + (id)managerWithBaseURL:(NSURL *)baseURL; /** Initializes a newly created object manager with a specified baseURL. @param baseURL A baseURL to initialize the underlying client instance with @return The newly initialized RKObjectManager object */ - (id)initWithBaseURL:(RKURL *)baseURL; /// @name Network Integration /** The underlying HTTP client for this manager */ @property (nonatomic, retain) RKClient *client; /** The base URL of the underlying RKClient instance. Object loader and paginator instances built through the object manager are relative to this URL. @see RKClient @return The baseURL of the client. */ @property (nonatomic, readonly) RKURL *baseURL; /** The request cache used to store and load responses for requests sent through this object manager's underlying client object */ @property (nonatomic, readonly) RKRequestCache *requestCache; /** The request queue used to dispatch asynchronous requests sent through this object manager's underlying client object */ @property (nonatomic, readonly) RKRequestQueue *requestQueue; /** Returns the current network status for this object manager as determined by connectivity to the remote backend system */ @property (nonatomic, readonly) RKObjectManagerNetworkStatus networkStatus; /** Returns YES when we are in online mode */ @property (nonatomic, readonly) BOOL isOnline; /** Returns YES when we are in offline mode */ @property (nonatomic, readonly) BOOL isOffline; /// @name Configuring Object Mapping /** The Mapping Provider responsible for returning mappings for various keyPaths. */ @property (nonatomic, retain) RKObjectMappingProvider *mappingProvider; /** Router object responsible for generating resource paths for HTTP requests */ @property (nonatomic, retain) RKObjectRouter *router; /** A Core Data backed object store for persisting objects that have been fetched from the Web */ @property (nonatomic, retain) RKManagedObjectStore *objectStore; /** The Grand Dispatch Queue to use when performing expensive object mapping operations within RKObjectLoader instances created through this object manager */ @property (nonatomic, assign) dispatch_queue_t mappingQueue; /** The Default MIME Type to be used in object serialization. */ @property (nonatomic, retain) NSString *serializationMIMEType; /** The value for the HTTP Accept header to specify the preferred format for retrieved data */ @property (nonatomic, assign) NSString *acceptMIMEType; //////////////////////////////////////////////////////// /// @name Building Object Loaders /** Returns the class of object loader instances built through the manager. When Core Data has been configured, instances of RKManagedObjectLoader will be emitted by the manager. Otherwise RKObjectLoader is used. @return RKObjectLoader OR RKManagedObjectLoader */ - (Class)objectLoaderClass; /** Creates and returns an RKObjectLoader or RKManagedObjectLoader instance targeting the specified resourcePath. The object loader instantiated will be initialized with an RKURL built by appending the resourcePath to the baseURL of the client. The loader will then be configured with object mapping configuration from the manager and request configuration from the client. @param resourcePath A resource to use when building the URL to initialize the object loader instance. @return The newly created object loader instance. @see RKURL @see RKClient */ - (id)loaderWithResourcePath:(NSString *)resourcePath; /** Creates and returns an RKObjectLoader or RKManagedObjectLoader instance targeting the specified URL. The object loader instantiated will be initialized with URL and will then be configured with object mapping configuration from the manager and request configuration from the client. @param URL The URL with which to initialize the object loader. @return The newly created object loader instance. @see RKURL @see RKClient */ - (id)loaderWithURL:(NSURL *)URL; /** Creates and returns an RKObjectLoader or RKManagedObjectLoader instance for an object instance. The object loader instantiated will be initialized with a URL built by evaluating the object with the router to construct a resource path and then appending that resource path to the baseURL of the client. The loader will then be configured with object mapping configuration from the manager and request configuration from the client. The specified object will be the target of the object loader and will have any returned content mapped back onto the instance. @param object The object with which to initialize the object loader. @return The newly created object loader instance. @see RKObjectLoader @see RKObjectRouter */ - (id)loaderForObject:(id<NSObject>)object method:(RKRequestMethod)method; /** Creates and returns an RKObjectPaginator instance targeting the specified resource path pattern. The paginator instantiated will be initialized with an RKURL built by appending the resourcePathPattern to the baseURL of the client. @return The newly created paginator instance. @see RKObjectMappingProvider @see RKObjectPaginator */ - (RKObjectPaginator *)paginatorWithResourcePathPattern:(NSString *)resourcePathPattern; //////////////////////////////////////////////////////// /// @name Registered Object Loaders /** These methods are suitable for loading remote payloads that encode type information into the payload. This enables the mapping of complex payloads spanning multiple types (i.e. a search operation returning Articles & Comments in one payload). Ruby on Rails JSON serialization is an example of such a conformant system. */ /** Create and send an asynchronous GET request to load the objects at the resource path and call back the delegate with the loaded objects. Remote objects will be mapped to local objects by consulting the keyPath registrations set on the mapping provider. */ - (void)loadObjectsAtResourcePath:(NSString *)resourcePath delegate:(id<RKObjectLoaderDelegate>)delegate; //////////////////////////////////////////////////////// /// @name Mappable Object Loaders /** Fetch the data for a mappable object by performing an HTTP GET. */ - (void)getObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate; /** Create a remote mappable model by POSTing the attributes to the remote resource and loading the resulting objects from the payload */ - (void)postObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate; /** Update a remote mappable model by PUTing the attributes to the remote resource and loading the resulting objects from the payload */ - (void)putObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate; /** Delete the remote instance of a mappable model by performing an HTTP DELETE on the remote resource */ - (void)deleteObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate; //////////////////////////////////////////////////////// /// @name Block Configured Object Loaders #if NS_BLOCKS_AVAILABLE /** Load the objects at the specified resource path and perform object mapping on the response payload. Prior to sending the object loader, the block will be invoked to allow you to configure the object loader as you see fit. This can be used to change the response type, set custom parameters, choose an object mapping, etc. For example: - (void)loadObjectUsingBlockExample { [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/monkeys.json" usingBlock:^(RKObjectLoader* loader) { loader.objectMapping = [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:[Monkey class]]; }]; } */ - (void)loadObjectsAtResourcePath:(NSString *)resourcePath usingBlock:(RKObjectLoaderBlock)block; /* Configure and send an object loader after yielding it to a block for configuration. This allows for very succinct on-the-fly configuration of the request without obtaining an object reference via objectLoaderForObject: and then sending it yourself. For example: - (BOOL)changePassword:(NSString*)newPassword error:(NSError**)error { if ([self validatePassword:newPassword error:error]) { self.password = newPassword; [[RKObjectManager sharedManager] sendObject:self toResourcePath:@"/some/path" usingBlock:^(RKObjectLoader* loader) { loader.delegate = self; loader.method = RKRequestMethodPOST; loader.serializationMIMEType = RKMIMETypeJSON; // We want to send this request as JSON loader.targetObject = nil; // Map the results back onto a new object instead of self // Set up a custom serialization mapping to handle this request loader.serializationMapping = [RKObjectMapping serializationMappingUsingBlock:^(RKObjectMapping* mapping) { [mapping mapAttributes:@"password", nil]; }]; }]; } } */ - (void)sendObject:(id<NSObject>)object toResourcePath:(NSString *)resourcePath usingBlock:(RKObjectLoaderBlock)block; /** GET a remote object instance and yield the object loader to the block before sending @see sendObject:method:delegate:block */ - (void)getObject:(id<NSObject>)object usingBlock:(RKObjectLoaderBlock)block; /** POST a remote object instance and yield the object loader to the block before sending @see sendObject:method:delegate:block */ - (void)postObject:(id<NSObject>)object usingBlock:(RKObjectLoaderBlock)block; /** PUT a remote object instance and yield the object loader to the block before sending @see sendObject:method:delegate:block */ - (void)putObject:(id<NSObject>)object usingBlock:(RKObjectLoaderBlock)block; /** DELETE a remote object instance and yield the object loader to the block before sending @see sendObject:method:delegate:block */ - (void)deleteObject:(id<NSObject>)object usingBlock:(RKObjectLoaderBlock)block; #endif ////// // Deprecations + (RKObjectManager *)objectManagerWithBaseURLString:(NSString *)baseURLString; + (RKObjectManager *)objectManagerWithBaseURL:(NSURL *)baseURL; - (void)loadObjectsAtResourcePath:(NSString*)resourcePath objectMapping:(RKObjectMapping*)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; - (RKObjectLoader *)objectLoaderWithResourcePath:(NSString*)resourcePath delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; - (RKObjectLoader *)objectLoaderForObject:(id<NSObject>)object method:(RKRequestMethod)method delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; /* NOTE: The mapResponseWith: family of methods have been deprecated by the support for object mapping selection using resourcePath's */ /*- (RKObjectLoader*)objectLoaderForObject:(id<NSObject>)object method:(RKRequestMethod)method delegate:(id<RKObjectLoaderDelegate>)delegate;*/ /*- (RKObjectLoader *)objectLoaderForObject:(id<NSObject>)object method:(RKRequestMethod)method delegate:(id<RKObjectLoaderDelegate>)delegate;*/ - (void)getObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; - (void)postObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; - (void)putObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; - (void)deleteObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate DEPRECATED_ATTRIBUTE; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectManager.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectManager.m
// // RKObjectManager.m // RestKit // // Created by Jeremy Ellison on 8/14/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectManager.h" #import "RKObjectSerializer.h" #import "RKManagedObjectStore.h" #import "RKManagedObjectLoader.h" #import "Support.h" #import "RKErrorMessage.h" NSString* const RKObjectManagerDidBecomeOfflineNotification = @"RKDidEnterOfflineModeNotification"; NSString* const RKObjectManagerDidBecomeOnlineNotification = @"RKDidEnterOnlineModeNotification"; ////////////////////////////////// // Shared Instances static RKObjectManager *sharedManager = nil; static dispatch_queue_t defaultMappingQueue = nil; /////////////////////////////////// @interface RKObjectManager () @property (nonatomic, assign, readwrite) RKObjectManagerNetworkStatus networkStatus; @end @implementation RKObjectManager @synthesize client = _client; @synthesize objectStore = _objectStore; @synthesize router = _router; @synthesize mappingProvider = _mappingProvider; @synthesize serializationMIMEType = _serializationMIMEType; @synthesize networkStatus = _networkStatus; @synthesize mappingQueue = _mappingQueue; + (dispatch_queue_t)defaultMappingQueue { if (! defaultMappingQueue) { defaultMappingQueue = dispatch_queue_create("org.restkit.ObjectMapping", DISPATCH_QUEUE_SERIAL); } return defaultMappingQueue; } + (void)setDefaultMappingQueue:(dispatch_queue_t)newDefaultMappingQueue { if (defaultMappingQueue) { dispatch_release(defaultMappingQueue); defaultMappingQueue = nil; } if (newDefaultMappingQueue) { dispatch_retain(newDefaultMappingQueue); defaultMappingQueue = newDefaultMappingQueue; } } - (id)init { self = [super init]; if (self) { _mappingProvider = [RKObjectMappingProvider new]; _router = [RKObjectRouter new]; _networkStatus = RKObjectManagerNetworkStatusUnknown; self.serializationMIMEType = RKMIMETypeFormURLEncoded; self.mappingQueue = [RKObjectManager defaultMappingQueue]; // Setup default error message mappings RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]]; errorMapping.rootKeyPath = @"errors"; [errorMapping mapKeyPath:@"" toAttribute:@"errorMessage"]; _mappingProvider.errorMapping = errorMapping; [self addObserver:self forKeyPath:@"client.reachabilityObserver" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial context:nil]; // Set shared manager if nil if (nil == sharedManager) { [RKObjectManager setSharedManager:self]; } } return self; } - (id)initWithBaseURL:(RKURL *)baseURL { self = [self init]; if (self) { self.client = [RKClient clientWithBaseURL:baseURL]; self.acceptMIMEType = RKMIMETypeJSON; } return self; } + (RKObjectManager *)sharedManager { return sharedManager; } + (void)setSharedManager:(RKObjectManager *)manager { [manager retain]; [sharedManager release]; sharedManager = manager; } + (RKObjectManager *)managerWithBaseURLString:(NSString *)baseURLString { return [self managerWithBaseURL:[RKURL URLWithString:baseURLString]]; } + (RKObjectManager *)managerWithBaseURL:(NSURL *)baseURL { RKObjectManager *manager = [[[self alloc] initWithBaseURL:baseURL] autorelease]; return manager; } - (void)dealloc { [self removeObserver:self forKeyPath:@"client.reachabilityObserver"]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [_router release]; _router = nil; self.client = nil; [_objectStore release]; _objectStore = nil; [_serializationMIMEType release]; _serializationMIMEType = nil; [_mappingProvider release]; _mappingProvider = nil; [super dealloc]; } - (BOOL)isOnline { return (_networkStatus == RKObjectManagerNetworkStatusOnline); } - (BOOL)isOffline { return (_networkStatus == RKObjectManagerNetworkStatusOffline); } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"client.reachabilityObserver"]) { [self reachabilityObserverDidChange:change]; } } - (void)reachabilityObserverDidChange:(NSDictionary *)change { RKReachabilityObserver *oldReachabilityObserver = [change objectForKey:NSKeyValueChangeOldKey]; RKReachabilityObserver *newReachabilityObserver = [change objectForKey:NSKeyValueChangeNewKey]; if (! [oldReachabilityObserver isEqual:[NSNull null]]) { RKLogDebug(@"Reachability observer changed for RKClient %@ of RKObjectManager %@, stopping observing reachability changes", self.client, self); [[NSNotificationCenter defaultCenter] removeObserver:self name:RKReachabilityDidChangeNotification object:oldReachabilityObserver]; } if (! [newReachabilityObserver isEqual:[NSNull null]]) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:RKReachabilityDidChangeNotification object:newReachabilityObserver]; RKLogDebug(@"Reachability observer changed for client %@ of object manager %@, starting observing reachability changes", self.client, self); } // Initialize current Network Status if ([self.client.reachabilityObserver isReachabilityDetermined]) { BOOL isNetworkReachable = [self.client.reachabilityObserver isNetworkReachable]; self.networkStatus = isNetworkReachable ? RKObjectManagerNetworkStatusOnline : RKObjectManagerNetworkStatusOffline; } else { self.networkStatus = RKObjectManagerNetworkStatusUnknown; } } - (void)reachabilityChanged:(NSNotification *)notification { BOOL isHostReachable = [self.client.reachabilityObserver isNetworkReachable]; _networkStatus = isHostReachable ? RKObjectManagerNetworkStatusOnline : RKObjectManagerNetworkStatusOffline; if (isHostReachable) { [[NSNotificationCenter defaultCenter] postNotificationName:RKObjectManagerDidBecomeOnlineNotification object:self]; } else { [[NSNotificationCenter defaultCenter] postNotificationName:RKObjectManagerDidBecomeOfflineNotification object:self]; } } - (void)setAcceptMIMEType:(NSString *)MIMEType { [_client setValue:MIMEType forHTTPHeaderField:@"Accept"]; } - (NSString *)acceptMIMEType { return [self.client.HTTPHeaders valueForKey:@"Accept"]; } ///////////////////////////////////////////////////////////// #pragma mark - Object Collection Loaders - (Class)objectLoaderClass { Class managedObjectLoaderClass = NSClassFromString(@"RKManagedObjectLoader"); if (self.objectStore && managedObjectLoaderClass) { return managedObjectLoaderClass; } return [RKObjectLoader class]; } - (id)loaderWithResourcePath:(NSString *)resourcePath { RKURL *URL = [self.baseURL URLByAppendingResourcePath:resourcePath]; return [self loaderWithURL:URL]; } - (id)loaderWithURL:(RKURL *)URL { RKObjectLoader *loader = [[self objectLoaderClass] loaderWithURL:URL mappingProvider:self.mappingProvider]; loader.configurationDelegate = self; if ([loader isKindOfClass:[RKManagedObjectLoader class]]) { [(RKManagedObjectLoader *)loader setObjectStore:self.objectStore]; } [self configureObjectLoader:loader]; return loader; } - (NSURL *)baseURL { return self.client.baseURL; } - (RKObjectPaginator *)paginatorWithResourcePathPattern:(NSString *)resourcePathPattern { RKURL *patternURL = [[self baseURL] URLByAppendingResourcePath:resourcePathPattern]; RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:self.mappingProvider]; paginator.configurationDelegate = self; return paginator; } - (id)loaderForObject:(id<NSObject>)object method:(RKRequestMethod)method { NSString* resourcePath = (method == RKRequestMethodInvalid) ? nil : [self.router resourcePathForObject:object method:method]; RKObjectLoader *loader = [self loaderWithResourcePath:resourcePath]; loader.method = method; loader.sourceObject = object; loader.serializationMIMEType = self.serializationMIMEType; loader.serializationMapping = [self.mappingProvider serializationMappingForClass:[object class]]; RKObjectMappingDefinition *objectMapping = resourcePath ? [self.mappingProvider objectMappingForResourcePath:resourcePath] : nil; if (objectMapping == nil || ([objectMapping isKindOfClass:[RKObjectMapping class]] && [object isMemberOfClass:[(RKObjectMapping *)objectMapping objectClass]])) { loader.targetObject = object; } else { loader.targetObject = nil; } return loader; } - (void)loadObjectsAtResourcePath:(NSString *)resourcePath delegate:(id<RKObjectLoaderDelegate>)delegate { RKObjectLoader *loader = [self loaderWithResourcePath:resourcePath]; loader.delegate = delegate; loader.method = RKRequestMethodGET; [loader send]; } ///////////////////////////////////////////////////////////// #pragma mark - Object Instance Loaders - (void)getObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate { RKObjectLoader *loader = [self loaderForObject:object method:RKRequestMethodGET]; loader.delegate = delegate; [loader send]; } - (void)postObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate { RKObjectLoader *loader = [self loaderForObject:object method:RKRequestMethodPOST]; loader.delegate = delegate; [loader send]; } - (void)putObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate { RKObjectLoader *loader = [self loaderForObject:object method:RKRequestMethodPUT]; loader.delegate = delegate; [loader send]; } - (void)deleteObject:(id<NSObject>)object delegate:(id<RKObjectLoaderDelegate>)delegate { RKObjectLoader *loader = [self loaderForObject:object method:RKRequestMethodDELETE]; loader.delegate = delegate; [loader send]; } #if NS_BLOCKS_AVAILABLE #pragma mark - Block Configured Object Loaders - (void)loadObjectsAtResourcePath:(NSString*)resourcePath usingBlock:(void(^)(RKObjectLoader *))block { RKObjectLoader* loader = [self loaderWithResourcePath:resourcePath]; loader.method = RKRequestMethodGET; // Yield to the block for setup block(loader); [loader send]; } - (void)sendObject:(id<NSObject>)object toResourcePath:(NSString *)resourcePath usingBlock:(void(^)(RKObjectLoader *))block { RKObjectLoader *loader = [self loaderForObject:object method:RKRequestMethodInvalid]; loader.URL = [self.baseURL URLByAppendingResourcePath:resourcePath]; // Yield to the block for setup block(loader); [loader send]; } - (void)sendObject:(id<NSObject>)object method:(RKRequestMethod)method usingBlock:(void(^)(RKObjectLoader *))block { NSString *resourcePath = [self.router resourcePathForObject:object method:method]; [self sendObject:object toResourcePath:resourcePath usingBlock:^(RKObjectLoader *loader) { loader.method = method; block(loader); }]; } - (void)getObject:(id<NSObject>)object usingBlock:(void(^)(RKObjectLoader *))block { [self sendObject:object method:RKRequestMethodGET usingBlock:block]; } - (void)postObject:(id<NSObject>)object usingBlock:(void(^)(RKObjectLoader *))block { [self sendObject:object method:RKRequestMethodPOST usingBlock:block]; } - (void)putObject:(id<NSObject>)object usingBlock:(void(^)(RKObjectLoader *))block { [self sendObject:object method:RKRequestMethodPUT usingBlock:block]; } - (void)deleteObject:(id<NSObject>)object usingBlock:(void(^)(RKObjectLoader *))block { [self sendObject:object method:RKRequestMethodDELETE usingBlock:block]; } #endif // NS_BLOCKS_AVAILABLE #pragma mark - Object Instance Loaders for Non-nested JSON - (void)getObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate { [self sendObject:object method:RKRequestMethodGET usingBlock:^(RKObjectLoader *loader) { loader.delegate = delegate; loader.objectMapping = objectMapping; }]; } - (void)postObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate { [self sendObject:object method:RKRequestMethodPOST usingBlock:^(RKObjectLoader *loader) { loader.delegate = delegate; loader.objectMapping = objectMapping; }]; } - (void)putObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate { [self sendObject:object method:RKRequestMethodPUT usingBlock:^(RKObjectLoader *loader) { loader.delegate = delegate; loader.objectMapping = objectMapping; }]; } - (void)deleteObject:(id<NSObject>)object mapResponseWith:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate { [self sendObject:object method:RKRequestMethodDELETE usingBlock:^(RKObjectLoader *loader) { loader.delegate = delegate; loader.objectMapping = objectMapping; }]; } - (RKRequestCache *)requestCache { return self.client.requestCache; } - (RKRequestQueue *)requestQueue { return self.client.requestQueue; } - (void)setMappingQueue:(dispatch_queue_t)newMappingQueue { if (_mappingQueue) { dispatch_release(_mappingQueue); _mappingQueue = nil; } if (newMappingQueue) { dispatch_retain(newMappingQueue); _mappingQueue = newMappingQueue; } } #pragma mark - RKConfigrationDelegate - (void)configureRequest:(RKRequest *)request { [self.client configureRequest:request]; } - (void)configureObjectLoader:(RKObjectLoader *)objectLoader { objectLoader.serializationMIMEType = self.serializationMIMEType; [self configureRequest:objectLoader]; } #pragma mark - Deprecations + (RKObjectManager *)objectManagerWithBaseURLString:(NSString *)baseURLString { return [self managerWithBaseURLString:baseURLString]; } + (RKObjectManager *)objectManagerWithBaseURL:(NSURL *)baseURL { return [self managerWithBaseURL:baseURL]; } - (RKObjectLoader *)objectLoaderWithResourcePath:(NSString *)resourcePath delegate:(id<RKObjectLoaderDelegate>)delegate { RKObjectLoader* loader = [self loaderWithResourcePath:resourcePath]; loader.delegate = delegate; return loader; } - (RKObjectLoader*)objectLoaderForObject:(id<NSObject>)object method:(RKRequestMethod)method delegate:(id<RKObjectLoaderDelegate>)delegate { RKObjectLoader *loader = [self loaderForObject:object method:method]; loader.delegate = delegate; return loader; } - (void)loadObjectsAtResourcePath:(NSString *)resourcePath objectMapping:(RKObjectMapping *)objectMapping delegate:(id<RKObjectLoaderDelegate>)delegate { RKObjectLoader *loader = [self loaderWithResourcePath:resourcePath]; loader.delegate = delegate; loader.method = RKRequestMethodGET; loader.objectMapping = objectMapping; [loader send]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectManager.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMapper.h
// // RKObjectMapper.h // RestKit // // Created by Blake Watters on 5/6/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> #import "RKObjectMapping.h" #import "RKObjectMappingOperation.h" #import "RKObjectMappingResult.h" #import "RKObjectMappingProvider.h" #import "RKMappingOperationQueue.h" #import "Support.h" @class RKObjectMapper; @protocol RKObjectMapperDelegate <NSObject> @optional - (void)objectMapperWillBeginMapping:(RKObjectMapper*)objectMapper; - (void)objectMapperDidFinishMapping:(RKObjectMapper*)objectMapper; - (void)objectMapper:(RKObjectMapper*)objectMapper didAddError:(NSError*)error; - (void)objectMapper:(RKObjectMapper*)objectMapper didFindMappableObject:(id)object atKeyPath:(NSString*)keyPath withMapping:(RKObjectMappingDefinition *)mapping; - (void)objectMapper:(RKObjectMapper*)objectMapper didNotFindMappableObjectAtKeyPath:(NSString*)keyPath; - (void)objectMapper:(RKObjectMapper*)objectMapper willMapFromObject:(id)sourceObject toObject:(id)destinationObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMappingDefinition *)objectMapping; - (void)objectMapper:(RKObjectMapper*)objectMapper didMapFromObject:(id)sourceObject toObject:(id)destinationObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMappingDefinition *)objectMapping; - (void)objectMapper:(RKObjectMapper*)objectMapper didFailMappingFromObject:(id)sourceObject toObject:(id)destinationObject withError:(NSError*)error atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMappingDefinition *)objectMapping; @end /** */ @interface RKObjectMapper : NSObject { @protected RKMappingOperationQueue *operationQueue; NSMutableArray* errors; } @property (nonatomic, readonly) id sourceObject; @property (nonatomic, assign) id targetObject; @property (nonatomic, readonly) RKObjectMappingProvider* mappingProvider; @property (nonatomic, assign) RKObjectMappingProviderContext context; @property (nonatomic, assign) id<RKObjectMapperDelegate> delegate; @property (nonatomic, readonly) NSArray* errors; + (id)mapperWithObject:(id)object mappingProvider:(RKObjectMappingProvider*)mappingProvider; - (id)initWithObject:(id)object mappingProvider:(RKObjectMappingProvider*)mappingProvider; // Primary entry point for the mapper. Examines the type of object and processes it appropriately... - (RKObjectMappingResult*)performMapping; - (NSUInteger)errorCount; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMapper.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMapper.m
// // RKObjectMapper.m // RestKit // // Created by Blake Watters on 5/6/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectMapper.h" #import "RKObjectMapperError.h" #import "RKObjectMapper_Private.h" #import "RKObjectMappingProvider+Contexts.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitObjectMapping @implementation RKObjectMapper @synthesize sourceObject; @synthesize targetObject; @synthesize delegate; @synthesize mappingProvider; @synthesize errors; @synthesize context; + (id)mapperWithObject:(id)object mappingProvider:(RKObjectMappingProvider *)theMappingProvider { return [[[self alloc] initWithObject:object mappingProvider:theMappingProvider] autorelease]; } - (id)initWithObject:(id)object mappingProvider:(RKObjectMappingProvider *)theMappingProvider { self = [super init]; if (self) { sourceObject = [object retain]; mappingProvider = theMappingProvider; errors = [NSMutableArray new]; operationQueue = [RKMappingOperationQueue new]; context = RKObjectMappingProviderContextObjectsByKeyPath; } return self; } - (void)dealloc { [sourceObject release]; [errors release]; [operationQueue release]; [super dealloc]; } #pragma mark - Errors - (NSArray *)errors { return [NSArray arrayWithArray:errors]; } - (NSUInteger)errorCount { return [self.errors count]; } - (void)addError:(NSError *)error { NSAssert(error, @"Cannot add a nil error"); [errors addObject:error]; if ([self.delegate respondsToSelector:@selector(objectMapper:didAddError:)]) { [self.delegate objectMapper:self didAddError:error]; } RKLogWarning(@"Adding mapping error: %@", [error localizedDescription]); } - (void)addErrorWithCode:(RKObjectMapperErrorCode)errorCode message:(NSString *)errorMessage keyPath:(NSString *)keyPath userInfo:(NSDictionary *)otherInfo { NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: errorMessage, NSLocalizedDescriptionKey, @"RKObjectMapperKeyPath", keyPath ? keyPath : (NSString *) [NSNull null], nil]; [userInfo addEntriesFromDictionary:otherInfo]; NSError* error = [NSError errorWithDomain:RKErrorDomain code:errorCode userInfo:userInfo]; [self addError:error]; } - (void)addErrorForUnmappableKeyPath:(NSString *)keyPath { NSString *errorMessage = [NSString stringWithFormat:@"Could not find an object mapping for keyPath: '%@'", keyPath]; [self addErrorWithCode:RKObjectMapperErrorObjectMappingNotFound message:errorMessage keyPath:keyPath userInfo:nil]; } - (BOOL)isNullCollection:(id)object { // The purpose of this method is to guard against the case where we perform valueForKeyPath: on an array // and it returns NSNull for each element in the array. // We consider an empty array/dictionary mappable, but a collection that contains only NSNull // values is unmappable if ([object respondsToSelector:@selector(objectForKey:)]) { return NO; } if ([object respondsToSelector:@selector(countForObject:)] && [object count] > 0) { if ([object countForObject:[NSNull null]] == [object count]) { RKLogDebug(@"Found a collection containing only NSNull values, considering the collection unmappable..."); return YES; } } return NO; } #pragma mark - Mapping Primitives - (id)mapObject:(id)mappableObject atKeyPath:(NSString *)keyPath usingMapping:(RKObjectMappingDefinition *)mapping { NSAssert([mappableObject respondsToSelector:@selector(setValue:forKeyPath:)], @"Expected self.object to be KVC compliant"); id destinationObject = nil; if (self.targetObject) { destinationObject = self.targetObject; RKObjectMapping *objectMapping = nil; if ([mapping isKindOfClass:[RKDynamicObjectMapping class]]) { objectMapping = [(RKDynamicObjectMapping *)mapping objectMappingForDictionary:mappableObject]; } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { objectMapping = (RKObjectMapping *)mapping; } else { NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([mapping class])); } if (NO == [[self.targetObject class] isSubclassOfClass:objectMapping.objectClass]) { NSString *errorMessage = [NSString stringWithFormat: @"Expected an object mapping for class of type '%@', provider returned one for '%@'", NSStringFromClass([self.targetObject class]), NSStringFromClass(objectMapping.objectClass)]; [self addErrorWithCode:RKObjectMapperErrorObjectMappingTypeMismatch message:errorMessage keyPath:keyPath userInfo:nil]; return nil; } } else { destinationObject = [self objectWithMapping:mapping andData:mappableObject]; } if (mapping && destinationObject) { BOOL success = [self mapFromObject:mappableObject toObject:destinationObject atKeyPath:keyPath usingMapping:mapping]; if (success) { return destinationObject; } } else { // Attempted to map an object but couldn't find a mapping for the keyPath [self addErrorForUnmappableKeyPath:keyPath]; return nil; } return nil; } - (NSArray *)mapCollection:(NSArray *)mappableObjects atKeyPath:(NSString *)keyPath usingMapping:(RKObjectMappingDefinition *)mapping { NSAssert(mappableObjects != nil, @"Cannot map without an collection of mappable objects"); NSAssert(mapping != nil, @"Cannot map without a mapping to consult"); NSArray *objectsToMap = mappableObjects; if (mapping.forceCollectionMapping) { // If we have forced mapping of a dictionary, map each subdictionary if ([mappableObjects isKindOfClass:[NSDictionary class]]) { RKLogDebug(@"Collection mapping forced for NSDictionary, mapping each key/value independently..."); objectsToMap = [NSMutableArray arrayWithCapacity:[mappableObjects count]]; for (id key in mappableObjects) { NSDictionary *dictionaryToMap = [NSDictionary dictionaryWithObject:[mappableObjects valueForKey:key] forKey:key]; [(NSMutableArray *)objectsToMap addObject:dictionaryToMap]; } } else { RKLogWarning(@"Collection mapping forced but mappable objects is of type '%@' rather than NSDictionary", NSStringFromClass([mappableObjects class])); } } // Ensure we are mapping onto a mutable collection if there is a target NSMutableArray *mappedObjects = self.targetObject ? self.targetObject : [NSMutableArray arrayWithCapacity:[mappableObjects count]]; if (NO == [mappedObjects respondsToSelector:@selector(addObject:)]) { NSString *errorMessage = [NSString stringWithFormat: @"Cannot map a collection of objects onto a non-mutable collection. Unexpected destination object type '%@'", NSStringFromClass([mappedObjects class])]; [self addErrorWithCode:RKObjectMapperErrorObjectMappingTypeMismatch message:errorMessage keyPath:keyPath userInfo:nil]; return nil; } for (id mappableObject in objectsToMap) { id destinationObject = [self objectWithMapping:mapping andData:mappableObject]; if (! destinationObject) { continue; } BOOL success = [self mapFromObject:mappableObject toObject:destinationObject atKeyPath:keyPath usingMapping:mapping]; if (success) { [mappedObjects addObject:destinationObject]; } } return mappedObjects; } // The workhorse of this entire process. Emits object loading operations - (BOOL)mapFromObject:(id)mappableObject toObject:(id)destinationObject atKeyPath:(NSString *)keyPath usingMapping:(RKObjectMappingDefinition *)mapping { NSAssert(destinationObject != nil, @"Cannot map without a target object to assign the results to"); NSAssert(mappableObject != nil, @"Cannot map without a collection of attributes"); NSAssert(mapping != nil, @"Cannot map without an mapping"); RKLogDebug(@"Asked to map source object %@ with mapping %@", mappableObject, mapping); if ([self.delegate respondsToSelector:@selector(objectMapper:willMapFromObject:toObject:atKeyPath:usingMapping:)]) { [self.delegate objectMapper:self willMapFromObject:mappableObject toObject:destinationObject atKeyPath:keyPath usingMapping:mapping]; } NSError *error = nil; RKObjectMappingOperation *operation = [RKObjectMappingOperation mappingOperationFromObject:mappableObject toObject:destinationObject withMapping:mapping]; operation.queue = operationQueue; BOOL success = [operation performMapping:&error]; if (success) { if ([self.delegate respondsToSelector:@selector(objectMapper:didMapFromObject:toObject:atKeyPath:usingMapping:)]) { [self.delegate objectMapper:self didMapFromObject:mappableObject toObject:destinationObject atKeyPath:keyPath usingMapping:mapping]; } } else if (error) { if ([self.delegate respondsToSelector:@selector(objectMapper:didFailMappingFromObject:toObject:withError:atKeyPath:usingMapping:)]) { [self.delegate objectMapper:self didFailMappingFromObject:mappableObject toObject:destinationObject withError:error atKeyPath:keyPath usingMapping:mapping]; } [self addError:error]; } return success; } - (id)objectWithMapping:(RKObjectMappingDefinition *)mapping andData:(id)mappableData { NSAssert([mapping isKindOfClass:[RKObjectMappingDefinition class]], @"Expected an RKObjectMappingDefinition object"); RKObjectMapping *objectMapping = nil; if ([mapping isKindOfClass:[RKDynamicObjectMapping class]]) { objectMapping = [(RKDynamicObjectMapping *)mapping objectMappingForDictionary:mappableData]; if (! objectMapping) { RKLogDebug(@"Mapping %@ declined mapping for data %@: returned nil objectMapping", mapping, mappableData); } } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { objectMapping = (RKObjectMapping *)mapping; } else { NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([mapping class])); } if (objectMapping) { return [objectMapping mappableObjectForData:mappableData]; } return nil; } - (id)performMappingForObject:(id)mappableValue atKeyPath:(NSString *)keyPath usingMapping:(RKObjectMappingDefinition *)mapping { id mappingResult; if (mapping.forceCollectionMapping || [mappableValue isKindOfClass:[NSArray class]] || [mappableValue isKindOfClass:[NSSet class]]) { RKLogDebug(@"Found mappable collection at keyPath '%@': %@", keyPath, mappableValue); mappingResult = [self mapCollection:mappableValue atKeyPath:keyPath usingMapping:mapping]; } else { RKLogDebug(@"Found mappable data at keyPath '%@': %@", keyPath, mappableValue); mappingResult = [self mapObject:mappableValue atKeyPath:keyPath usingMapping:mapping]; } return mappingResult; } - (NSMutableDictionary *)performKeyPathMappingUsingMappingDictionary:(NSDictionary *)mappingsByKeyPath { BOOL foundMappable = NO; NSMutableDictionary *results = [NSMutableDictionary dictionary]; for (NSString *keyPath in mappingsByKeyPath) { id mappingResult = nil; id mappableValue = nil; RKLogTrace(@"Examining keyPath '%@' for mappable content...", keyPath); if ([keyPath isEqualToString:@""]) { mappableValue = self.sourceObject; } else { mappableValue = [self.sourceObject valueForKeyPath:keyPath]; } // Not found... if (mappableValue == nil || mappableValue == [NSNull null] || [self isNullCollection:mappableValue]) { RKLogDebug(@"Found unmappable value at keyPath: %@", keyPath); if ([self.delegate respondsToSelector:@selector(objectMapper:didNotFindMappableObjectAtKeyPath:)]) { [self.delegate objectMapper:self didNotFindMappableObjectAtKeyPath:keyPath]; } continue; } // Found something to map foundMappable = YES; RKObjectMappingDefinition * mapping = [mappingsByKeyPath objectForKey:keyPath]; if ([self.delegate respondsToSelector:@selector(objectMapper:didFindMappableObject:atKeyPath:withMapping:)]) { [self.delegate objectMapper:self didFindMappableObject:mappableValue atKeyPath:keyPath withMapping:mapping]; } mappingResult = [self performMappingForObject:mappableValue atKeyPath:keyPath usingMapping:mapping]; if (mappingResult) { [results setObject:mappingResult forKey:keyPath]; } } if (NO == foundMappable) return nil; return results; } // Primary entry point for the mapper. - (RKObjectMappingResult *)performMapping { NSAssert(self.sourceObject != nil, @"Cannot perform object mapping without a source object to map from"); NSAssert(self.mappingProvider != nil, @"Cannot perform object mapping without an object mapping provider"); RKLogDebug(@"Performing object mapping sourceObject: %@\n and targetObject: %@", self.sourceObject, self.targetObject); if ([self.delegate respondsToSelector:@selector(objectMapperWillBeginMapping:)]) { [self.delegate objectMapperWillBeginMapping:self]; } // Perform the mapping BOOL foundMappable = NO; NSMutableDictionary *results = nil; // Handle mapping selection for context id mappingsForContext = [self.mappingProvider valueForContext:context]; if ([mappingsForContext isKindOfClass:[NSDictionary class]]) { results = [self performKeyPathMappingUsingMappingDictionary:mappingsForContext]; foundMappable = (results != nil); } else if ([mappingsForContext isKindOfClass:[RKObjectMappingDefinition class]]) { id mappableData = self.sourceObject; if ([mappingsForContext rootKeyPath] != nil) { NSString* rootKeyPath = [mappingsForContext rootKeyPath]; mappableData = [self.sourceObject valueForKeyPath:rootKeyPath]; RKLogDebug(@"Selected object mapping has rootKeyPath. Apply valueForKeyPath to mappable data: %@", rootKeyPath); } if (mappableData) { id mappingResult = [self performMappingForObject:mappableData atKeyPath:@"" usingMapping:mappingsForContext]; foundMappable = YES; results = [NSDictionary dictionaryWithObject:mappingResult forKey:@""]; } } // Allow any queued operations to complete RKLogDebug(@"The following operations are in the queue: %@", operationQueue.operations); [operationQueue waitUntilAllOperationsAreFinished]; if ([self.delegate respondsToSelector:@selector(objectMapperDidFinishMapping:)]) { [self.delegate objectMapperDidFinishMapping:self]; } // If we found nothing eligible for mapping in the content, add an unmappable key path error and fail mapping // If the content is empty, we don't consider it an error BOOL isEmpty = [self.sourceObject respondsToSelector:@selector(count)] && ([self.sourceObject count] == 0); if (foundMappable == NO && !isEmpty) { [self addErrorForUnmappableKeyPath:@""]; return nil; } RKLogDebug(@"Finished performing object mapping. Results: %@", results); return [RKObjectMappingResult mappingResultWithDictionary:results]; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMapper.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMapper_Private.h
// // RKObjectMapper_Private.h // RestKit // // Created by Blake Watters on 5/9/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // @interface RKObjectMapper (Private) - (id)mapObject:(id)mappableObject atKeyPath:(NSString *)keyPath usingMapping:(RKObjectMappingDefinition *)mapping; - (NSArray*)mapCollection:(NSArray*)mappableObjects atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMappingDefinition *)mapping; - (BOOL)mapFromObject:(id)mappableObject toObject:(id)destinationObject atKeyPath:(NSString *)keyPath usingMapping:(RKObjectMappingDefinition *)mapping; - (id)objectWithMapping:(RKObjectMappingDefinition *)objectMapping andData:(id)mappableData; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMapper_Private.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMapperError.h
// // RKObjectMapperError.h // RestKit // // Created by Blake Watters on 5/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKErrors.h" typedef enum { RKObjectMapperErrorObjectMappingNotFound = 1001, // No mapping found RKObjectMapperErrorObjectMappingTypeMismatch = 1002, // Target class and object mapping are in disagreement RKObjectMapperErrorUnmappableContent = 1003, // No mappable attributes or relationships were found RKObjectMapperErrorFromMappingResult = 1004, // The error was returned from the mapping result RKObjectMapperErrorValidationFailure = 1005 // Generic error code for use when constructing validation errors } RKObjectMapperErrorCode;
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMapperError.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMapping.h
// // RKObjectMapping.h // RestKit // // Created by Blake Watters on 4/30/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <Foundation/Foundation.h> #import "RKObjectMappingDefinition.h" #import "RKObjectAttributeMapping.h" #import "RKObjectRelationshipMapping.h" /** An object mapping defines the rules for transforming a key-value coding compliant object into another representation. The mapping is defined in terms of a source object class and a collection of rules defining how keyPaths should be transformed into target attributes and relationships. There are two types of transformations possible: 1. keyPath to attribute. Defines that the value found at the keyPath should be transformed and assigned to the property specified by the attribute. The transformation to be performed is determined by inspecting the type of the target property at runtime. 1. keyPath to relationship. Defines that the value found at the keyPath should be transformed into another object instance and assigned to the property specified by the relationship. Relationships are processed using an object mapping as well. Through the use of relationship mappings, an arbitrarily complex object graph can be mapped for you. Instances of RKObjectMapping are used to configure RKObjectMappingOperation instances, which actually perform the mapping work. Both object loading and serialization are defined in terms of object mappings. */ @interface RKObjectMapping : RKObjectMappingDefinition <NSCopying> { Class _objectClass; NSMutableArray* _mappings; NSString* _rootKeyPath; BOOL _setDefaultValueForMissingAttributes; BOOL _setNilForMissingRelationships; BOOL _performKeyValueValidation; NSArray *_dateFormatters; NSFormatter *_preferredDateFormatter; } /** The target class this object mapping is defining rules for */ @property (nonatomic, assign) Class objectClass; /** The name of the target class the receiver defines a mapping for. @see objectClass */ @property (nonatomic, copy) NSString *objectClassName; /** The aggregate collection of attribute and relationship mappings within this object mapping */ @property (nonatomic, readonly) NSArray *mappings; /** The collection of attribute mappings within this object mapping */ @property (nonatomic, readonly) NSArray *attributeMappings; /** The collection of relationship mappings within this object mapping */ @property (nonatomic, readonly) NSArray *relationshipMappings; /** The collection of mappable keyPaths that are defined within this object mapping. These keyPaths refer to keys within the source object being mapped (i.e. the parsed JSON payload). */ @property (nonatomic, readonly) NSArray *mappedKeyPaths; /** When YES, any attributes that have mappings defined but are not present within the source object will be set to nil, clearing any existing value. */ @property (nonatomic, assign, getter = shouldSetDefaultValueForMissingAttributes) BOOL setDefaultValueForMissingAttributes; /** When YES, any relationships that have mappings defined but are not present within the source object will be set to nil, clearing any existing value. */ @property (nonatomic, assign) BOOL setNilForMissingRelationships; /** When YES, RestKit will invoke key-value validation at object mapping time. **Default**: YES @see validateValue:forKey:error: */ @property (nonatomic, assign) BOOL performKeyValueValidation; /** When YES, RestKit will check that the object being mapped is key-value coding compliant for the mapped key. If it is not, the attribute/relationship mapping will be ignored and mapping will continue. When NO, unknown keyPath mappings will generate NSUnknownKeyException errors for the unknown keyPath. Defaults to NO to help the developer catch incorrect mapping configurations during development. **Default**: NO */ @property (nonatomic, assign) BOOL ignoreUnknownKeyPaths; /** An array of NSDateFormatter objects to use when mapping string values into NSDate attributes on the target objectClass. Each date formatter will be invoked with the string value being mapped until one of the date formatters does not return nil. Defaults to the application-wide collection of date formatters configured via: [RKObjectMapping setDefaultDateFormatters:] @see [RKObjectMapping defaultDateFormatters] */ @property (nonatomic, retain) NSArray *dateFormatters; /** The NSFormatter object for your application's preferred date and time configuration. This date formatter will be used when generating string representations of NSDate attributes (i.e. during serialization to URL form encoded or JSON format). Defaults to the application-wide preferred date formatter configured via: [RKObjectMapping setPreferredDateFormatter:] @see [RKObjectMapping preferredDateFormatter] */ @property (nonatomic, retain) NSFormatter *preferredDateFormatter; #pragma mark - Mapping Instantiation /** Returns an object mapping for the specified class that is ready for configuration */ + (id)mappingForClass:(Class)objectClass; /** Creates and returns an object mapping for the class with the given name @param objectClassName The name of the class the mapping is for. @return A new object mapping with for the class with given name. */ + (id)mappingForClassWithName:(NSString *)objectClassName; /** Returns an object mapping useful for configuring a serialization mapping. The object class is configured as NSMutableDictionary */ + (id)serializationMapping; #if NS_BLOCKS_AVAILABLE /** Returns an object mapping targeting the specified class. The RKObjectMapping instance will be yieled to the block so that you can perform on the fly configuration without having to obtain a reference variable for the mapping. For example, consider we have a one-off request that will load a few attributes for our object. Using blocks, this is very succinct: [[RKObjectManager sharedManager] postObject:self usingBlock:^(RKObjectLoader* loader) { loader.objectMapping = [RKObjectMapping mappingForClass:[Person class] usingBlock:^(RKObjectMapping* mapping) { [mapping mapAttributes:@"email", @"first_name", nil]; }]; }]; */ + (id)mappingForClass:(Class)objectClass usingBlock:(void (^)(RKObjectMapping *mapping))block; /** Returns serialization mapping for encoding a local object to a dictionary for transport. The RKObjectMapping instance will be yieled to the block so that you can perform on the fly configuration without having to obtain a reference variable for the mapping. For example, consider we have a one-off request within which we want to post a subset of our object data. Using blocks, this is very succinct: - (BOOL)changePassword:(NSString*)newPassword error:(NSError**)error { if ([self validatePassword:newPassword error:error]) { self.password = newPassword; [[RKObjectManager sharedManager] putObject:self delegate:self block:^(RKObjectLoader* loader) { loader.serializationMapping = [RKObjectMapping serializationMappingUsingBlock:^(RKObjectMapping* mapping) { [mapping mapAttributes:@"password", nil]; }]; }]; } } Using the block forms we are able to quickly configure and send this request on the fly. */ + (id)serializationMappingUsingBlock:(void (^)(RKObjectMapping *serializationMapping))block; #endif /** Add a configured attribute mapping to this object mapping @see RKObjectAttributeMapping */ - (void)addAttributeMapping:(RKObjectAttributeMapping*)mapping; /** Add a configured attribute mapping to this object mapping @see RKObjectRelationshipMapping */ - (void)addRelationshipMapping:(RKObjectRelationshipMapping*)mapping; #pragma mark - Retrieving Mappings /** Returns the attribute or relationship mapping for the given source keyPath. @param sourceKeyPath A keyPath within the mappable source object that is mapped to an attribute or relationship in this object mapping. */ - (id)mappingForKeyPath:(NSString*)sourceKeyPath; /** Returns the attribute or relationship mapping for the given source keyPath. @param sourceKeyPath A keyPath within the mappable source object that is mapped to an attribute or relationship in this object mapping. */ - (id)mappingForSourceKeyPath:(NSString*)sourceKeyPath; /** Returns the attribute or relationship mapping for the given destination keyPath. @param destinationKeyPath A keyPath on the destination object that is currently */ - (id)mappingForDestinationKeyPath:(NSString *)destinationKeyPath; /** Returns the attribute mapping targeting the specified attribute on the destination object @param attributeKey The name of the attribute we want to retrieve the mapping for */ - (RKObjectAttributeMapping *)mappingForAttribute:(NSString *)attributeKey; /** Returns the relationship mapping targeting the specified relationship on the destination object @param relationshipKey The name of the relationship we want to retrieve the mapping for */ - (RKObjectRelationshipMapping*)mappingForRelationship:(NSString*)relationshipKey; #pragma mark - Attribute & Relationship Mapping /** Define an attribute mapping for one or more keyPaths where the source keyPath and destination attribute property have the same name. For example, given the transformation from a JSON dictionary: {"name": "My Name", "age": 28} To a Person class with corresponding name & age properties, we could configure the attribute mappings via: [mapping mapAttributes:@"name", @"age", nil]; @param attributeKey A key-value coding key corresponding to a value in the mappable source object and an attribute on the destination class that have the same name. */ - (void)mapAttributes:(NSString *)attributeKey, ... NS_REQUIRES_NIL_TERMINATION; /** Defines an attribute mapping for each string attribute in the collection where the source keyPath and the destination attribute property have the same name. For example, given the transformation from a JSON dictionary: {"name": "My Name", "age": 28} To a Person class with corresponding name & age properties, we could configure the attribute mappings via: [mapping mapAttributesFromSet:[NSSet setWithObjects:@"name", @"age", nil]]; @param set A set of string attribute keyPaths to deifne mappings for */ - (void)mapAttributesFromSet:(NSSet *)set; /** Defines an attribute mapping for each string attribute in the collection where the source keyPath and the destination attribute property have the same name. For example, given the transformation from a JSON dictionary: {"name": "My Name", "age": 28} To a Person class with corresponding name & age properties, we could configure the attribute mappings via: [mapping mapAttributesFromSet:[NSArray arrayWithObjects:@"name", @"age", nil]]; @param array An array of string attribute keyPaths to deifne mappings for */ - (void)mapAttributesFromArray:(NSArray *)set; /** Defines a relationship mapping for a key where the source keyPath and the destination relationship property have the same name. For example, given the transformation from a JSON dictionary: {"name": "My Name", "age": 28, "cat": { "name": "Asia" } } To a Person class with corresponding 'cat' relationship property, we could configure the mappings via: RKObjectMapping* catMapping = [RKObjectMapping mappingForClass:[Cat class]]; [personMapping mapRelationship:@"cat" withObjectMapping:catMapping]; @param relationshipKey A key-value coding key corresponding to a value in the mappable source object and a property on the destination class that have the same name. @param objectOrDynamicMapping An RKObjectMapping or RKObjectDynamic mapping to apply when mapping the relationship */ - (void)mapRelationship:(NSString*)relationshipKey withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping; /** Syntactic sugar to improve readability when defining a relationship mapping. Implies that the mapping targets a one-to-many relationship nested within the source data. @see mapRelationship:withObjectMapping: */ - (void)hasMany:(NSString*)keyPath withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping; /** Syntactic sugar to improve readability when defining a relationship mapping. Implies that the mapping targets a one-to-one relationship nested within the source data. @see mapRelationship:withObjectMapping: */ - (void)hasOne:(NSString*)keyPath withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping; /** Instantiate and add an RKObjectAttributeMapping instance targeting a keyPath within the mappable source data to an attribute on the target object. Used to quickly define mappings where the source value is deeply nested in the mappable data or the source and destination do not have corresponding names. Examples: // We want to transform the name to something Cocoa-esque [mapping mapKeyPath:@"created_at" toAttribute:@"createdAt"]; // We want to extract nested data and map it to a property [mapping mapKeyPath:@"results.metadata.generated_on" toAttribute:@"generationTimestamp"]; @param sourceKeyPath A key-value coding keyPath to fetch the mappable value from @param destinationAttribute The attribute name to assign the mapped value to @see RKObjectAttributeMapping */ - (void)mapKeyPath:(NSString*)sourceKeyPath toAttribute:(NSString*)destinationAttribute; /** Instantiate and add an RKObjectRelationshipMapping instance targeting a keyPath within the mappable source data to a relationship property on the target object. Used to quickly define mappings where the source value is deeply nested in the mappable data or the source and destination do not have corresponding names. Examples: // We want to transform the name to something Cocoa-esque [mapping mapKeyPath:@"best_friend" toRelationship:@"bestFriend" withObjectMapping:friendMapping]; // We want to extract nested data and map it to a property [mapping mapKeyPath:@"best_friend.favorite_cat" toRelationship:@"bestFriendsFavoriteCat" withObjectMapping:catMapping]; @param sourceKeyPath A key-value coding keyPath to fetch the mappable value from @param destinationRelationship The relationship name to assign the mapped value to @param objectMapping An object mapping to use when processing the nested objects @see RKObjectRelationshipMapping */ - (void)mapKeyPath:(NSString *)sourceKeyPath toRelationship:(NSString*)destinationRelationship withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping; /** Instantiate and add an RKObjectRelationshipMapping instance targeting a keyPath within the mappable source data to a relationship property on the target object. Used to indicate whether the relationship should be included in serialization. @param sourceKeyPath A key-value coding keyPath to fetch the mappable value from @param destinationRelationship The relationship name to assign the mapped value to @param objectMapping An object mapping to use when processing the nested objects @param serialize A boolean value indicating whether to include this relationship in serialization @see mapKeyPath:toRelationship:withObjectMapping: */ - (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping serialize:(BOOL)serialize; /** Quickly define a group of attribute mappings using alternating keyPath and attribute names. You must provide an equal number of keyPath and attribute pairs or an exception will be generated. For example: [personMapping mapKeyPathsToAttributes:@"name", @"name", @"createdAt", @"createdAt", @"street_address", @"streetAddress", nil]; @param sourceKeyPath A key-value coding key path to fetch a mappable value from @param ... A nil-terminated sequence of strings alternating between source key paths and destination attributes */ - (void)mapKeyPathsToAttributes:(NSString*)sourceKeyPath, ... NS_REQUIRES_NIL_TERMINATION; /** Configures a sub-key mapping for cases where JSON has been nested underneath a key named after an attribute. For example, consider the following JSON: { "users": { "blake": { "id": 1234, "email": "[email protected]" }, "rachit": { "id": 5678", "email": "[email protected]" } } } We can configure our mappings to handle this in the following form: RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[User class]]; mapping.forceCollectionMapping = YES; // RestKit cannot infer this is a collection, so we force it [mapping mapKeyOfNestedDictionaryToAttribute:@"firstName"]; [mapping mapFromKeyPath:@"(firstName).id" toAttribute:"userID"]; [mapping mapFromKeyPath:@"(firstName).email" toAttribute:"email"]; [[RKObjectManager sharedManager].mappingProvider setObjectMapping:mapping forKeyPath:@"users"]; */ - (void)mapKeyOfNestedDictionaryToAttribute:(NSString *)attributeName; /** Returns the attribute mapping targeting the key of a nested dictionary in the source JSON. This attribute mapping corresponds to the attributeName configured via mapKeyOfNestedDictionaryToAttribute: @see mapKeyOfNestedDictionaryToAttribute: @returns An attribute mapping for the key of a nested dictionary being mapped or nil */ - (RKObjectAttributeMapping *)attributeMappingForKeyOfNestedDictionary; /** Removes all currently configured attribute and relationship mappings from the object mapping */ - (void)removeAllMappings; /** Removes an instance of an attribute or relationship mapping from the object mapping @param attributeOrRelationshipMapping The attribute or relationship mapping to remove */ - (void)removeMapping:(RKObjectAttributeMapping*)attributeOrRelationshipMapping; /** Remove the attribute or relationship mapping for the specified source keyPath @param sourceKeyPath A key-value coding key path to remove the mappings for */ - (void)removeMappingForKeyPath:(NSString*)sourceKeyPath; #pragma mark - Inverse Mappings /** Generates an inverse mapping for the rules specified within this object mapping. This can be used to quickly generate a corresponding serialization mapping from a configured object mapping. The inverse mapping will have the source and destination keyPaths swapped for all attribute and relationship mappings. */ - (RKObjectMapping*)inverseMapping; /** Returns the default value to be assigned to the specified attribute when it is missing from a mappable payload. The default implementation returns nil for transient object mappings. On managed object mappings, the default value returned from the Entity definition will be used. @see [RKManagedObjectMapping defaultValueForMissingAttribute:] */ - (id)defaultValueForMissingAttribute:(NSString*)attributeName; /** Returns an auto-released object that can be used to apply this object mapping given a set of mappable data. For transient objects, this generally returns an instance of the objectClass. For Core Data backed persistent objects, mappableData will be inspected to search for primary key data to lookup existing object instances. */ /*- (id)mappableObjectForData:(id)mappableData;*/ /** Returns the class of the attribute or relationship property of the target objectClass Given the name of a string property, this will return an NSString, etc. @param propertyName The name of the property we would like to retrieve the type of */ - (Class)classForProperty:(NSString*)propertyName; /** Returns an auto-released object that can be used to apply this object mapping given a set of mappable data. For transient objects, this generally returns an instance of the objectClass. For Core Data backed persistent objects, mappableData will be inspected to search for primary key data to lookup existing object instances. */ - (id)mappableObjectForData:(id)mappableData; // Deprecations + (id)mappingForClass:(Class)objectClass withBlock:(void (^)(RKObjectMapping*))block DEPRECATED_ATTRIBUTE; + (id)mappingForClass:(Class)objectClass block:(void (^)(RKObjectMapping*))block DEPRECATED_ATTRIBUTE; + (id)serializationMappingWithBlock:(void (^)(RKObjectMapping*))block DEPRECATED_ATTRIBUTE; @end ///////////////////////////////////////////////////////////////////////////// /** Defines the inteface for configuring time and date formatting handling within RestKit object mappings. For performance reasons, RestKit reuses a pool of date formatters rather than constructing them at mapping time. This collection of date formatters can be configured on a per-object mapping or application-wide basis using the static methods exposed in this category. */ @interface RKObjectMapping (DateAndTimeFormatting) /** Returns the collection of default date formatters that will be used for all object mappings that have not been configured specifically. Out of the box, RestKit initializes the following default date formatters for you in the UTC time zone: * yyyy-MM-dd'T'HH:mm:ss'Z' * MM/dd/yyyy @return An array of NSFormatter objects used when mapping strings into NSDate attributes */ + (NSArray *)defaultDateFormatters; /** Sets the collection of default date formatters to the specified array. The array should contain configured instances of NSDateFormatter in the order in which you want them applied during object mapping operations. @param dateFormatters An array of date formatters to replace the existing defaults @see defaultDateFormatters */ + (void)setDefaultDateFormatters:(NSArray *)dateFormatters; /** Adds a date formatter instance to the default collection @param dateFormatter An NSFormatter object to append to the end of the default formatters collection @see defaultDateFormatters */ + (void)addDefaultDateFormatter:(NSFormatter *)dateFormatter; /** Convenience method for quickly constructing a date formatter and adding it to the collection of default date formatters. The locale is auto-configured to en_US_POSIX @param dateFormatString The dateFormat string to assign to the newly constructed NSDateFormatter instance @param nilOrTimeZone The NSTimeZone object to configure on the NSDateFormatter instance. Defaults to UTC time. @result A new NSDateFormatter will be appended to the defaultDateFormatters with the specified date format and time zone @see NSDateFormatter */ + (void)addDefaultDateFormatterForString:(NSString *)dateFormatString inTimeZone:(NSTimeZone *)nilOrTimeZone; /** Returns the preferred date formatter to use when generating NSString representations from NSDate attributes. This type of transformation occurs when RestKit is mapping local objects into JSON or form encoded serializations that do not have a native time construct. Defaults to a date formatter configured for the UTC Time Zone with a format string of "yyyy-MM-dd HH:mm:ss Z" @return The preferred NSFormatter object to use when serializing dates into strings */ + (NSFormatter *)preferredDateFormatter; /** Sets the preferred date formatter to use when generating NSString representations from NSDate attributes. This type of transformation occurs when RestKit is mapping local objects into JSON or form encoded serializations that do not have a native time construct. @param dateFormatter The NSFormatter object to designate as the new preferred instance */ + (void)setPreferredDateFormatter:(NSFormatter *)dateFormatter; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMapping.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMapping.m
// // RKObjectMapping.m // RestKit // // Created by Blake Watters on 4/30/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectMapping.h" #import "RKObjectRelationshipMapping.h" #import "RKObjectPropertyInspector.h" #import "RKLog.h" #import "RKISO8601DateFormatter.h" // Constants NSString* const RKObjectMappingNestingAttributeKeyName = @"<RK_NESTING_ATTRIBUTE>"; @implementation RKObjectMapping @synthesize objectClass = _objectClass; @synthesize mappings = _mappings; @synthesize dateFormatters = _dateFormatters; @synthesize preferredDateFormatter = _preferredDateFormatter; @synthesize rootKeyPath = _rootKeyPath; @synthesize setDefaultValueForMissingAttributes = _setDefaultValueForMissingAttributes; @synthesize setNilForMissingRelationships = _setNilForMissingRelationships; @synthesize performKeyValueValidation = _performKeyValueValidation; @synthesize ignoreUnknownKeyPaths = _ignoreUnknownKeyPaths; + (id)mappingForClass:(Class)objectClass { RKObjectMapping* mapping = [self new]; mapping.objectClass = objectClass; return [mapping autorelease]; } + (id)mappingForClassWithName:(NSString *)objectClassName { return [self mappingForClass:NSClassFromString(objectClassName)]; } + (id)serializationMapping { return [self mappingForClass:[NSMutableDictionary class]]; } #if NS_BLOCKS_AVAILABLE + (id)mappingForClass:(Class)objectClass usingBlock:(void (^)(RKObjectMapping*))block { RKObjectMapping* mapping = [self mappingForClass:objectClass]; block(mapping); return mapping; } + (id)serializationMappingUsingBlock:(void (^)(RKObjectMapping*))block { RKObjectMapping* mapping = [self serializationMapping]; block(mapping); return mapping; } // Deprecated... Move to category or bottom... + (id)mappingForClass:(Class)objectClass withBlock:(void (^)(RKObjectMapping*))block { return [self mappingForClass:objectClass usingBlock:block]; } + (id)mappingForClass:(Class)objectClass block:(void (^)(RKObjectMapping*))block { return [self mappingForClass:objectClass usingBlock:block]; } + (id)serializationMappingWithBlock:(void (^)(RKObjectMapping*))block { RKObjectMapping* mapping = [self serializationMapping]; block(mapping); return mapping; } #endif // NS_BLOCKS_AVAILABLE - (id)init { self = [super init]; if (self) { _mappings = [NSMutableArray new]; self.setDefaultValueForMissingAttributes = NO; self.setNilForMissingRelationships = NO; self.forceCollectionMapping = NO; self.performKeyValueValidation = YES; self.ignoreUnknownKeyPaths = NO; } return self; } - (id)copyWithZone:(NSZone *)zone { RKObjectMapping *copy = [[[self class] allocWithZone:zone] init]; copy.objectClass = self.objectClass; copy.rootKeyPath = self.rootKeyPath; copy.setDefaultValueForMissingAttributes = self.setDefaultValueForMissingAttributes; copy.setNilForMissingRelationships = self.setNilForMissingRelationships; copy.forceCollectionMapping = self.forceCollectionMapping; copy.performKeyValueValidation = self.performKeyValueValidation; copy.dateFormatters = self.dateFormatters; copy.preferredDateFormatter = self.preferredDateFormatter; for (RKObjectAttributeMapping *mapping in self.mappings) { [copy addAttributeMapping:mapping]; } return copy; } - (void)dealloc { [_rootKeyPath release]; [_mappings release]; [_dateFormatters release]; [_preferredDateFormatter release]; [super dealloc]; } - (NSString *)objectClassName { return NSStringFromClass(self.objectClass); } - (void)setObjectClassName:(NSString *)objectClassName { self.objectClass = NSClassFromString(objectClassName); } - (NSArray *)mappedKeyPaths { return [_mappings valueForKey:@"destinationKeyPath"]; } - (NSArray *)attributeMappings { NSMutableArray* mappings = [NSMutableArray array]; for (RKObjectAttributeMapping* mapping in self.mappings) { if ([mapping isMemberOfClass:[RKObjectAttributeMapping class]]) { [mappings addObject:mapping]; } } return mappings; } - (NSArray *)relationshipMappings { NSMutableArray* mappings = [NSMutableArray array]; for (RKObjectAttributeMapping* mapping in self.mappings) { if ([mapping isMemberOfClass:[RKObjectRelationshipMapping class]]) { [mappings addObject:mapping]; } } return mappings; } - (void)addAttributeMapping:(RKObjectAttributeMapping*)mapping { NSAssert1([[self mappedKeyPaths] containsObject:mapping.destinationKeyPath] == NO, @"Unable to add mapping for keyPath %@, one already exists...", mapping.destinationKeyPath); [_mappings addObject:mapping]; } - (void)addRelationshipMapping:(RKObjectRelationshipMapping*)mapping { [self addAttributeMapping:mapping]; } - (NSString *)description { return [NSString stringWithFormat:@"<%@:%p objectClass=%@ keyPath mappings => %@>", NSStringFromClass([self class]), self, NSStringFromClass(self.objectClass), _mappings]; } - (id)mappingForKeyPath:(NSString *)keyPath { return [self mappingForSourceKeyPath:keyPath]; } - (id)mappingForSourceKeyPath:(NSString *)sourceKeyPath { for (RKObjectAttributeMapping* mapping in _mappings) { if ([mapping.sourceKeyPath isEqualToString:sourceKeyPath]) { return mapping; } } return nil; } - (id)mappingForDestinationKeyPath:(NSString *)destinationKeyPath { for (RKObjectAttributeMapping* mapping in _mappings) { if ([mapping.destinationKeyPath isEqualToString:destinationKeyPath]) { return mapping; } } return nil; } - (void)mapAttributesCollection:(id<NSFastEnumeration>)attributes { for (NSString* attributeKeyPath in attributes) { [self addAttributeMapping:[RKObjectAttributeMapping mappingFromKeyPath:attributeKeyPath toKeyPath:attributeKeyPath]]; } } - (void)mapAttributes:(NSString*)attributeKeyPath, ... { va_list args; va_start(args, attributeKeyPath); NSMutableSet* attributeKeyPaths = [NSMutableSet set]; for (NSString* keyPath = attributeKeyPath; keyPath != nil; keyPath = va_arg(args, NSString*)) { [attributeKeyPaths addObject:keyPath]; } va_end(args); [self mapAttributesCollection:attributeKeyPaths]; } - (void)mapAttributesFromSet:(NSSet *)set { [self mapAttributesCollection:set]; } - (void)mapAttributesFromArray:(NSArray *)array { [self mapAttributesCollection:[NSSet setWithArray:array]]; } - (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping serialize:(BOOL)serialize { RKObjectRelationshipMapping* mapping = [RKObjectRelationshipMapping mappingFromKeyPath:relationshipKeyPath toKeyPath:keyPath withMapping:objectOrDynamicMapping reversible:serialize]; [self addRelationshipMapping:mapping]; } - (void)mapKeyPath:(NSString *)relationshipKeyPath toRelationship:(NSString*)keyPath withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping { [self mapKeyPath:relationshipKeyPath toRelationship:keyPath withMapping:objectOrDynamicMapping serialize:YES]; } - (void)mapRelationship:(NSString*)relationshipKeyPath withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping { [self mapKeyPath:relationshipKeyPath toRelationship:relationshipKeyPath withMapping:objectOrDynamicMapping]; } - (void)mapKeyPath:(NSString*)sourceKeyPath toAttribute:(NSString*)destinationKeyPath { RKObjectAttributeMapping* mapping = [RKObjectAttributeMapping mappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath]; [self addAttributeMapping:mapping]; } - (void)hasMany:(NSString*)keyPath withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping { [self mapRelationship:keyPath withMapping:objectOrDynamicMapping]; } - (void)hasOne:(NSString*)keyPath withMapping:(RKObjectMappingDefinition *)objectOrDynamicMapping { [self mapRelationship:keyPath withMapping:objectOrDynamicMapping]; } - (void)removeAllMappings { [_mappings removeAllObjects]; } - (void)removeMapping:(RKObjectAttributeMapping*)attributeOrRelationshipMapping { [_mappings removeObject:attributeOrRelationshipMapping]; } - (void)removeMappingForKeyPath:(NSString*)keyPath { RKObjectAttributeMapping* mapping = [self mappingForKeyPath:keyPath]; [self removeMapping:mapping]; } #ifndef MAX_INVERSE_MAPPING_RECURSION_DEPTH #define MAX_INVERSE_MAPPING_RECURSION_DEPTH (100) #endif - (RKObjectMapping*)inverseMappingAtDepth:(NSInteger)depth { NSAssert(depth < MAX_INVERSE_MAPPING_RECURSION_DEPTH, @"Exceeded max recursion level in inverseMapping. This is likely due to a loop in the serialization graph. To break this loop, specify one-way relationships by setting serialize to NO in mapKeyPath:toRelationship:withObjectMapping:serialize:"); RKObjectMapping* inverseMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; for (RKObjectAttributeMapping* attributeMapping in self.attributeMappings) { [inverseMapping mapKeyPath:attributeMapping.destinationKeyPath toAttribute:attributeMapping.sourceKeyPath]; } for (RKObjectRelationshipMapping* relationshipMapping in self.relationshipMappings) { if (relationshipMapping.reversible) { RKObjectMappingDefinition * mapping = relationshipMapping.mapping; if (! [mapping isKindOfClass:[RKObjectMapping class]]) { RKLogWarning(@"Unable to generate inverse mapping for relationship '%@': %@ relationships cannot be inversed.", relationshipMapping.sourceKeyPath, NSStringFromClass([mapping class])); continue; } [inverseMapping mapKeyPath:relationshipMapping.destinationKeyPath toRelationship:relationshipMapping.sourceKeyPath withMapping:[(RKObjectMapping*)mapping inverseMappingAtDepth:depth+1]]; } } return inverseMapping; } - (RKObjectMapping*)inverseMapping { return [self inverseMappingAtDepth:0]; } - (void)mapKeyPathsToAttributes:(NSString*)firstKeyPath, ... { va_list args; va_start(args, firstKeyPath); for (NSString* keyPath = firstKeyPath; keyPath != nil; keyPath = va_arg(args, NSString*)) { NSString* attributeKeyPath = va_arg(args, NSString*); NSAssert(attributeKeyPath != nil, @"Cannot map a keyPath without a destination attribute keyPath"); [self mapKeyPath:keyPath toAttribute:attributeKeyPath]; // TODO: Raise proper exception here, argument error... } va_end(args); } - (void)mapKeyOfNestedDictionaryToAttribute:(NSString*)attributeName { [self mapKeyPath:RKObjectMappingNestingAttributeKeyName toAttribute:attributeName]; } - (RKObjectAttributeMapping *)attributeMappingForKeyOfNestedDictionary { return [self mappingForKeyPath:RKObjectMappingNestingAttributeKeyName]; } - (RKObjectAttributeMapping*)mappingForAttribute:(NSString*)attributeKey { for (RKObjectAttributeMapping* mapping in [self attributeMappings]) { if ([mapping.destinationKeyPath isEqualToString:attributeKey]) { return mapping; } } return nil; } - (RKObjectRelationshipMapping*)mappingForRelationship:(NSString*)relationshipKey { for (RKObjectRelationshipMapping* mapping in [self relationshipMappings]) { if ([mapping.destinationKeyPath isEqualToString:relationshipKey]) { return mapping; } } return nil; } - (id)defaultValueForMissingAttribute:(NSString*)attributeName { return nil; } - (id)mappableObjectForData:(id)mappableData { return [[self.objectClass new] autorelease]; } - (Class)classForProperty:(NSString*)propertyName { return [[RKObjectPropertyInspector sharedInspector] typeForProperty:propertyName ofClass:self.objectClass]; } #pragma mark - Date and Time - (NSFormatter *)preferredDateFormatter { return _preferredDateFormatter ? _preferredDateFormatter : [RKObjectMapping preferredDateFormatter]; } - (NSArray *)dateFormatters { return _dateFormatters ? _dateFormatters : [RKObjectMapping defaultDateFormatters]; } @end ///////////////////////////////////////////////////////////////////////////// static NSMutableArray *defaultDateFormatters = nil; static NSDateFormatter *preferredDateFormatter = nil; @implementation RKObjectMapping (DateAndTimeFormatting) + (NSArray *)defaultDateFormatters { if (!defaultDateFormatters) { defaultDateFormatters = [[NSMutableArray alloc] initWithCapacity:2]; // Setup the default formatters RKISO8601DateFormatter *isoFormatter = [[RKISO8601DateFormatter alloc] init]; [self addDefaultDateFormatter:isoFormatter]; [isoFormatter release]; [self addDefaultDateFormatterForString:@"MM/dd/yyyy" inTimeZone:nil]; [self addDefaultDateFormatterForString:@"yyyy-MM-dd'T'HH:mm:ss'Z'" inTimeZone:nil]; } return defaultDateFormatters; } + (void)setDefaultDateFormatters:(NSArray *)dateFormatters { [defaultDateFormatters release]; defaultDateFormatters = nil; if (dateFormatters) { defaultDateFormatters = [[NSMutableArray alloc] initWithArray:dateFormatters]; } } + (void)addDefaultDateFormatter:(id)dateFormatter { [self defaultDateFormatters]; [defaultDateFormatters insertObject:dateFormatter atIndex:0]; } + (void)addDefaultDateFormatterForString:(NSString *)dateFormatString inTimeZone:(NSTimeZone *)nilOrTimeZone { NSDateFormatter *dateFormatter = [NSDateFormatter new]; dateFormatter.dateFormat = dateFormatString; dateFormatter.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; if (nilOrTimeZone) { dateFormatter.timeZone = nilOrTimeZone; } else { dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; } [self addDefaultDateFormatter:dateFormatter]; [dateFormatter release]; } + (NSFormatter *)preferredDateFormatter { if (!preferredDateFormatter) { // A date formatter that matches the output of [NSDate description] preferredDateFormatter = [NSDateFormatter new]; [preferredDateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss Z"]; preferredDateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; preferredDateFormatter.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; } return preferredDateFormatter; } + (void)setPreferredDateFormatter:(NSDateFormatter *)dateFormatter { [dateFormatter retain]; [preferredDateFormatter release]; preferredDateFormatter = dateFormatter; } @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMapping.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMappingDefinition.h
// // RKObjectMappingDefinition.h // RestKit // // Created by Blake Watters on 7/31/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // /** RKObjectMappingDefinition is an abstract class for objects defining RestKit object mappings. Its interface is common to all object mapping classes, including its concrete subclasses RKObjectMapping and RKDynamicObjectMapping. */ @interface RKObjectMappingDefinition : NSObject /** The root key path for the receiver. Root key paths are handled differently depending on the context in which the mapping is being used. If the receiver is used for object mapping, the rootKeyPath specifies a nested root dictionary that all attribute and relationship mappings will be considered relative to. When the mapping is used in a serialization context, the rootKeyPath specifies that the serialized content should be stored in a dictionary nested with the rootKeyPath as the key. @see RKObjectSerializer */ @property (nonatomic, copy) NSString *rootKeyPath; /** Forces the mapper to treat the mapped keyPath as a collection even if it does not return an array or a set of objects. This permits mapping where a dictionary identifies a collection of objects. When enabled, each key/value pair in the resolved dictionary will be mapped as a separate entity. This is useful when you have a JSON structure similar to: { "users": { "blake": { "id": 1234, "email": "[email protected]" }, "rachit": { "id": 5678", "email": "[email protected]" } } } By enabling forceCollectionMapping, RestKit will map "blake" => attributes and "rachit" => attributes as independent objects. This can be combined with mapKeyOfNestedDictionaryToAttribute: to properly map these sorts of structures. @default NO @see mapKeyOfNestedDictionaryToAttribute */ @property (nonatomic, assign) BOOL forceCollectionMapping; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMappingDefinition.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMappingDefinition.m
// // RKObjectMappingDefinition.m // RestKit // // Created by Blake Watters on 2/15/12. // Copyright (c) 2009-2012 RestKit. All rights reserved. // #import "RKObjectMappingDefinition.h" @implementation RKObjectMappingDefinition @synthesize rootKeyPath; @synthesize forceCollectionMapping; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMappingDefinition.m
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMappingOperation.h
// // RKObjectMappingOperation.h // RestKit // // Created by Blake Watters on 4/30/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import "RKObjectMapping.h" #import "RKObjectAttributeMapping.h" @class RKObjectMappingOperation; @class RKMappingOperationQueue; /** Objects acting as the delegate for RKObjectMappingOperation objects must adopt the RKObjectMappingOperationDelegate protocol. These methods enable the delegate to be notified of events such as the application of attribute and relationship mappings during a mapping operation. */ @protocol RKObjectMappingOperationDelegate <NSObject> @optional /** Tells the delegate that an attribute or relationship mapping was found for a given key path within the data being mapped. @param operation The object mapping operation being performed. @param mapping The RKObjectAttributeMapping or RKObjectRelationshipMapping found for the key path. @param keyPath The key path in the source object for which the mapping is to be applied. */ - (void)objectMappingOperation:(RKObjectMappingOperation *)operation didFindMapping:(RKObjectAttributeMapping *)mapping forKeyPath:(NSString *)keyPath; /** Tells the delegate that no attribute or relationships mapping was found for a given key path within the data being mapped. @param operation The object mapping operation being performed. @param keyPath The key path in the source object for which no mapping was found. */ - (void)objectMappingOperation:(RKObjectMappingOperation *)operation didNotFindMappingForKeyPath:(NSString *)keyPath; /** Tells the delegate that the mapping operation has set a value for a given key path with an attribute or relationship mapping. @param operation The object mapping operation being performed. @param value A new value that was set on the destination object. @param keyPath The key path in the destination object for which a new value has been set. @param mapping The RKObjectAttributeMapping or RKObjectRelationshipMapping found for the key path. */ - (void)objectMappingOperation:(RKObjectMappingOperation *)operation didSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKObjectAttributeMapping *)mapping; /** Tells the delegate that the mapping operation has declined to set a value for a given key path because the value has not changed. @param operation The object mapping operation being performed. @param value A unchanged value for the key path in the destination object. @param keyPath The key path in the destination object for which a unchanged value was not set. @param mapping The RKObjectAttributeMapping or RKObjectRelationshipMapping found for the key path. */ - (void)objectMappingOperation:(RKObjectMappingOperation *)operation didNotSetUnchangedValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKObjectAttributeMapping *)mapping; /** Tells the delegate that the object mapping operation has failed due to an error. @param operation The object mapping operation that has failed. @param error An error object indicating the reason for the failure. */ - (void)objectMappingOperation:(RKObjectMappingOperation *)operation didFailWithError:(NSError *)error; @end /** Instances of RKObjectMappingOperation perform transformation between object representations according to the rules express in RKObjectMapping objects. Mapping operations provide the foundation for the RestKit object mapping engine and perform the work of inspecting the attributes and relationships of a source object and determining how to map them into new representations on a destination object. */ @interface RKObjectMappingOperation : NSObject /** A dictionary of mappable elements containing simple values or nested object structures. */ @property (nonatomic, readonly) id sourceObject; /** The target object for this operation. Mappable values in elements will be applied to object using key-value coding. */ @property (nonatomic, readonly) id destinationObject; /** The object mapping defining how values contained in the source object should be transformed to the destination object via key-value coding */ @property (nonatomic, readonly) RKObjectMapping *objectMapping; /** The delegate to inform of interesting events during the mapping operation */ @property (nonatomic, assign) id<RKObjectMappingOperationDelegate> delegate; /** An operation queue for deferring portions of the mapping process until later Defaults to nil. If this mapping operation was configured by an instance of RKObjectMapper, then an instance of the operation queue will be configured and assigned for use. If the queue is nil, the mapping operation will perform all its operations within the body of performMapping. If a queue is present, it may elect to defer portions of the mapping operation using the queue. */ @property (nonatomic, retain) RKMappingOperationQueue *queue; /** Creates and returns a new mapping operation configured to transform the object representation in a source object to a new destination object according to an object mapping definition. Note that if Core Data support is available, an instance of RKManagedObjectMappingOperation may be returned. @param sourceObject The source object to be mapped. Cannot be nil. @param destinationObject The destination object the results are to be mapped onto. May be nil, in which case a new object will be constructed during the mapping. @param mapping An instance of RKObjectMapping or RKDynamicObjectMapping defining how the mapping is to be performed. @return An instance of RKObjectMappingOperation or RKManagedObjectMappingOperation for performing the mapping. */ + (id)mappingOperationFromObject:(id)sourceObject toObject:(id)destinationObject withMapping:(RKObjectMappingDefinition *)mapping; /** Initializes the receiver with a source and destination objects and an object mapping definition for performing a mapping. @param sourceObject The source object to be mapped. Cannot be nil. @param destinationObject The destination object the results are to be mapped onto. May be nil, in which case a new object will be constructed during the mapping. @param mapping An instance of RKObjectMapping or RKDynamicObjectMapping defining how the mapping is to be performed. @return The receiver, initialized with a source object, a destination object, and a mapping. */ - (id)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKObjectMappingDefinition *)mapping; /** Process all mappable values from the mappable dictionary and assign them to the target object according to the rules expressed in the object mapping definition @param error A pointer to an NSError reference to capture any error that occurs during the mapping. May be nil. @return A Boolean value indicating if the mapping operation was successful. */ - (BOOL)performMapping:(NSError **)error; @end
__MACOSX/IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/._RKObjectMappingOperation.h
IT4781-U02A1-AlexBenavides/StoreLocator/Libraries/RestKit/Code/ObjectMapping/RKObjectMappingOperation.m
// // RKObjectMappingOperation.m // RestKit // // Created by Blake Watters on 4/30/11. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #import <objc/message.h> #import "RKObjectMappingOperation.h" #import "RKObjectMapperError.h" #import "RKObjectPropertyInspector.h" #import "RKObjectRelationshipMapping.h" #import "RKObjectMapper.h" #import "RKErrors.h" #import "RKLog.h" // Set Logging Component #undef RKLogComponent #define RKLogComponent lcl_cRestKitObjectMapping // Temporary home for object equivalancy tests BOOL RKObjectIsValueEqualToValue(id sourceValue, id destinationValue); BOOL RKObjectIsValueEqualToValue(id sourceValue, id destinationValue) { NSCAssert(sourceValue, @"Expected sourceValue not to be nil"); NSCAssert(destinationValue, @"Expected destinationValue not to be nil"); SEL comparisonSelector; if ([sourceValue isKindOfClass:[NSString class]] && [destinationValue isKindOfClass:[NSString class]]) { comparisonSelector = @selector(isEqualToString:); } else if ([sourceValue isKindOfClass:[NSNumber class]] && [destinationValue isKindOfClass:[NSNumber class]]) { comparisonSelector = @selector(isEqualToNumber:); } else if ([sourceValue isKindOfClass:[NSDate class]] && [destinationValue isKindOfClass:[NSDate class]]) { comparisonSelector = @selector(isEqualToDate:); } else if ([sourceValue isKindOfClass:[NSArray class]] && [destinationValue isKindOfClass:[NSArray class]]) { comparisonSelector = @selector(isEqualToArray:); } else if ([sourceValue isKindOfClass:[NSDictionary class]] && [destinationValue isKindOfClass:[NSDictionary class]]) { comparisonSelector = @selector(isEqualToDictionary:); } else if ([sourceValue isKindOfClass:[NSSet class]] && [destinationValue isKindOfClass:[NSSet class]]) { comparisonSelector = @selector(isEqualToSet:); } else { comparisonSelector = @selector(isEqual:); } // Comparison magic using function pointers. See this page for details: http://www.red-sweater.com/blog/320/abusing-objective-c-with-class // Original code courtesy of Greg Parker // This is necessary because isEqualToNumber will return negative integer values that aren't coercable directly to BOOL's without help [sbw] BOOL (*ComparisonSender)(id, SEL, id) = (BOOL (*)(id, SEL, id)) objc_msgSend; return ComparisonSender(sourceValue, comparisonSelector, destinationValue); } @interface RKObjectMappingOperation () @property (nonatomic, retain) NSDictionary *nestedAttributeSubstitution; @property (nonatomic, retain) NSError *validationError; @end @implementation RKObjectMappingOperation @synthesize sourceObject = _sourceObject; @synthesize destinationObject = _destinationObject; @synthesize objectMapping = _objectMapping; @synthesize delegate = _delegate; @synthesize queue = _queue; @synthesize nestedAttributeSubstitution = _nestedAttributeSubstitution; @synthesize validationError = _validationError; + (id)mappingOperationFromObject:(id)sourceObject toObject:(id)destinationObject withMapping:(RKObjectMappingDefinition *)objectMapping { // Check for availability of ManagedObjectMappingOperation. Better approach for handling? Class targetClass = NSClassFromString(@"RKManagedObjectMappingOperation"); if (targetClass == nil) targetClass = [RKObjectMappingOperation class]; return [[[targetClass alloc] initWithSourceObject:sourceObject destinationObject:destinationObject mapping:objectMapping] autorelease]; } - (id)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKObjectMappingDefinition *)objectMapping { NSAssert(sourceObject != nil, @"Cannot perform a mapping operation without a sourceObject object"); NSAssert(destinationObject != nil, @"Cannot perform a mapping operation without a destinationObject"); NSAssert(objectMapping != nil, @"Cannot perform a mapping operation without a mapping"); self = [super init]; if (self) { _sourceObject = [sourceObject retain]; _destinationObject = [destinationObject retain]; if ([objectMapping isKindOfClass:[RKDynamicObjectMapping class]]) { _objectMapping = [[(RKDynamicObjectMapping*)objectMapping objectMappingForDictionary:_sourceObject] retain]; RKLogDebug(@"RKObjectMappingOperation was initialized with a dynamic mapping. Determined concrete mapping = %@", _objectMapping); } else if ([objectMapping isKindOfClass:[RKObjectMapping class]]) { _objectMapping = (RKObjectMapping*)[objectMapping retain]; } NSAssert(_objectMapping, @"Cannot perform a mapping operation with an object mapping"); } return self; } - (void)dealloc { [_sourceObject release]; [_destinationObject release]; [_objectMapping release]; [_nestedAttributeSubstitution release]; [_queue release]; [super dealloc]; } - (NSDate*)parseDateFromString:(NSString*)string { RKLogTrace(@"Transforming string value '%@' to NSDate...", string); NSDate* date = nil; NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; NSNumber *numeric = [numberFormatter numberFromString:string]; [numberFormatter release]; if (numeric) { date = [NSDate dateWithTimeIntervalSince1970:[numeric doubleValue]]; } else if(![string isEqualToString:@""]) { for (NSFormatter *dateFormatter in self.objectMapping.dateFormatters) { BOOL success; @synchronized(dateFormatter) { if ([dateFormatter isKindOfClass:[NSDateFormatter class]]) { RKLogTrace(@"Attempting to parse string '%@' with format string '%@' and time zone '%@'", string, [(NSDateFormatter *)dateFormatter dateFormat], [(NSDateFormatter *)dateFormatter timeZone]); } NSString *errorDescription = nil; success = [dateFormatter getObjectValue:&date forString:string errorDescription:&errorDescription]; } if (success && date) { if ([dateFormatter isKindOfClass:[NSDateFormatter class]]) { RKLogTrace(@"Successfully parsed string '%@' with format string '%@' and time zone '%@' and turned into date '%@'", string, [(NSDateFormatter *)dateFormatter dateFormat], [(NSDateFormatter *)dateFormatter timeZone], date); } break; } } } return date; } - (id)transformValue:(id)value atKeyPath:(NSString *)keyPath toType:(Class)destinationType { RKLogTrace(@"Found transformable value at keyPath '%@'. Transforming from type '%@' to '%@'", keyPath, NSStringFromClass([value class]), NSStringFromClass(destinationType)); Class sourceType = [value class]; Class orderedSetClass = NSClassFromString(@"NSOrderedSet"); if ([sourceType isSubclassOfClass:[NSString class]]) { if ([destinationType isSubclassOfClass:[NSDate class]]) { // String -> Date return [self parseDateFromString:(NSString*)value]; } else if ([destinationType isSubclassOfClass:[NSURL class]]) { // String -> URL return [NSURL URLWithString:(NSString*)value]; } else if ([destinationType isSubclassOfClass:[NSDecimalNumber class]]) { // String -> Decimal Number return [NSDecimalNumber decimalNumberWithString:(NSString*)value]; } else if ([destinationType isSubclassOfClass:[NSNumber class]]) { // String -> Number NSString* lowercasedString = [(NSString*)value lowercaseString]; NSSet* trueStrings = [NSSet setWithObjects:@"true", @"t", @"yes", nil]; NSSet* booleanStrings = [trueStrings setByAddingObjectsFromSet:[NSSet setWithObjects:@"false", @"f", @"no", nil]]; if ([booleanStrings containsObject:lowercasedString]) { // Handle booleans encoded as Strings return [NSNumber numberWithBool:[trueStrings containsObject:lowercasedString]]; } else { return [NSNumber numberWithDouble:[(NSString*)value doubleValue]]; } } } else if (value == [NSNull null] || [value isEqual:[NSNull null]]) { // Transform NSNull -> nil for simplicity return nil; } else if ([sourceType isSubclassOfClass:[NSSet class]]) { // Set -> Array if ([destinationType isSubclassOfClass:[NSArray class]]) { return [(NSSet*)value allObjects]; } } else if (orderedSetClass && [sourceType isSubclassOfClass:orderedSetClass]) { // OrderedSet -> Array if ([destinationType isSubclassOfClass:[NSArray class]]) { return [value array]; } } else if ([sourceType isSubclassOfClass:[NSArray class]]) { // Array -> Set if ([destinationType isSubclassOfClass:[NSSet class]]) { return [NSSet setWithArray:value]; } // Array -> OrderedSet if (orderedSetClass && [destinationType isSubclassOfClass:orderedSetClass]) { return [orderedSetClass orderedSetWithArray:value]; } } else if ([sourceType isSubclassOfClass:[NSNumber class]] && [destinationType isSubclassOfClass:[NSDate class]]) { // Number -> Date if ([destinationType isSubclassOfClass:[NSDate class]]) { return [NSDate dateWithTimeIntervalSince1970:[(NSNumber*)value intValue]]; } else if ([sourceType isSubclassOfClass:NSClassFromString(@"__NSCFBoolean")] && [destinationType isSubclassOfClass:[NSString class]]) { return ([value boolValue] ? @"true" : @"false"); } return [NSDate dateWithTimeIntervalSince1970:[(NSNumber*)value doubleValue]]; } else if ([sourceType isSubclassOfClass:[NSNumber class]] && [destinationType isSubclassOfClass:[NSDecimalNumber class]]) { // Number -> Decimal Number return [NSDecimalNumber decimalNumberWithDecimal:[value decimalValue]]; } else if ( ([sourceType isSubclassOfClass:NSClassFromString(@"__NSCFBoolean")] || [sourceType isSubclassOfClass:NSClassFromString(@"NSCFBoolean")] ) && [destinationType isSubclassOfClass:[NSString class]]) { return ([value boolValue] ? @"true" : @"false"); if ([destinationType isSubclassOfClass:[NSDate class]]) { return [NSDate dateWithTimeIntervalSince1970:[(NSNumber*)value intValue]]; } else if (([sourceType isSubclassOfClass:NSClassFromString(@"__NSCFBoolean")] || [sourceType isSubclassOfClass:NSClassFromString(@"NSCFBoolean")]) && [destinationType isSubclassOfClass:[NSString class]]) { return ([value boolValue] ? @"true" : @"false"); } } else if ([destinationType isSubclassOfClass:[NSString class]] && [value respondsToSelector:@selector(stringValue)]) { return [value stringValue]; } else if ([destinationType isSubclassOfClass:[NSString class]] && [value isKindOfClass:[NSDate class]]) { // NSDate -> NSString // Transform using the preferred date formatter NSString* dateString = nil; @synchronized(self.objectMapping.preferredDateFormatter) { dateString = [self.objectMapping.preferredDateFormatter stringForObjectValue:value]; } return dateString; } RKLogWarning(@"Failed transformation of value at keyPath '%@'. No strategy for transforming from '%@' to '%@'", keyPath, NSStringFromClass([value class]), NSStringFromClass(destinationType)); return nil; } - (BOOL)isValue:(id)sourceValue equalToValue:(id)destinationValue { return RKObjectIsValueEqualToValue(sourceValue, destinationValue); } - (BOOL)validateValue:(id *)value atKeyPath:(NSString*)keyPath { BOOL success = YES; if (self.objectMapping.performKeyValueValidation && [self.destinationObject respondsToSelector:@selector(validateValue:forKeyPath:error:)]) { success = [self.destinationObject validateValue:value forKeyPath:keyPath error:&_validationError]; if (!success) { if (_validationError) { RKLogError(@"Validation failed while mapping attribute at key path '%@' to value %@. Error: %@", keyPath, *value, [_validationError localizedDescription]); RKLogValidationError(_validationError); } else { RKLogWarning(@"Destination object %@ rejected attribute value %@ for keyPath %@. Skipping...", self.destinationObject, *value, keyPath); } } } return success; } - (BOOL)shouldSetValue:(id *)value atKeyPath:(NSString*)keyPath { id currentValue = [self.destinationObject valueForKeyPath:keyPath]; if (currentValue == [NSNull null] || [currentValue isEqual:[NSNull null]]) { currentValue = nil; } /* WTF - This workaround should not be necessary, but I have been unable to replicate the circumstances that trigger it in a unit test to fix elsewhere. The proper place to handle it is in transformValue:atKeyPath:toType: See issue & pull request: https://github.com/RestKit/RestKit/pull/436 */ if (*value == [NSNull null] || [*value isEqual:[NSNull null]]) { RKLogWarning(@"Coercing NSNull value to nil in shouldSetValue:atKeyPath: -- should be fixed."); *value = nil; } if (nil == currentValue && nil == *value) { // Both are nil return NO; } else if (nil == *value || nil == currentValue) { // One is nil and the other is not return [self validateValue:value atKeyPath:keyPath]; } if (! [self isValue:*value equalToValue:currentValue]) { // Validate value for key return [self validateValue:value atKeyPath:keyPath]; } return NO; } - (NSArray*)applyNestingToMappings:(NSArray*)mappings { if (_nestedAttributeSubstitution) { NSString* searchString = [NSString stringWithFormat:@"(%@)", [[_nestedAttributeSubstitution allKeys] lastObject]]; NSString* replacementString = [[_nestedAttributeSubstitution allValues] lastObject]; NSMutableArray* array = [NSMutableArray arrayWithCapacity:[self.objectMapping.attributeMappings count]]; for (RKObjectAttributeMapping* mapping in mappings) { RKObjectAttributeMapping* nestedMapping = [mapping copy]; nestedMapping.sourceKeyPath = [nestedMapping.sourceKeyPath stringByReplacingOccurrencesOfString:searchString withString:replacementString]; nestedMapping.destinationKeyPath = [nestedMapping.destinationKeyPath stringByReplacingOccurrencesOfString:searchString withString:replacementString]; [array addObject:nestedMapping]; [nestedMapping release]; } return array; } return mappings; } - (NSArray*)attributeMappings { return [self applyNestingToMappings:self.objectMapping.attributeMappings]; } - (NSArray*)relationshipMappings { return [self applyNestingToMappings:self.objectMapping.relationshipMappings]; } - (void)applyAttributeMapping:(RKObjectAttributeMapping*)attributeMapping withValue:(id)value { if ([self.delegate respondsToSelector:@selector(objectMappingOperation:didFindMapping:forKeyPath:)]) { [self.delegate objectMappingOperation:self didFindMapping:attributeMapping forKeyPath:attributeMapping.sourceKeyPath]; } RKLogTrace(@"Mapping attribute value keyPath '%@' to '%@'", attributeMapping.sourceKeyPath, attributeMapping.destinationKeyPath); // Inspect the property type to handle any value transformations Class type = [self.objectMapping classForProperty:attributeMapping.destinationKeyPath]; if (type && NO == [[value class] isSubclassOfClass:type]) { value = [self transformValue:value atKeyPath:attributeMapping.sourceKeyPath toType:type]; } // Ensure that the value is different if ([self shouldSetValue:&value atKeyPath:attributeMapping.destinationKeyPath]) { RKLogTrace(@"Mapped attribute value from keyPath '%@' to '%@'. Value: %@", attributeMapping.sourceKeyPath, attributeMapping.destinationKeyPath, value); [self.destinationObject setValue:value forKeyPath:attributeMapping.destinationKeyPath]; if ([self.delegate respondsToSelector:@selector(objectMappingOperation:didSetValue:forKeyPath:usingMapping:)]) { [self.delegate objectMappingOperation:self didSetValue:value forKeyPath:attributeMapping.destinationKeyPath usingMapping:attributeMapping]; } } else { RKLogTrace(@"Skipped mapping of attribute value from keyPath '%@ to keyPath '%@' -- value is unchanged (%@)", attributeMapping.sourceKeyPath, attributeMapping.destinationKeyPath, value); if ([self.delegate respondsToSelector:@selector(objectMappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { [self.delegate objectMappingOperation:self didNotSetUnchangedValue:value forKeyPath:attributeMapping.destinationKeyPath usingMapping:attributeMapping]; } } } // Return YES if we mapped any attributes - (BOOL)applyAttributeMappings { // If we have a nesting substitution value, we have alread BOOL appliedMappings = (_nestedAttributeSubstitution != nil); if (!self.objectMapping.performKeyValueValidation) { RKLogDebug(@"Key-value validation is disabled for mapping, skipping..."); } for (RKObjectAttributeMapping* attributeMapping in [self attributeMappings]) { if ([attributeMapping isMappingForKeyOfNestedDictionary]) { RKLogTrace(@"Skipping attribute mapping for special keyPath '%@'", attributeMapping.sourceKeyPath); continue; } if (self.objectMapping.ignoreUnknownKeyPaths && ![self.sourceObject respondsToSelector:NSSelectorFromString(attributeMapping.sourceKeyPath)]) { RKLogDebug(@"Source object is not key-value coding compliant for the keyPath '%@', skipping...", attributeMapping.sourceKeyPath); continue; } id value = nil; @try { if ([attributeMapping.sourceKeyPath isEqualToString:@""]) { value = self.sourceObject; } else { value = [self.sourceObject valueForKeyPath:attributeMapping.sourceKeyPath]; } } @catch (NSException *exception) { if ([[exception name] isEqualToString:NSUndefinedKeyException] && self.objectMapping.ignoreUnknownKeyPaths) { RKLogWarning(@"Encountered an undefined attribute mapping for keyPath '%@' that generated NSUndefinedKeyException exception. Skipping due to objectMapping.ignoreUnknownKeyPaths = YES", attributeMapping.sourceKeyPath); continue; } @throw; } if (value) { appliedMappings = YES; [self applyAttributeMapping:attributeMapping withValue:value]; } else { if ([self.delegate respondsToSelector:@selector(objectMappingOperation:didNotFindMappingForKeyPath:)]) { [self.delegate objectMappingOperation:self didNotFindMappingForKeyPath:attributeMapping.sourceKeyPath]; } RKLogTrace(@"Did not find mappable attribute value keyPath '%@'", attributeMapping.sourceKeyPath); // Optionally set the default value for missing values if ([self.objectMapping shouldSetDefaultValueForMissingAttributes]) { [self.destinationObject setValue:[self.objectMapping defaultValueForMissingAttribute:attributeMapping.destinationKeyPath] forKeyPath:attributeMapping.destinationKeyPath]; RKLogTrace(@"Setting nil for missing attribute value at keyPath '%@'", attributeMapping.sourceKeyPath); } } // Fail out if an error has occurred if (_validationError) { return NO; } } return appliedMappings; } - (BOOL)isTypeACollection:(Class)type { Class orderedSetClass = NSClassFromString(@"NSOrderedSet"); return (type && ([type isSubclassOfClass:[NSSet class]] || [type isSubclassOfClass:[NSArray class]] || (orderedSetClass && [type isSubclassOfClass:orderedSetClass]))); } - (BOOL)isValueACollection:(id)value { return [self isTypeACollection:[value class]]; } - (BOOL)mapNestedObject:(id)anObject toObject:(id)anotherObject withRealtionshipMapping:(RKObjectRelationshipMapping*)relationshipMapping { NSAssert(anObject, @"Cannot map nested object without a nested source object"); NSAssert(anotherObject, @"Cannot map nested object without a destination object"); NSAssert(relationshipMapping, @"Cannot map a nested object relationship without a relationship mapping"); NSError* error = nil; RKLogTrace(@"Performing nested object mapping using mapping %@ for data: %@", relationshipMapping, anObject); RKObjectMappingOperation* subOperation = [RKObjectMappingOperation mappingOperationFromObject:anObject toObject:anotherObject withMapping:relationshipMapping.mapping]; subOperation.delegate = self.delegate; subOperation.queue = self.queue; if (NO == [subOperation performMapping:&error]) { RKLogWarning(@"WARNING: Failed mapping nested object: %@", [error localizedDescription]); } return YES; } - (BOOL)applyRelationshipMappings { BOOL appliedMappings = NO; id destinationObject = nil; for (RKObjectRelationshipMapping* relationshipMapping in [self relationshipMappings]) { id value = nil; @try { value = [self.sourceObject valueForKeyPath:relationshipMapping.sourceKeyPath]; } @catch (NSException *exception) { if ([[exception name] isEqualToString:NSUndefinedKeyException] && self.objectMapping.ignoreUnknownKeyPaths) { RKLogWarning(@"Encountered an undefined relationship mapping for keyPath '%@' that generated NSUndefinedKeyException exception. Skipping due to objectMapping.ignoreUnknownKeyPaths = YES", relationshipMapping.sourceKeyPath); continue; } @throw; } if (value == nil || value == [NSNull null] || [value isEqual:[NSNull null]]) { RKLogDebug(@"Did not find mappable relationship value keyPath '%@'", relationshipMapping.sourceKeyPath); // Optionally nil out the property id nilReference = nil; if ([self.objectMapping setNilForMissingRelationships] && [self shouldSetValue:&nilReference atKeyPath:relationshipMapping.destinationKeyPath]) { RKLogTrace(@"Setting nil for missing relationship value at keyPath '%@'", relationshipMapping.sourceKeyPath); [self.destinationObject setValue:nil forKeyPath:relationshipMapping.destinationKeyPath]; } continue; } // Handle case where incoming content is collection represented by a dictionary if (relationshipMapping.mapping.forceCollectionMapping) { // If we have forced mapping of a dictionary, map each subdictionary if ([value isKindOfClass:[NSDictionary class]]) { RKLogDebug(@"Collection mapping forced for NSDictionary, mapping each key/value independently..."); NSArray* objectsToMap = [NSMutableArray arrayWithCapacity:[value count]]; for (id key in value) { NSDictionary* dictionaryToMap = [NSDictionary dictionaryWithObject:[value valueForKey:key] forKey:key]; [(NSMutableArray*)objectsToMap addObject:dictionaryToMap]; } value = objectsToMap; } else { RKLogWarning(@"Collection mapping forced but mappable objects is of type '%@' rather than NSDictionary", NSStringFromClass([value class])); } } // Handle case where incoming content is a single object, but we want a collection Class relationshipType = [self.objectMapping classForProperty:relationshipMapping.destinationKeyPath]; BOOL mappingToCollection = [self isTypeACollection:relationshipType]; if (mappingToCollection && ![self isValueACollection:value]) { Class orderedSetClass = NSClassFromString(@"NSOrderedSet"); RKLogDebug(@"Asked to map a single object into a collection relationship. Transforming to an instance of: %@", NSStringFromClass(relationshipType)); if ([relationshipType isSubclassOfClass:[NSArray class]]) { value = [relationshipType arrayWithObject:value]; } else if ([relationshipType isSubclassOfClass:[NSSet class]]) { value = [relationshipType setWithObject:value]; } else if (orderedSetClass && [relationshipType isSubclassOfClass:orderedSetClass]) { value = [relationshipType orderedSetWithObject:value]; } else { RKLogWarning(@"Failed to transform single object"); } } if ([self isValueACollection:value]) { // One to many relationship RKLogDebug(@"Mapping one to many relationship value at keyPath '%@' to '%@'", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath); appliedMappings = YES; destinationObject = [NSMutableArray arrayWithCapacity:[value count]]; id collectionSanityCheckObject = nil; if ([value respondsToSelector:@selector(anyObject)]) collectionSanityCheckObject = [value anyObject]; if ([value respondsToSelector:@selector(lastObject)]) collectionSanityCheckObject = [value lastObject]; if ([self isValueACollection:collectionSanityCheckObject]) { RKLogWarning(@"WARNING: Detected a relationship mapping for a collection containing another collection. This is probably not what you want. Consider using a KVC collection operator (such as @unionOfArrays) to flatten your mappable collection."); RKLogWarning(@"Key path '%@' yielded collection containing another collection rather than a collection of objects: %@", relationshipMapping.sourceKeyPath, value); } for (id nestedObject in value) { RKObjectMappingDefinition * mapping = relationshipMapping.mapping; RKObjectMapping* objectMapping = nil; if ([mapping isKindOfClass:[RKDynamicObjectMapping class]]) { objectMapping = [(RKDynamicObjectMapping*)mapping objectMappingForDictionary:nestedObject]; if (! objectMapping) { RKLogDebug(@"Mapping %@ declined mapping for data %@: returned nil objectMapping", mapping, nestedObject); continue; } } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { objectMapping = (RKObjectMapping*)mapping; } else { NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([mapping class])); } id mappedObject = [objectMapping mappableObjectForData:nestedObject]; if ([self mapNestedObject:nestedObject toObject:mappedObject withRealtionshipMapping:relationshipMapping]) { [destinationObject addObject:mappedObject]; } } // Transform from NSSet <-> NSArray if necessary Class type = [self.objectMapping classForProperty:relationshipMapping.destinationKeyPath]; if (type && NO == [[destinationObject class] isSubclassOfClass:type]) { destinationObject = [self transformValue:destinationObject atKeyPath:relationshipMapping.sourceKeyPath toType:type]; } // If the relationship has changed, set it if ([self shouldSetValue:&destinationObject atKeyPath:relationshipMapping.destinationKeyPath]) { Class managedObjectClass = NSClassFromString(@"NSManagedObject"); Class nsOrderedSetClass = NSClassFromString(@"NSOrderedSet"); if (managedObjectClass && [self.destinationObject isKindOfClass:managedObjectClass]) { RKLogTrace(@"Found a managedObject collection. About to apply value via mutable[Set|Array]ValueForKey"); if ([destinationObject isKindOfClass:[NSSet class]]) { RKLogTrace(@"Mapped NSSet relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, destinationObject); NSMutableSet* destinationSet = [self.destinationObject mutableSetValueForKey:relationshipMapping.destinationKeyPath]; [destinationSet setSet:destinationObject]; } else if ([destinationObject isKindOfClass:[NSArray class]]) { RKLogTrace(@"Mapped NSArray relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, destinationObject); NSMutableArray* destinationArray = [self.destinationObject mutableArrayValueForKey:relationshipMapping.destinationKeyPath]; [destinationArray setArray:destinationObject]; } else if (nsOrderedSetClass && [destinationObject isKindOfClass:nsOrderedSetClass]) { RKLogTrace(@"Mapped NSOrderedSet relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, destinationObject); [self.destinationObject setValue:destinationObject forKey:relationshipMapping.destinationKeyPath]; } } else { RKLogTrace(@"Mapped relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, destinationObject); [self.destinationObject setValue:destinationObject forKeyPath:relationshipMapping.destinationKeyPath]; } } else { if ([self.delegate respondsToSelector:@selector(objectMappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { [self.delegate objectMappingOperation:self didNotSetUnchangedValue:destinationObject forKeyPath:relationshipMapping.destinationKeyPath usingMapping:relationshipMapping]; } } } else { // One to one relationship RKLogDebug(@"Mapping one to one relationship value at keyPath '%@' to '%@'", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath); RKObjectMappingDefinition * mapping = relationshipMapping.mapping; RKObjectMapping* objectMapping = nil; if ([mapping isKindOfClass:[RKDynamicObjectMapping class]]) { objectMapping = [(RKDynamicObjectMapping*)mapping objectMappingForDictionary:value]; } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { objectMapping = (RKObjectMapping*)mapping; } NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([mapping class])); destinationObject = [objectMapping mappableObjectForData:value]; if ([self mapNestedObject:value toObject:destinationObject withRealtionshipMapping:relationshipMapping]) { appliedMappings = YES; } // If the relationship has changed, set it if ([self shouldSetValue:&destinationObject atKeyPath:relationshipMapping.destinationKeyPath]) { appliedMappings = YES; RKLogTrace(@"Mapped relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, destinationObject); [self.destinationObject setValue:destinationObject forKey:relationshipMapping.destinationKeyPath]; } else { if ([self.delegate respondsToSelector:@selector(objectMappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { [self.delegate objectMappingOperation:self didNotSetUnchangedValue:destinationObject forKeyPath:relationshipMapping.destinationKeyPath usingMapping:relationshipMapping]; } } } // Notify the delegate if ([self.delegate respondsToSelector:@selector(objectMappingOperation:didSetValue:forKeyPath:usingMapping:)]) { [self.delegate objectMappingOperation:self didSetValue:destinationObject forKeyPath:relationshipMapping.destinationKeyPath usingMapping:relationshipMapping]; } // Fail out if a validation error has occurred if (_validationError) { return NO; } } return appliedMappings; } - (void)applyNestedMappings { RKObjectAttributeMapping* attributeMapping = [self.objectMapping attributeMappingForKeyOfNestedDictionary]; if (attributeMapping) { RKLogDebug(@"Found nested mapping definition to attribute '%@'", attributeMapping.destinationKeyPath); id attributeValue = [[self.sourceObject allKeys] lastObject]; if (attributeValue) { RKLogDebug(@"Found nesting value of '%@' for attribute '%@'", attributeValue, attributeMapping.destinationKeyPath); _nestedAttributeSubstitution = [[NSDictionary alloc] initWithObjectsAndKeys:attributeValue, attributeMapping.destinationKeyPath, nil]; [self applyAttributeMapping:attributeMapping withValue:attributeValue]; } else { RKLogWarning(@"Unable to find nesting value for attribute '%@'", attributeMapping.destinationKeyPath); } } } - (BOOL)performMapping:(NSError**)error { RKLogDebug(@"Starting mapping operation..."); RKLogTrace(@"Performing mapping operation: %@", self); [self applyNestedMappings]; BOOL mappedAttributes = [self applyAttributeMappings]; BOOL mappedRelationships = [self applyRelationshipMappings]; if ((mappedAttributes || mappedRelationships) && _validationError == nil) { RKLogDebug(@"Finished mapping operation successfully..."); return YES; } if (_validationError) { // We failed out due to validation if (error) *error = _validationError; if ([self.delegate respondsToSelector:@selector(objectMappingOperation:didFailWithError:)]) { [self.delegate objectMappingOperation:self didFailWithError:_validationError]; } RKLogError(@"Failed mapping operation: %@", [_validationError localizedDescription]); } else { // We did not find anything to do RKLogDebug(@"Mapping operation did not find any mappable content"); } return NO; } - (NSString*)description { return [NSString stringWithFormat:@"RKObjectMappingOperation for '%@' object. Mapping values from object %@ to object %@ with object mapping %@", NSStringFromClass([self.destinationObject class]), self.sourceObject, self.destinationObject, self.objectMapping]; } @end