Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Migrate table controller codebase into standalone project

  • Loading branch information...
commit c69f0118cd07e6010264391318a8749129c6736a 1 parent 806aaea
@blakewatters blakewatters authored
Showing with 0 additions and 5,894 deletions.
  1. +0 −26 Code/Support/NSBundle+RKAdditions.h
  2. +0 −29 Code/Support/NSBundle+RKAdditions.m
  3. +0 −456 Code/UI/RKAbstractTableController.h
  4. +0 −1,446 Code/UI/RKAbstractTableController.m
  5. +0 −78 Code/UI/RKAbstractTableController_Internals.h
  6. +0 −68 Code/UI/RKFetchedResultsTableController.h
  7. +0 −709 Code/UI/RKFetchedResultsTableController.m
  8. +0 −57 Code/UI/RKKeyboardScroller.h
  9. +0 −148 Code/UI/RKKeyboardScroller.m
  10. +0 −60 Code/UI/RKObjectManager+RKTableController.h
  11. +0 −50 Code/UI/RKObjectManager+RKTableController.m
  12. +0 −43 Code/UI/RKRefreshGestureRecognizer.h
  13. +0 −243 Code/UI/RKRefreshGestureRecognizer.m
  14. +0 −42 Code/UI/RKRefreshTriggerView.h
  15. +0 −196 Code/UI/RKRefreshTriggerView.m
  16. +0 −15 Code/UI/RKTableCellBlockTypes.h
  17. +0 −155 Code/UI/RKTableController.h
  18. +0 −520 Code/UI/RKTableController.m
  19. +0 −156 Code/UI/RKTableItem.h
  20. +0 −158 Code/UI/RKTableItem.m
  21. +0 −59 Code/UI/RKTableSection.h
  22. +0 −173 Code/UI/RKTableSection.m
  23. +0 −235 Code/UI/RKTableViewCellMapping.h
  24. +0 −295 Code/UI/RKTableViewCellMapping.m
  25. +0 −33 Code/UI/RKTableViewCellMappings.h
  26. +0 −79 Code/UI/RKTableViewCellMappings.m
  27. +0 −33 Code/UI/UI.h
  28. +0 −42 Code/UI/UIImage+RKAdditions.h
  29. +0 −38 Code/UI/UIImage+RKAdditions.m
  30. +0 −27 Code/UI/UIView+FindFirstResponder.h
  31. +0 −41 Code/UI/UIView+FindFirstResponder.m
  32. BIN  Resources/RKRefreshTriggerViewAssets/blackArrow.png
  33. BIN  Resources/RKRefreshTriggerViewAssets/blackArrow@2x.png
  34. BIN  Resources/RKRefreshTriggerViewAssets/blueArrow.png
  35. BIN  Resources/RKRefreshTriggerViewAssets/blueArrow@2x.png
  36. BIN  Resources/RKRefreshTriggerViewAssets/grayArrow.png
  37. BIN  Resources/RKRefreshTriggerViewAssets/grayArrow@2x.png
  38. BIN  Resources/RKRefreshTriggerViewAssets/whiteArrow.png
  39. BIN  Resources/RKRefreshTriggerViewAssets/whiteArrow@2x.png
  40. +0 −124 RestKit.xcodeproj/project.pbxproj
  41. +0 −60 RestKitResources.bundle/Contents/Info.plist
  42. BIN  RestKitResources.bundle/Contents/Resources/blackArrow.png
  43. BIN  RestKitResources.bundle/Contents/Resources/blackArrow@2x.png
  44. BIN  RestKitResources.bundle/Contents/Resources/blueArrow.png
  45. BIN  RestKitResources.bundle/Contents/Resources/blueArrow@2x.png
  46. BIN  RestKitResources.bundle/Contents/Resources/grayArrow.png
  47. BIN  RestKitResources.bundle/Contents/Resources/grayArrow@2x.png
  48. BIN  RestKitResources.bundle/Contents/Resources/whiteArrow.png
  49. BIN  RestKitResources.bundle/Contents/Resources/whiteArrow@2x.png
View
26 Code/Support/NSBundle+RKAdditions.h
@@ -20,10 +20,6 @@
#import <Foundation/Foundation.h>
-#if TARGET_OS_IPHONE
-#import <UIKit/UIImage.h>
-#endif
-
/**
Provides convenience methods for accessing data in resources
within an NSBundle.
@@ -31,17 +27,6 @@
@interface NSBundle (RKAdditions)
/**
- Returns an NSBundle reference to the RestKitResources.bundle file containing
- RestKit specific resource assets.
-
- This method is a convenience wrapper for invoking
- `[NSBundle bundleWithIdentifier:@"org.restkit.RestKitResources"]`
-
- @return An NSBundle object corresponding to the RestKitResources.bundle file.
- */
-+ (NSBundle *)restKitResourcesBundle;
-
-/**
Returns the MIME Type for the resource identified by the specified name and file extension.
@param name The name of the resource file.
@@ -69,17 +54,6 @@
*/
- (NSString *)stringWithContentsOfResource:(NSString *)name withExtension:(NSString *)extension encoding:(NSStringEncoding)encoding;
-#if TARGET_OS_IPHONE
-/**
- Creates and returns an image object by loading the image data from the resource identified by the specified name and file extension.
-
- @param name The name of the resource file.
- @param extension If extension is an empty string or nil, the extension is assumed not to exist and the file is the first file encountered that exactly matches name.
- @return A new image object for the specified file, or nil if the method could not initialize the image from the specified file.
- */
-- (UIImage *)imageWithContentsOfResource:(NSString *)name withExtension:(NSString *)extension;
-#endif
-
/**
Creates and returns an object representation of the data from the resource identified by the specified name and file extension by reading the
data as a string and parsing it using a parser appropriate for the MIME Type of the file.
View
29 Code/Support/NSBundle+RKAdditions.m
@@ -20,28 +20,12 @@
#import "NSBundle+RKAdditions.h"
#import "NSString+RKAdditions.h"
-#import "UIImage+RKAdditions.h"
#import "RKLog.h"
#import "RKParser.h"
#import "RKParserRegistry.h"
@implementation NSBundle (RKAdditions)
-+ (NSBundle *)restKitResourcesBundle
-{
- static BOOL searchedForBundle = NO;
-
- if (! searchedForBundle) {
- NSString *path = [[NSBundle mainBundle] pathForResource:@"RestKitResources" ofType:@"bundle"];
- searchedForBundle = YES;
- NSBundle *resourcesBundle = [NSBundle bundleWithPath:path];
- if (! resourcesBundle) RKLogWarning(@"Unable to find RestKitResources.bundle in your project. Did you forget to add it?");
- return resourcesBundle;
- }
-
- return [NSBundle bundleWithIdentifier:@"org.restkit.RestKitResources"];
-}
-
- (NSString *)MIMETypeForResource:(NSString *)name withExtension:(NSString *)extension
{
NSString *resourcePath = [self pathForResource:name ofType:extension];
@@ -80,19 +64,6 @@ - (NSString *)stringWithContentsOfResource:(NSString *)name withExtension:(NSStr
return fixtureData;
}
-#if TARGET_OS_IPHONE
-- (UIImage *)imageWithContentsOfResource:(NSString *)name withExtension:(NSString *)extension
-{
- NSString *resourcePath = [self pathForResource:name ofType:extension];
- if (! resourcePath) {
- RKLogWarning(@"%@ Failed to locate Resource with name '%@' and extension '%@': File Not Found.", self, resourcePath, extension);
- return nil;
- }
-
- return [UIImage imageWithContentsOfResolutionIndependentFile:resourcePath];
-}
-#endif
-
- (id)parsedObjectWithContentsOfResource:(NSString *)name withExtension:(NSString *)extension
{
NSError *error = nil;
View
456 Code/UI/RKAbstractTableController.h
@@ -1,456 +0,0 @@
-//
-// RKAbstractTableController.h
-// RestKit
-//
-// Created by Jeff Arena on 8/11/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.
-//
-
-#if TARGET_OS_IPHONE
-
-#import <UIKit/UIKit.h>
-#import "RKTableCellBlockTypes.h"
-#import "RKTableViewCellMappings.h"
-#import "RKTableItem.h"
-#import "RKObjectManager.h"
-#import "RKObjectMapping.h"
-#import "RKObjectLoader.h"
-#import "RKKeyboardScroller.h"
-
-///-----------------------------------------------------------------------------
-/// @name Constants
-///-----------------------------------------------------------------------------
-
-/**
- Posted when the table controller starts loading.
- */
-extern NSString * const RKTableControllerDidStartLoadNotification;
-
-/**
- Posted when the table controller finishes loading.
- */
-extern NSString * const RKTableControllerDidFinishLoadNotification;
-
-/**
- Posted when the table controller has loaded objects into the table view.
- */
-extern NSString * const RKTableControllerDidLoadObjectsNotification;
-
-/**
- Posted when the table controller has loaded an empty collection of objects into the table view.
- */
-extern NSString * const RKTableControllerDidLoadEmptyNotification;
-
-/**
- Posted when the table controller has loaded an error.
- */
-extern NSString * const RKTableControllerDidLoadErrorNotification;
-
-/**
- Posted when the table controller has transitioned from an offline to online state.
- */
-extern NSString * const RKTableControllerDidBecomeOnline;
-
-/**
- Posted when the table controller has transitioned from an online to an offline state.
- */
-extern NSString * const RKTableControllerDidBecomeOffline;
-
-@protocol RKAbstractTableControllerDelegate;
-
-/**
- @enum RKTableControllerState
-
- @constant RKTableControllerStateNormal Indicates that the table has
- loaded normally and is displaying cell content. It is not loading content,
- is not empty, has not loaded an error, and is not offline.
-
- @constant RKTableControllerStateLoading Indicates that the table controller
- is loading content from a remote source.
-
- @constant RKTableControllerStateEmpty Indicates that the table controller has
- retrieved an empty collection of objects.
-
- @constant RKTableControllerStateError Indicates that the table controller has
- encountered an error while attempting to load.
-
- @constant RKTableControllerStateOffline Indicates that the table controller is
- offline and cannot perform network access.
-
- @constant RKTableControllerStateNotYetLoaded Indicates that the table controller is
- has not yet attempted a load and state is unknown.
- */
-enum {
- RKTableControllerStateNormal = 0,
- RKTableControllerStateLoading = 1 << 1,
- RKTableControllerStateEmpty = 1 << 2,
- RKTableControllerStateError = 1 << 3,
- RKTableControllerStateOffline = 1 << 4,
- RKTableControllerStateNotYetLoaded = 0xFF000000
-};
-typedef NSUInteger RKTableControllerState;
-
-/**
- RKAbstractTableController is an abstract base class for concrete table controller classes.
- A table controller object acts as both the delegate and data source for a UITableView
- object and leverages the RestKit object mapping engine to transform local domain models
- into UITableViewCell representations. Concrete implementations are provided for the
- display of static table views and Core Data backed fetched results controller basied
- table views.
- */
-@interface RKAbstractTableController : NSObject <UITableViewDataSource, UITableViewDelegate>
-
-///-----------------------------------------------------------------------------
-/// @name Configuring the Table Controller
-///-----------------------------------------------------------------------------
-
-@property (nonatomic, assign) id<RKAbstractTableControllerDelegate> delegate;
-@property (nonatomic, readonly) UIViewController *viewController;
-@property (nonatomic, readonly) UITableView *tableView;
-@property (nonatomic, assign) UITableViewRowAnimation defaultRowAnimation;
-
-@property (nonatomic, assign) BOOL pullToRefreshEnabled;
-@property (nonatomic, assign) BOOL canEditRows;
-@property (nonatomic, assign) BOOL canMoveRows;
-@property (nonatomic, assign) BOOL autoResizesForKeyboard;
-
-///-----------------------------------------------------------------------------
-/// @name Instantiation
-///-----------------------------------------------------------------------------
-
-+ (id)tableControllerWithTableView:(UITableView *)tableView
- forViewController:(UIViewController *)viewController;
-
-+ (id)tableControllerForTableViewController:(UITableViewController *)tableViewController;
-
-- (id)initWithTableView:(UITableView *)tableView
- viewController:(UIViewController *)viewController;
-
-///-----------------------------------------------------------------------------
-/// @name Object to Table View Cell Mappings
-///-----------------------------------------------------------------------------
-
-@property (nonatomic, retain) RKTableViewCellMappings *cellMappings;
-
-- (void)mapObjectsWithClass:(Class)objectClass toTableCellsWithMapping:(RKTableViewCellMapping *)cellMapping;
-- (void)mapObjectsWithClassName:(NSString *)objectClassName toTableCellsWithMapping:(RKTableViewCellMapping *)cellMapping;
-- (id)objectForRowAtIndexPath:(NSIndexPath *)indexPath;
-- (RKTableViewCellMapping *)cellMappingForObjectAtIndexPath:(NSIndexPath *)indexPath;
-
-/**
- Return the index path of the object within the table
- */
-- (NSIndexPath *)indexPathForObject:(id)object;
-- (UITableViewCell *)cellForObject:(id)object;
-- (void)reloadRowForObject:(id)object withRowAnimation:(UITableViewRowAnimation)rowAnimation;
-
-///-----------------------------------------------------------------------------
-/// @name Header and Footer Rows
-///-----------------------------------------------------------------------------
-
-- (void)addHeaderRowForItem:(RKTableItem *)tableItem;
-- (void)addFooterRowForItem:(RKTableItem *)tableItem;
-- (void)addHeaderRowWithMapping:(RKTableViewCellMapping *)cellMapping;
-- (void)addFooterRowWithMapping:(RKTableViewCellMapping *)cellMapping;
-- (void)removeAllHeaderRows;
-- (void)removeAllFooterRows;
-
-///-----------------------------------------------------------------------------
-/// @name RESTful Table Loading
-///-----------------------------------------------------------------------------
-
-/**
- The object manager instance this table controller is associated with.
-
- This instance is used for creating object loaders when loading Network
- tables and provides the managed object store used for Core Data tables.
- Online/offline state is also determined by watching for reachability
- notifications generated from the object manager.
-
- **Default**: The shared manager instance `[RKObjectManager sharedManager]`
- */
-@property (nonatomic, assign) RKObjectManager *objectManager;
-@property (nonatomic, assign) BOOL autoRefreshFromNetwork;
-@property (nonatomic, assign) NSTimeInterval autoRefreshRate;
-
-- (void)loadTableWithObjectLoader:(RKObjectLoader *)objectLoader;
-- (void)cancelLoad;
-- (BOOL)isAutoRefreshNeeded;
-
-///-----------------------------------------------------------------------------
-/// @name Inspecting Table State
-///-----------------------------------------------------------------------------
-
-/**
- The current state of the table controller. Note that the controller may be in more
- than one state (e.g. loading | empty).
- */
-@property (nonatomic, readonly, assign) RKTableControllerState state;
-
-/**
- An error object that was encountered as the result of an attempt to load
- the table. Will return a value when the table is in the error state,
- otherwise nil.
- */
-@property (nonatomic, readonly, retain) NSError *error;
-
-/**
- Returns a Boolean value indicating if the table controller is currently
- loading content.
- */
-- (BOOL)isLoading;
-
-/**
- Returns a Boolean value indicating if the table controller has attempted
- a load and transitioned into any state.
- */
-- (BOOL)isLoaded;
-
-/**
- Returns a Boolean value indicating if the table controller has loaded an
- empty set of content.
-
- When YES and there is not an empty item configured, the table controller
- will optionally display an empty image overlayed on top of the table view.
-
- **NOTE**: It is possible for an empty table controller to display cells
- witin the managed table view in the event an empty item or header/footer
- rows are configured.
-
- @see imageForEmpty
- */
-- (BOOL)isEmpty;
-
-/**
- Returns a Boolean value indicating if the table controller is online
- and network operations may be performed.
- */
-- (BOOL)isOnline;
-
-/**
- Returns a Boolean value indicating if the table controller is offline.
-
- When YES, the table controller will optionally display an offline image
- overlayed on top of the table view.
-
- @see imageForOffline
- */
-- (BOOL)isOffline;
-
-/**
- Returns a Boolean value indicating if the table controller encountered
- an error while attempting to load.
-
- When YES, the table controller will optionally display an error image
- overlayed on top of the table view.
-
- @see imageForError
- */
-- (BOOL)isError;
-
-///-----------------------------------------------------------------------------
-/// @name Block Callbacks
-///-----------------------------------------------------------------------------
-
-// TODO: Audit and expand the library of callbacks...
-// TODO: Docs AND tests...
-@property (nonatomic, copy) RKTableCellForObjectAtIndexPathBlock onSelectCellForObjectAtIndexPath;
-@property (nonatomic, copy) RKTableCellForObjectAtIndexPathBlock onPrepareCellForObjectAtIndexPath; // TODO: May want to eliminate...
-@property (nonatomic, copy) RKTableCellForObjectAtIndexPathBlock onWillDisplayCellForObjectAtIndexPath;
-
-- (void)setOnSelectCellForObjectAtIndexPath:(RKTableCellForObjectAtIndexPathBlock)onSelectCellForObjectAtIndexPath;
-- (void)setOnPrepareCellForObjectAtIndexPath:(RKTableCellForObjectAtIndexPathBlock)onPrepareCellForObjectAtIndexPath;
-- (void)setOnWillDisplayCellForObjectAtIndexPath:(RKTableCellForObjectAtIndexPathBlock)onWillDisplayCellForObjectAtIndexPath;
-
-///-----------------------------------------------------------------------------
-/// @name Model State Views
-///-----------------------------------------------------------------------------
-
-/**
- An image to overlay onto the table when the table view
- does not have any row data to display. It will be centered
- within the table view.
- */
-@property (nonatomic, retain) UIImage *imageForEmpty;
-
-/**
- An image to overlay onto the table when a load operation
- has encountered an error. It will be centered
- within the table view.
- */
-@property (nonatomic, retain) UIImage *imageForError;
-
-/**
- An image to overlay onto the table with when the user does
- not have connectivity to the Internet.
-
- @see RKReachabilityObserver
- */
-@property (nonatomic, retain) UIImage *imageForOffline;
-
-/**
- A UIView to add to the table overlay during loading. It
- will be positioned directly in the center of the table view.
-
- The loading view is always presented non-modally.
- */
-@property (nonatomic, retain) UIView *loadingView;
-
-/**
- Returns the image, if any, configured for display when the table controller
- is in the given state.
-
- **NOTE** This method accepts a single state value.
-
- @param state The table controller state
- @return The image for the specified state, else nil. Always returns nil for
- RKTableControllerStateNormal, RKTableControllerStateLoading and RKTableControllerStateLoading.
- */
-- (UIImage *)imageForState:(RKTableControllerState)state;
-
-/**
- A rectangle configuring the dimensions for the overlay view that is
- applied to the table view during display of the loading view and
- state overlay images (offline/error/empty). By default, the overlay
- view will be auto-sized to cover the entire table. This can result in
- an inaccessible table UI if you have embedded controls within the header
- or footer views of your table. You can adjust the frame of the overlay
- precisely by configuring the overlayFrame property.
- */
-@property (nonatomic, assign) CGRect overlayFrame;
-
-/**
- The image currently displayed within the overlay view.
- */
-@property (nonatomic, readonly) UIImage *overlayImage;
-
-/**
- When YES, the image view added to the table overlay for displaying table
- state (i.e. for offline, error and empty) will be displayed modally
- and prevent any interaction with the table.
-
- **Default**: YES
- */
-@property (nonatomic, assign) BOOL showsOverlayImagesModally;
-
-// Default NO
-@property (nonatomic, assign) BOOL variableHeightRows;
-@property (nonatomic, assign) BOOL showsHeaderRowsWhenEmpty;
-@property (nonatomic, assign) BOOL showsFooterRowsWhenEmpty;
-@property (nonatomic, retain) RKTableItem *emptyItem;
-
-///-----------------------------------------------------------------------------
-/// @name Managing Sections
-///-----------------------------------------------------------------------------
-
-/**
- The number of sections in the table.
- */
-@property (nonatomic, readonly) NSUInteger sectionCount;
-
-/**
- The number of rows across all sections in the model.
- */
-@property (nonatomic, readonly) NSUInteger rowCount;
-
-/**
- Returns the number of rows in the section at the given index.
-
- @param index The index of the section to return the row count for.
- @returns The number of rows contained within the section with the given index.
- @raises NSInvalidArgumentException Raised if index is greater than or
- equal to the total number of sections in the table.
- */
-- (NSUInteger)numberOfRowsInSection:(NSUInteger)index;
-
-///-----------------------------------------------------------------------------
-/// @name Managing Swipe View
-///-----------------------------------------------------------------------------
-
-@property (nonatomic, assign) BOOL cellSwipeViewsEnabled;
-@property (nonatomic, retain) UIView *cellSwipeView;
-@property (nonatomic, readonly) UITableViewCell *swipeCell;
-@property (nonatomic, readonly) id swipeObject;
-@property (nonatomic, readonly) BOOL animatingCellSwipe;
-@property (nonatomic, readonly) UISwipeGestureRecognizerDirection swipeDirection;
-
-- (void)addSwipeViewTo:(UITableViewCell *)cell withObject:(id)object direction:(UISwipeGestureRecognizerDirection)direction;
-- (void)removeSwipeView:(BOOL)animated;
-
-@end
-
-@protocol RKAbstractTableControllerDelegate <NSObject>
-
-@optional
-
-// Network
-- (void)tableController:(RKAbstractTableController *)tableController willLoadTableWithObjectLoader:(RKObjectLoader *)objectLoader;
-- (void)tableController:(RKAbstractTableController *)tableController didLoadTableWithObjectLoader:(RKObjectLoader *)objectLoader;
-
-// Basic States
-- (void)tableControllerDidStartLoad:(RKAbstractTableController *)tableController;
-
-/**
- Sent when the table view has transitioned out of the loading state regardless of outcome
- */
-- (void)tableControllerDidFinishLoad:(RKAbstractTableController *)tableController;
-- (void)tableController:(RKAbstractTableController *)tableController didFailLoadWithError:(NSError *)error;
-- (void)tableControllerDidCancelLoad:(RKAbstractTableController *)tableController;
-
-/**
- Sent to the delegate when the controller is really and truly finished loading/updating, whether from the network or from Core Data,
- or from static data, ... this happens in didFinishLoading
- */
-- (void)tableControllerDidFinalizeLoad:(RKAbstractTableController *)tableController;
-
-/**
- Sent to the delegate when the content of the table view has become empty
- */
-- (void)tableControllerDidBecomeEmpty:(RKAbstractTableController *)tableController;
-
-/**
- Sent to the delegate when the table controller has transitioned from offline to online
- */
-- (void)tableControllerDidBecomeOnline:(RKAbstractTableController *)tableController;
-
-/**
- Sent to the delegate when the table controller has transitioned from online to offline
- */
-- (void)tableControllerDidBecomeOffline:(RKAbstractTableController *)tableController;
-
-// Objects
-- (void)tableController:(RKAbstractTableController *)tableController didInsertObject:(id)object atIndexPath:(NSIndexPath *)indexPath;
-- (void)tableController:(RKAbstractTableController *)tableController didUpdateObject:(id)object atIndexPath:(NSIndexPath *)indexPath;
-- (void)tableController:(RKAbstractTableController *)tableController didDeleteObject:(id)object atIndexPath:(NSIndexPath *)indexPath;
-
-// Editing
-- (void)tableController:(RKAbstractTableController *)tableController willBeginEditing:(id)object atIndexPath:(NSIndexPath *)indexPath;
-- (void)tableController:(RKAbstractTableController *)tableController didEndEditing:(id)object atIndexPath:(NSIndexPath *)indexPath;
-
-// Swipe Views
-- (void)tableController:(RKAbstractTableController *)tableController willAddSwipeView:(UIView *)swipeView toCell:(UITableViewCell *)cell forObject:(id)object;
-- (void)tableController:(RKAbstractTableController *)tableController willRemoveSwipeView:(UIView *)swipeView fromCell:(UITableViewCell *)cell forObject:(id)object;
-
-// Cells
-- (void)tableController:(RKAbstractTableController *)tableController willDisplayCell:(UITableViewCell *)cell forObject:(id)object atIndexPath:(NSIndexPath *)indexPath;
-- (void)tableController:(RKAbstractTableController *)tableController didSelectCell:(UITableViewCell *)cell forObject:(id)object atIndexPath:(NSIndexPath *)indexPath;
-
-// Sections
-- (CGFloat)tableController:(RKAbstractTableController *)tableController heightForHeaderInSection:(NSInteger)sectionIndex;
-- (CGFloat)tableController:(RKAbstractTableController *)tableController heightForFooterInSection:(NSInteger)sectionIndex;
-
-@end
-
-#endif // TARGET_OS_IPHONE
View
1,446 Code/UI/RKAbstractTableController.m
@@ -1,1446 +0,0 @@
-//
-// RKAbstractTableController.m
-// RestKit
-//
-// Created by Jeff Arena on 8/11/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 "RKAbstractTableController.h"
-#import "RKAbstractTableController_Internals.h"
-#import "RKMappingOperation.h"
-#import "RKLog.h"
-#import "RKErrors.h"
-#import "RKReachabilityObserver.h"
-#import "UIView+FindFirstResponder.h"
-#import "RKRefreshGestureRecognizer.h"
-#import "RKTableSection.h"
-
-// Define logging component
-#undef RKLogComponent
-#define RKLogComponent lcl_cRestKitUI
-
-/**
- Bounce pixels define how many pixels the cell swipe view is
- moved during the bounce animation
- */
-#define BOUNCE_PIXELS 5.0
-
-NSString * const RKTableControllerDidStartLoadNotification = @"RKTableControllerDidStartLoadNotification";
-NSString * const RKTableControllerDidFinishLoadNotification = @"RKTableControllerDidFinishLoadNotification";
-NSString * const RKTableControllerDidLoadObjectsNotification = @"RKTableControllerDidLoadObjectsNotification";
-NSString * const RKTableControllerDidLoadEmptyNotification = @"RKTableControllerDidLoadEmptyNotification";
-NSString * const RKTableControllerDidLoadErrorNotification = @"RKTableControllerDidLoadErrorNotification";
-NSString * const RKTableControllerDidBecomeOnline = @"RKTableControllerDidBecomeOnline";
-NSString * const RKTableControllerDidBecomeOffline = @"RKTableControllerDidBecomeOffline";
-
-static NSString *lastUpdatedDateDictionaryKey = @"lastUpdatedDateDictionaryKey";
-
-@interface RKAbstractTableController ()
-
-@property (nonatomic, retain) RKKeyboardScroller *keyboardScroller;
-
-@end
-
-
-@implementation RKAbstractTableController
-
-@synthesize delegate = _delegate;
-@synthesize viewController = _viewController;
-@synthesize tableView = _tableView;
-@synthesize defaultRowAnimation = _defaultRowAnimation;
-
-@synthesize objectLoader = _objectLoader;
-@synthesize objectManager = _objectManager;
-@synthesize cellMappings = _cellMappings;
-@synthesize autoRefreshFromNetwork = _autoRefreshFromNetwork;
-@synthesize autoRefreshRate = _autoRefreshRate;
-
-@synthesize state = _state;
-@synthesize error = _error;
-
-@synthesize imageForEmpty = _imageForEmpty;
-@synthesize imageForError = _imageForError;
-@synthesize imageForOffline = _imageForOffline;
-@synthesize loadingView = _loadingView;
-
-@synthesize variableHeightRows = _variableHeightRows;
-@synthesize showsHeaderRowsWhenEmpty = _showsHeaderRowsWhenEmpty;
-@synthesize showsFooterRowsWhenEmpty = _showsFooterRowsWhenEmpty;
-@synthesize pullToRefreshEnabled = _pullToRefreshEnabled;
-@synthesize headerItems = _headerItems;
-@synthesize footerItems = _footerItems;
-@synthesize canEditRows = _canEditRows;
-@synthesize canMoveRows = _canMoveRows;
-@synthesize autoResizesForKeyboard = _autoResizesForKeyboard;
-@synthesize emptyItem = _emptyItem;
-
-@synthesize onSelectCellForObjectAtIndexPath = _onSelectCellForObjectAtIndexPath;
-@synthesize onPrepareCellForObjectAtIndexPath = _onPrepareCellForObjectAtIndexPath;
-@synthesize onWillDisplayCellForObjectAtIndexPath = _onWillDisplayCellForObjectAtIndexPath;
-
-@synthesize cellSwipeViewsEnabled = _cellSwipeViewsEnabled;
-@synthesize cellSwipeView = _cellSwipeView;
-@synthesize swipeCell = _swipeCell;
-@synthesize animatingCellSwipe = _animatingCellSwipe;
-@synthesize swipeDirection = _swipeDirection;
-@synthesize swipeObject = _swipeObject;
-
-@synthesize showsOverlayImagesModally = _modalOverlay;
-@synthesize overlayFrame = _overlayFrame;
-@synthesize tableOverlayView = _tableOverlayView;
-@synthesize stateOverlayImageView = _stateOverlayImageView;
-@synthesize cache = _cache;
-@synthesize pullToRefreshHeaderView = _pullToRefreshHeaderView;
-
-@synthesize keyboardScroller = _keyboardScroller;
-
-#pragma mark - Instantiation
-
-+ (id)tableControllerWithTableView:(UITableView *)tableView
- forViewController:(UIViewController *)viewController
-{
- return [[[self alloc] initWithTableView:tableView viewController:viewController] autorelease];
-}
-
-+ (id)tableControllerForTableViewController:(UITableViewController *)tableViewController
-{
- return [self tableControllerWithTableView:tableViewController.tableView
- forViewController:tableViewController];
-}
-
-- (id)initWithTableView:(UITableView *)theTableView viewController:(UIViewController *)theViewController
-{
- NSAssert(theTableView, @"Cannot initialize a table view model with a nil tableView");
- NSAssert(theViewController, @"Cannot initialize a table view model with a nil viewController");
- self = [self init];
- if (self) {
- self.tableView = theTableView;
- _viewController = theViewController; // Assign directly to avoid side-effect of overloaded accessor method
- self.variableHeightRows = NO;
- self.defaultRowAnimation = UITableViewRowAnimationFade;
- self.overlayFrame = CGRectZero;
- self.showsOverlayImagesModally = YES;
- }
-
- return self;
-}
-
-- (id)init
-{
- self = [super init];
- if (self) {
- if ([self isMemberOfClass:[RKAbstractTableController class]]) {
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:[NSString stringWithFormat:@"%@ is abstract. Instantiate one its subclasses instead.",
- NSStringFromClass([self class])]
- userInfo:nil];
- }
-
- self.state = RKTableControllerStateNotYetLoaded;
- self.objectManager = [RKObjectManager sharedManager];
- _cellMappings = [RKTableViewCellMappings new];
-
- _headerItems = [NSMutableArray new];
- _footerItems = [NSMutableArray new];
- _showsHeaderRowsWhenEmpty = YES;
- _showsFooterRowsWhenEmpty = YES;
-
- // Setup autoRefreshRate to (effectively) never
- _autoRefreshFromNetwork = NO;
- _autoRefreshRate = NSTimeIntervalSince1970;
-
- // Setup key-value observing
- [self addObserver:self
- forKeyPath:@"state"
- options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
- context:nil];
- [self addObserver:self
- forKeyPath:@"error"
- options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
- context:nil];
- }
- return self;
-}
-
-- (void)dealloc
-{
- // Disconnect from the tableView
- if (_tableView.delegate == self) _tableView.delegate = nil;
- if (_tableView.dataSource == self) _tableView.dataSource = nil;
- _tableView = nil;
-
- // Remove overlay and pull-to-refresh subviews
- [_stateOverlayImageView removeFromSuperview];
- [_stateOverlayImageView release];
- _stateOverlayImageView = nil;
- [_tableOverlayView removeFromSuperview];
- [_tableOverlayView release];
- _tableOverlayView = nil;
-
- // Remove observers
- [self removeObserver:self forKeyPath:@"state"];
- [self removeObserver:self forKeyPath:@"error"];
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- // TODO: WTF? Get UI crashes when enabled...
-// [_objectManager.requestQueue abortRequestsWithDelegate:self];
- _objectLoader.delegate = nil;
- [_objectLoader release];
- _objectLoader = nil;
-
- // Blocks
- [_onSelectCellForObjectAtIndexPath release];
- [_onPrepareCellForObjectAtIndexPath release];
- [_onWillDisplayCellForObjectAtIndexPath release];
-
- [_cellMappings release];
- [_headerItems release];
- [_footerItems release];
- [_cellSwipeView release];
- [_swipeCell release];
- [_swipeObject release];
- [_emptyItem release];
- [super dealloc];
-}
-
-- (void)setTableView:(UITableView *)tableView
-{
- NSAssert(tableView, @"Cannot assign a nil tableView to the model");
- _tableView = tableView;
- _tableView.delegate = self;
- _tableView.dataSource = self;
-}
-
-- (void)setViewController:(UIViewController *)viewController
-{
- if ([viewController isKindOfClass:[UITableViewController class]]) {
- self.tableView = [(UITableViewController *)viewController tableView];
- }
-}
-
-- (void)setObjectManager:(RKObjectManager *)objectManager
-{
- NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
-
- // Remove observers
- if (_objectManager) {
- [notificationCenter removeObserver:self
- name:RKObjectManagerDidBecomeOfflineNotification
- object:_objectManager];
- [notificationCenter removeObserver:self
- name:RKObjectManagerDidBecomeOnlineNotification
- object:_objectManager];
- }
-
- _objectManager = objectManager;
-
- if (objectManager) {
- // Set observers
- [notificationCenter addObserver:self
- selector:@selector(objectManagerConnectivityDidChange:)
- name:RKObjectManagerDidBecomeOnlineNotification
- object:objectManager];
- [notificationCenter addObserver:self
- selector:@selector(objectManagerConnectivityDidChange:)
- name:RKObjectManagerDidBecomeOfflineNotification
- object:objectManager];
-
- // Initialize online/offline state (if it is known)
- if (objectManager.networkStatus != RKObjectManagerNetworkStatusUnknown) {
- if (objectManager.isOnline) {
- self.state &= ~RKTableControllerStateOffline;
- } else {
- self.state |= RKTableControllerStateOffline;
- }
- }
- }
-}
-
-- (void)setAutoResizesForKeyboard:(BOOL)autoResizesForKeyboard
-{
- if (_autoResizesForKeyboard != autoResizesForKeyboard) {
- _autoResizesForKeyboard = autoResizesForKeyboard;
- if (_autoResizesForKeyboard) {
- self.keyboardScroller = [[RKKeyboardScroller alloc] initWithViewController:self.viewController scrollView:self.tableView];
- [self.keyboardScroller release];
- } else {
- self.keyboardScroller = nil;
- }
- }
-}
-
-- (void)setAutoRefreshFromNetwork:(BOOL)autoRefreshFromNetwork
-{
- if (_autoRefreshFromNetwork != autoRefreshFromNetwork) {
- _autoRefreshFromNetwork = autoRefreshFromNetwork;
- if (_autoRefreshFromNetwork) {
- NSString *cachePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
- stringByAppendingPathComponent:@"RKAbstractTableControllerCache"];
- _cache = [[RKCache alloc] initWithPath:cachePath subDirectories:nil];
- } else {
- if (_cache) {
- [_cache invalidateAll];
- [_cache release];
- _cache = nil;
- }
- }
- }
-}
-
-- (void)setLoading:(BOOL)loading
-{
- if (loading) {
- self.state |= RKTableControllerStateLoading;
- } else {
- self.state &= ~RKTableControllerStateLoading;
- }
-}
-
-// NOTE: The loaded flag is handled specially. When loaded becomes NO,
-// we clear all other flags. In practice this should not happen outside of init.
-- (void)setLoaded:(BOOL)loaded
-{
- if (loaded) {
- self.state &= ~RKTableControllerStateNotYetLoaded;
- } else {
- self.state = RKTableControllerStateNotYetLoaded;
- }
-}
-
-- (void)setEmpty:(BOOL)empty
-{
- if (empty) {
- self.state |= RKTableControllerStateEmpty;
- } else {
- self.state &= ~RKTableControllerStateEmpty;
- }
-}
-
-- (void)setOffline:(BOOL)offline
-{
- if (offline) {
- self.state |= RKTableControllerStateOffline;
- } else {
- self.state &= ~RKTableControllerStateOffline;
- }
-}
-
-- (void)setErrorState:(BOOL)error
-{
- if (error) {
- self.state |= RKTableControllerStateError;
- } else {
- self.state &= ~RKTableControllerStateError;
- }
-}
-
-- (void)objectManagerConnectivityDidChange:(NSNotification *)notification
-{
- RKLogTrace(@"%@ received network status change notification: %@", self, [notification name]);
- [self setOffline:!self.objectManager.isOnline];
-}
-
-#pragma mark - Abstract Methods
-
-- (BOOL)isConsideredEmpty
-{
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
- userInfo:nil];
-}
-
-- (NSUInteger)sectionCount
-{
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
- userInfo:nil];
-}
-
-- (NSUInteger)rowCount
-{
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
- userInfo:nil];
-}
-
-- (id)objectForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
- userInfo:nil];
-}
-
-- (NSIndexPath *)indexPathForObject:(id)object
-{
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
- userInfo:nil];
-}
-
-- (NSUInteger)numberOfRowsInSection:(NSUInteger)index
-{
- @throw [NSException exceptionWithName:NSInternalInconsistencyException
- reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
- userInfo:nil];
-}
-
-#pragma mark - Cell Mappings
-
-- (void)mapObjectsWithClass:(Class)objectClass toTableCellsWithMapping:(RKTableViewCellMapping *)cellMapping
-{
- // TODO: Should we raise an exception/throw a warning if you are doing class mapping for a type
- // that implements a cellMapping instance method? Maybe a class declaration overrides
- [_cellMappings setCellMapping:cellMapping forClass:objectClass];
-}
-
-- (void)mapObjectsWithClassName:(NSString *)objectClassName toTableCellsWithMapping:(RKTableViewCellMapping *)cellMapping
-{
- [self mapObjectsWithClass:NSClassFromString(objectClassName) toTableCellsWithMapping:cellMapping];
-}
-
-- (RKTableViewCellMapping *)cellMappingForObjectAtIndexPath:(NSIndexPath *)indexPath
-{
- NSAssert(indexPath, @"Cannot lookup cell mapping for object with a nil indexPath");
- id object = [self objectForRowAtIndexPath:indexPath];
- return [self.cellMappings cellMappingForObject:object];
-}
-
-- (UITableViewCell *)cellForObject:(id)object
-{
- NSIndexPath *indexPath = [self indexPathForObject:object];
- return indexPath ? [self.tableView cellForRowAtIndexPath:indexPath] : nil;
-}
-
-#pragma mark - Header and Footer Rows
-
-- (void)addHeaderRowForItem:(RKTableItem *)tableItem
-{
- [_headerItems addObject:tableItem];
-}
-
-- (void)addFooterRowForItem:(RKTableItem *)tableItem
-{
- [_footerItems addObject:tableItem];
-}
-
-- (void)addHeaderRowWithMapping:(RKTableViewCellMapping *)cellMapping
-{
- RKTableItem *tableItem = [RKTableItem tableItem];
- tableItem.cellMapping = cellMapping;
- [self addHeaderRowForItem:tableItem];
-}
-
-- (void)addFooterRowWithMapping:(RKTableViewCellMapping *)cellMapping
-{
- RKTableItem *tableItem = [RKTableItem tableItem];
- tableItem.cellMapping = cellMapping;
- [self addFooterRowForItem:tableItem];
-}
-
-- (void)removeAllHeaderRows
-{
- [_headerItems removeAllObjects];
-}
-
-- (void)removeAllFooterRows
-{
- [_footerItems removeAllObjects];
-}
-
-#pragma mark - UITableViewDataSource methods
-
-- (UITableViewCell *)cellFromCellMapping:(RKTableViewCellMapping *)cellMapping
-{
- RKLogTrace(@"About to dequeue reusable cell using self.reuseIdentifier=%@", cellMapping.reuseIdentifier);
- UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellMapping.reuseIdentifier];
- if (cell) {
- RKLogTrace(@"Dequeued existing cell object for reuse identifier '%@': %@", cellMapping.reuseIdentifier, cell);
- } else {
- cell = [[[cellMapping.objectClass alloc] initWithStyle:cellMapping.style
- reuseIdentifier:cellMapping.reuseIdentifier] autorelease];
- RKLogTrace(@"Failed to dequeue existing cell object for reuse identifier '%@', instantiated new cell: %@", cellMapping.reuseIdentifier, cell);
- }
-
- if (cellMapping.managesCellAttributes) {
- cell.accessoryType = cellMapping.accessoryType;
- cell.selectionStyle = cellMapping.selectionStyle;
- }
-
- // Fire the prepare callbacks
- for (void (^block)(UITableViewCell *) in cellMapping.prepareCellBlocks) {
- block(cell);
- }
-
- return cell;
-}
-
-- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- NSAssert(theTableView == self.tableView, @"tableView:cellForRowAtIndexPath: invoked with inappropriate tableView: %@", theTableView);
- NSAssert(indexPath, @"Cannot retrieve cell for nil indexPath");
- id mappableObject = [self objectForRowAtIndexPath:indexPath];
- NSAssert(mappableObject, @"Cannot build a tableView cell without an object");
-
- RKTableViewCellMapping* cellMapping = [self.cellMappings cellMappingForObject:mappableObject];
- NSAssert(cellMapping, @"Cannot build a tableView cell for object %@: No cell mapping defined for objects of type '%@'", mappableObject, NSStringFromClass([mappableObject class]));
-
- UITableViewCell *cell = [self cellFromCellMapping:cellMapping];
- NSAssert(cell, @"Cell mapping failed to dequeue or allocate a tableViewCell for object: %@", mappableObject);
-
- // Map the object state into the cell
- RKMappingOperation* mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:mappableObject destinationObject:cell mapping:cellMapping];
- NSError* error = nil;
- BOOL success = [mappingOperation performMapping:&error];
- [mappingOperation release];
-
- // NOTE: If there is no mapping work performed, but no error is generated then
- // we consider the operation a success. It is common for table cells to not contain
- // any dynamically mappable content (i.e. header/footer rows, banners, etc.)
- if (success == NO && error != nil) {
- RKLogError(@"Failed table cell mapping: %@", error);
- }
-
- if (self.onPrepareCellForObjectAtIndexPath) {
- self.onPrepareCellForObjectAtIndexPath(cell, mappableObject, indexPath);
- }
-
- RKLogTrace(@"%@ cellForRowAtIndexPath:%@ = %@", self, indexPath, cell);
- return cell;
-}
-
-- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-{
- [NSException raise:@"Must be implemented in a subclass!" format:@"sectionCount must be implemented with a subclass"];
- return 0;
-}
-
-#pragma mark - UITableViewDelegate methods
-
-- (void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
-{
- NSAssert(theTableView == self.tableView, @"tableView:didSelectRowAtIndexPath: invoked with inappropriate tableView: %@", theTableView);
- RKLogTrace(@"%@: Row at indexPath %@ selected for tableView %@", self, indexPath, theTableView);
-
- id object = [self objectForRowAtIndexPath:indexPath];
-
- UITableViewCell *cell = [theTableView cellForRowAtIndexPath:indexPath];
- RKTableViewCellMapping *cellMapping = [_cellMappings cellMappingForObject:object];
-
- // NOTE: Handle deselection first as the onSelectCell processing may result in the tableView
- // being reloaded and our instances invalidated
- if (cellMapping.deselectsRowOnSelection) {
- [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
- }
-
- if (cellMapping.onSelectCell) {
- cellMapping.onSelectCell();
- }
-
- if (cellMapping.onSelectCellForObjectAtIndexPath) {
- RKLogTrace(@"%@: Invoking onSelectCellForObjectAtIndexPath block with cellMapping %@ for object %@ at indexPath = %@", self, cell, object, indexPath);
- cellMapping.onSelectCellForObjectAtIndexPath(cell, object, indexPath);
- }
-
- // Table level selection callbacks
- if (self.onSelectCellForObjectAtIndexPath) {
- self.onSelectCellForObjectAtIndexPath(cell, object, indexPath);
- }
-
- if ([self.delegate respondsToSelector:@selector(tableController:didSelectCell:forObject:atIndexPath:)]) {
- [self.delegate tableController:self didSelectCell:cell forObject:object atIndexPath:indexPath];
- }
-}
-
-- (void)tableView:(UITableView *)theTableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
-{
- NSAssert(theTableView == self.tableView, @"tableView:didSelectRowAtIndexPath: invoked with inappropriate tableView: %@", theTableView);
- cell.hidden = NO;
- id mappableObject = [self objectForRowAtIndexPath:indexPath];
- RKTableViewCellMapping *cellMapping = [self.cellMappings cellMappingForObject:mappableObject];
- if (cellMapping.onCellWillAppearForObjectAtIndexPath) {
- cellMapping.onCellWillAppearForObjectAtIndexPath(cell, mappableObject, indexPath);
- }
-
- if (self.onWillDisplayCellForObjectAtIndexPath) {
- self.onWillDisplayCellForObjectAtIndexPath(cell, mappableObject, indexPath);
- }
-
- if ([self.delegate respondsToSelector:@selector(tableController:willDisplayCell:forObject:atIndexPath:)]) {
- [self.delegate tableController:self willDisplayCell:cell forObject:mappableObject atIndexPath:indexPath];
- }
-
- // Informal protocol
- // TODO: Needs documentation!!!
- SEL willDisplaySelector = @selector(willDisplayInTableViewCell:);
- if ([mappableObject respondsToSelector:willDisplaySelector]) {
- [mappableObject performSelector:willDisplaySelector withObject:cell];
- }
-
- // Handle hiding header/footer rows when empty
- if ([self isEmpty]) {
- if (! self.showsHeaderRowsWhenEmpty && [_headerItems containsObject:mappableObject]) {
- cell.hidden = YES;
- }
-
- if (! self.showsFooterRowsWhenEmpty && [_footerItems containsObject:mappableObject]) {
- cell.hidden = YES;
- }
- } else {
- if (self.emptyItem && [self.emptyItem isEqual:mappableObject]) {
- cell.hidden = YES;
- }
- }
-}
-
-// Variable height support
-
-- (CGFloat)tableView:(UITableView *)theTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- if (self.variableHeightRows) {
- RKTableViewCellMapping *cellMapping = [self cellMappingForObjectAtIndexPath:indexPath];
-
- if (cellMapping.heightOfCellForObjectAtIndexPath) {
- id object = [self objectForRowAtIndexPath:indexPath];
- CGFloat height = cellMapping.heightOfCellForObjectAtIndexPath(object, indexPath);
- RKLogTrace(@"Variable row height configured for tableView. Height via block invocation for row at indexPath '%@' = %f", indexPath, cellMapping.rowHeight);
- return height;
- } else {
- RKLogTrace(@"Variable row height configured for tableView. Height for row at indexPath '%@' = %f", indexPath, cellMapping.rowHeight);
- return cellMapping.rowHeight;
- }
- }
-
- RKLogTrace(@"Uniform row height configured for tableView. Table view row height = %f", self.tableView.rowHeight);
- return self.tableView.rowHeight;
-}
-
-- (void)tableView:(UITableView *)theTableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
-{
- RKTableViewCellMapping *cellMapping = [self cellMappingForObjectAtIndexPath:indexPath];
- if (cellMapping.onTapAccessoryButtonForObjectAtIndexPath) {
- RKLogTrace(@"Found a block for tableView:accessoryButtonTappedForRowWithIndexPath: Executing...");
- UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:indexPath];
- id object = [self objectForRowAtIndexPath:indexPath];
- cellMapping.onTapAccessoryButtonForObjectAtIndexPath(cell, object, indexPath);
- }
-}
-
-- (NSString *)tableView:(UITableView *)theTableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- RKTableViewCellMapping *cellMapping = [self cellMappingForObjectAtIndexPath:indexPath];
- if (cellMapping.titleForDeleteButtonForObjectAtIndexPath) {
- RKLogTrace(@"Found a block for tableView:titleForDeleteConfirmationButtonForRowAtIndexPath: Executing...");
- UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:indexPath];
- id object = [self objectForRowAtIndexPath:indexPath];
- return cellMapping.titleForDeleteButtonForObjectAtIndexPath(cell, object, indexPath);
- }
- return NSLocalizedString(@"Delete", nil);
-}
-
-- (UITableViewCellEditingStyle)tableView:(UITableView *)theTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- if (_canEditRows) {
- RKTableViewCellMapping *cellMapping = [self cellMappingForObjectAtIndexPath:indexPath];
- UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:indexPath];
- if (cellMapping.editingStyleForObjectAtIndexPath) {
- RKLogTrace(@"Found a block for tableView:editingStyleForRowAtIndexPath: Executing...");
- id object = [self objectForRowAtIndexPath:indexPath];
- return cellMapping.editingStyleForObjectAtIndexPath(cell, object, indexPath);
- }
- return UITableViewCellEditingStyleDelete;
- }
- return UITableViewCellEditingStyleNone;
-}
-
-- (void)tableView:(UITableView *)theTableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
-{
- if ([self.delegate respondsToSelector:@selector(tableController:didEndEditing:atIndexPath:)]) {
- id object = [self objectForRowAtIndexPath:indexPath];
- [self.delegate tableController:self didEndEditing:object atIndexPath:indexPath];
- }
-}
-
-- (void)tableView:(UITableView *)theTableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
-{
- if ([self.delegate respondsToSelector:@selector(tableController:willBeginEditing:atIndexPath:)]) {
- id object = [self objectForRowAtIndexPath:indexPath];
- [self.delegate tableController:self willBeginEditing:object atIndexPath:indexPath];
- }
-}
-
-- (NSIndexPath *)tableView:(UITableView *)theTableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
-{
- if (_canMoveRows) {
- RKTableViewCellMapping *cellMapping = [self cellMappingForObjectAtIndexPath:sourceIndexPath];
- if (cellMapping.targetIndexPathForMove) {
- RKLogTrace(@"Found a block for tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: Executing...");
- UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:sourceIndexPath];
- id object = [self objectForRowAtIndexPath:sourceIndexPath];
- return cellMapping.targetIndexPathForMove(cell, object, sourceIndexPath, proposedDestinationIndexPath);
- }
- }
- return proposedDestinationIndexPath;
-}
-
-- (NSIndexPath *)tableView:(UITableView *)theTableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
-{
- [self removeSwipeView:YES];
- return indexPath;
-}
-
-#pragma mark - Network Table Loading
-
-- (void)cancelLoad
-{
- [self.objectLoader cancel];
-}
-
-- (NSDate *)lastUpdatedDate
-{
- if (! self.objectLoader) {
- return nil;
- }
-
- if (_autoRefreshFromNetwork) {
- NSAssert(_cache, @"Found a nil cache when trying to read our last loaded time");
- NSDictionary *lastUpdatedDates = [_cache dictionaryForCacheKey:lastUpdatedDateDictionaryKey];
- RKLogTrace(@"Last updated dates dictionary retrieved from tableController cache: %@", lastUpdatedDates);
- if (lastUpdatedDates) {
- NSString *absoluteURLString = [self.objectLoader.URL absoluteString];
- NSNumber *lastUpdatedTimeIntervalSince1970 = (NSNumber *)[lastUpdatedDates objectForKey:absoluteURLString];
- if (absoluteURLString && lastUpdatedTimeIntervalSince1970) {
- return [NSDate dateWithTimeIntervalSince1970:[lastUpdatedTimeIntervalSince1970 doubleValue]];
- }
- }
- }
- return nil;
-}
-
-- (BOOL)isAutoRefreshNeeded
-{
- BOOL isAutoRefreshNeeded = NO;
- if (_autoRefreshFromNetwork) {
- isAutoRefreshNeeded = YES;
- NSDate *lastUpdatedDate = [self lastUpdatedDate];
- RKLogTrace(@"Last updated: %@", lastUpdatedDate);
- if (lastUpdatedDate) {
- RKLogTrace(@"-timeIntervalSinceNow=%f, autoRefreshRate=%f",
- -[lastUpdatedDate timeIntervalSinceNow], _autoRefreshRate);
- isAutoRefreshNeeded = (-[lastUpdatedDate timeIntervalSinceNow] > _autoRefreshRate);
- }
- }
- return isAutoRefreshNeeded;
-}
-
-#pragma mark - RKRequestDelegate & RKObjectLoaderDelegate methods
-
-- (void)requestDidStartLoad:(RKRequest *)request
-{
- RKLogTrace(@"tableController %@ started loading.", self);
- [self didStartLoad];
-}
-
-- (void)requestDidCancelLoad:(RKRequest *)request
-{
- RKLogTrace(@"tableController %@ cancelled loading.", self);
- self.loading = NO;
-
- if ([self.delegate respondsToSelector:@selector(tableControllerDidCancelLoad:)]) {
- [self.delegate tableControllerDidCancelLoad:self];
- }
-}
-
-- (void)requestDidTimeout:(RKRequest *)request
-{
- RKLogTrace(@"tableController %@ timed out while loading.", self);
- self.loading = NO;
-}
-
-- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response
-{
- RKLogTrace(@"tableController %@ finished loading.", self);
-
- // Updated the lastUpdatedDate dictionary using the URL of the request
- if (self.autoRefreshFromNetwork) {
- NSAssert(_cache, @"Found a nil cache when trying to save our last loaded time");
- NSMutableDictionary *lastUpdatedDates = [[_cache dictionaryForCacheKey:lastUpdatedDateDictionaryKey] mutableCopy];
- if (lastUpdatedDates) {
- [_cache invalidateEntry:lastUpdatedDateDictionaryKey];
- } else {
- lastUpdatedDates = [[NSMutableDictionary alloc] init];
- }
- NSNumber *timeIntervalSince1970 = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]];
- RKLogTrace(@"Setting timeIntervalSince1970=%@ for URL %@", timeIntervalSince1970, [request.URL absoluteString]);
- [lastUpdatedDates setObject:timeIntervalSince1970
- forKey:[request.URL absoluteString]];
- [_cache writeDictionary:lastUpdatedDates withCacheKey:lastUpdatedDateDictionaryKey];
- [lastUpdatedDates release];
- }
-}
-
-- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error
-{
- RKLogError(@"tableController %@ failed network load with error: %@", self, error);
- [self didFailLoadWithError:error];
-}
-
-- (void)objectLoaderDidFinishLoading:(RKObjectLoader *)objectLoader
-{
- if ([self.delegate respondsToSelector:@selector(tableController:didLoadTableWithObjectLoader:)]) {
- [self.delegate tableController:self didLoadTableWithObjectLoader:objectLoader];
- }
-
- [objectLoader reset];
- [self didFinishLoad];
-}
-
-- (void)didStartLoad
-{
- self.loading = YES;
-}
-
-- (void)didFailLoadWithError:(NSError *)error
-{
- self.error = error;
- [self didFinishLoad];
-}
-
-- (void)didFinishLoad
-{
- self.empty = [self isConsideredEmpty];
- self.loading = [self.objectLoader isLoading]; // Mutate loading state after we have adjusted empty
- self.loaded = YES;
-
- if (![self isEmpty] && ![self isLoading]) {
- [[NSNotificationCenter defaultCenter] postNotificationName:RKTableControllerDidLoadObjectsNotification object:self];
- }
-
- if (self.delegate && [_delegate respondsToSelector:@selector(tableControllerDidFinalizeLoad:)]) {
- [self.delegate performSelector:@selector(tableControllerDidFinalizeLoad:) withObject:self];
- }
-}
-
-#pragma mark - Table Overlay Views
-
-- (UIImage *)imageForState:(RKTableControllerState)state
-{
- switch (state) {
- case RKTableControllerStateNormal:
- case RKTableControllerStateLoading:
- case RKTableControllerStateNotYetLoaded:
- break;
-
- case RKTableControllerStateEmpty:
- return self.imageForEmpty;
- break;
-
- case RKTableControllerStateError:
- return self.imageForError;
- break;
-
- case RKTableControllerStateOffline:
- return self.imageForOffline;
- break;
-
- default:
- break;
- }
-
- return nil;
-}
-
-- (UIImage *)overlayImage
-{
- return _stateOverlayImageView.image;
-}
-
-// Adds an overlay view above the table
-- (void)addToOverlayView:(UIView *)view modally:(BOOL)modally
-{
- if (! _tableOverlayView) {
- CGRect overlayFrame = CGRectIsEmpty(self.overlayFrame) ? self.tableView.frame : self.overlayFrame;
- _tableOverlayView = [[UIView alloc] initWithFrame:overlayFrame];
- _tableOverlayView.autoresizesSubviews = YES;
- _tableOverlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
- NSInteger tableIndex = [_tableView.superview.subviews indexOfObject:_tableView];
- if (tableIndex != NSNotFound) {
- [_tableView.superview addSubview:_tableOverlayView];
- }
- }
-
- // When modal, we enable user interaction to catch & discard events on the overlay and its subviews
- _tableOverlayView.userInteractionEnabled = modally;
- view.userInteractionEnabled = modally;
-
- if (CGRectIsEmpty(view.frame)) {
- view.frame = _tableOverlayView.bounds;
-
- // Center it in the overlay
- view.center = _tableOverlayView.center;
- }
-
- [_tableOverlayView addSubview:view];
-}
-
-- (void)resetOverlayView
-{
- if (_stateOverlayImageView && _stateOverlayImageView.image == nil) {
- [_stateOverlayImageView removeFromSuperview];
- }
- if (_tableOverlayView && _tableOverlayView.subviews.count == 0) {
- [_tableOverlayView removeFromSuperview];
- [_tableOverlayView release];
- _tableOverlayView = nil;
- }
-}
-
-- (void)addSubviewOverTableView:(UIView *)view
-{
- NSInteger tableIndex = [_tableView.superview.subviews
- indexOfObject:_tableView];
- if (NSNotFound != tableIndex) {
- [_tableView.superview addSubview:view];
- }
-}
-
-- (BOOL)removeImageFromOverlay:(UIImage *)image
-{
- if (image && _stateOverlayImageView.image == image) {
- _stateOverlayImageView.image = nil;
- return YES;
- }
- return NO;
-}
-
-- (void)showImageInOverlay:(UIImage *)image
-{
- NSAssert(self.tableView, @"Cannot add an overlay image to a nil tableView");
- if (! _stateOverlayImageView) {
- _stateOverlayImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
- _stateOverlayImageView.opaque = YES;
- _stateOverlayImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
- _stateOverlayImageView.contentMode = UIViewContentModeCenter;
- }
- _stateOverlayImageView.image = image;
- [self addToOverlayView:_stateOverlayImageView modally:self.showsOverlayImagesModally];
-}
-
-- (void)removeImageOverlay
-{
- _stateOverlayImageView.image = nil;
- [_stateOverlayImageView removeFromSuperview];
- [self resetOverlayView];
-}
-
-- (void)setImageForEmpty:(UIImage *)imageForEmpty
-{
- [imageForEmpty retain];
- BOOL imageRemoved = [self removeImageFromOverlay:_imageForEmpty];
- [_imageForEmpty release];
- _imageForEmpty = imageForEmpty;
- if (imageRemoved) [self showImageInOverlay:_imageForEmpty];
-}
-
-- (void)setImageForError:(UIImage *)imageForError
-{
- [imageForError retain];
- BOOL imageRemoved = [self removeImageFromOverlay:_imageForError];
- [_imageForError release];
- _imageForError = imageForError;
- if (imageRemoved) [self showImageInOverlay:_imageForError];
-}
-
-- (void)setImageForOffline:(UIImage *)imageForOffline
-{
- [imageForOffline retain];
- BOOL imageRemoved = [self removeImageFromOverlay:_imageForOffline];
- [_imageForOffline release];
- _imageForOffline = imageForOffline;
- if (imageRemoved) [self showImageInOverlay:_imageForOffline];
-}
-
-- (void)setLoadingView:(UIView *)loadingView
-{
- [loadingView retain];
- BOOL viewRemoved = (_loadingView.superview != nil);
- [_loadingView removeFromSuperview];
- [self resetOverlayView];
- [_loadingView release];
- _loadingView = loadingView;
- if (viewRemoved) [self addToOverlayView:_loadingView modally:NO];
-}
-
-#pragma mark - KVO & Table States
-
-- (BOOL)isLoading
-{
- return (self.state & RKTableControllerStateLoading) != 0;
-}
-
-- (BOOL)isLoaded
-{
- return (self.state & RKTableControllerStateNotYetLoaded) == 0;
-// return self.state != RKTableControllerStateNotYetLoaded;
-}
-
-- (BOOL)isOffline
-{
- return (self.state & RKTableControllerStateOffline) != 0;
-}
-- (BOOL)isOnline
-{
- return ![self isOffline];
-}
-
-- (BOOL)isError
-{
- return (self.state & RKTableControllerStateError) != 0;
-}
-
-- (BOOL)isEmpty
-{
- return (self.state & RKTableControllerStateEmpty) != 0;
-}
-
-- (void)isLoadingDidChange
-{
- if ([self isLoading]) {
- if ([self.delegate respondsToSelector:@selector(tableControllerDidStartLoad:)]) {
- [self.delegate tableControllerDidStartLoad:self];
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName:RKTableControllerDidStartLoadNotification object:self];
-
- if (self.loadingView) {
- [self addToOverlayView:self.loadingView modally:NO];
- }
- } else {
- if ([self.delegate respondsToSelector:@selector(tableControllerDidFinishLoad:)]) {
- [self.delegate tableControllerDidFinishLoad:self];
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName:RKTableControllerDidFinishLoadNotification object:self];
-
- if (self.loadingView) {
- [self.loadingView removeFromSuperview];
- [self resetOverlayView];
- }
-
- [self resetPullToRefreshRecognizer];
- }
-
- // We don't want any image overlays applied until loading is finished
- _stateOverlayImageView.hidden = [self isLoading];
-}
-
-- (void)isLoadedDidChange
-{
- if ([self isLoaded]) {
- RKLogDebug(@"%@: is now loaded.", self);
- } else {
- RKLogDebug(@"%@: is NOT loaded.", self);
- }
-}
-
-- (void)isErrorDidChange
-{
- if ([self isError]) {
- if ([self.delegate respondsToSelector:@selector(tableController:didFailLoadWithError:)]) {
- [self.delegate tableController:self didFailLoadWithError:self.error];
- }
-
- NSDictionary *userInfo = [NSDictionary dictionaryWithObject:self.error forKey:RKErrorNotificationErrorKey];
- [[NSNotificationCenter defaultCenter] postNotificationName:RKTableControllerDidLoadErrorNotification object:self userInfo:userInfo];
- }
-}
-
-- (void)isEmptyDidChange
-{
- if ([self isEmpty]) {
- if ([self.delegate respondsToSelector:@selector(tableControllerDidBecomeEmpty:)]) {
- [self.delegate tableControllerDidBecomeEmpty:self];
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName:RKTableControllerDidLoadEmptyNotification object:self];
- }
-}
-
-- (void)isOnlineDidChange
-{
- if ([self isOnline]) {
- // We just transitioned to online
- if ([self.delegate respondsToSelector:@selector(tableControllerDidBecomeOnline:)]) {
- [self.delegate tableControllerDidBecomeOnline:self];
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName:RKTableControllerDidBecomeOnline object:self];
- } else {
- // We just transitioned to offline
- if ([self.delegate respondsToSelector:@selector(tableControllerDidBecomeOffline:)]) {
- [self.delegate tableControllerDidBecomeOffline:self];
- }
-
- [[NSNotificationCenter defaultCenter] postNotificationName:RKTableControllerDidBecomeOffline object:self];
- }
-}
-
-- (void)updateTableViewForStateChange:(NSDictionary *)change
-{
- RKTableControllerState oldState = [[change valueForKey:NSKeyValueChangeOldKey] integerValue];
- RKTableControllerState newState = [[change valueForKey:NSKeyValueChangeNewKey] integerValue];
-
- // Determine state transitions
- BOOL loadedChanged = ((oldState ^ newState) & RKTableControllerStateNotYetLoaded);
- BOOL emptyChanged = ((oldState ^ newState) & RKTableControllerStateEmpty);
- BOOL offlineChanged = ((oldState ^ newState) & RKTableControllerStateOffline);
- BOOL loadingChanged = ((oldState ^ newState) & RKTableControllerStateLoading);
- BOOL errorChanged = ((oldState ^ newState) & RKTableControllerStateError);
-
- if (loadedChanged) [self isLoadedDidChange];
- if (emptyChanged) [self isEmptyDidChange];
- if (offlineChanged) [self isOnlineDidChange];
- if (errorChanged) [self isErrorDidChange];
- if (loadingChanged) [self isLoadingDidChange];
-
- // Clear the image from the overlay
- _stateOverlayImageView.image = nil;
-
- // Determine the appropriate overlay image to display (if any)
- if (self.state == RKTableControllerStateNormal) {
- [self removeImageOverlay];
- } else {
- if ([self isLoading]) {
- // During a load we don't adjust the overlay
- return;
- }
-
- // Though the table can be in more than one state, we only
- // want to display a single overlay image.
- if ([self isOffline] && self.imageForOffline) {
- [self showImageInOverlay:self.imageForOffline];
- } else if ([self isError] && self.imageForError) {
- [self showImageInOverlay:self.imageForError];
- } else if ([self isEmpty] && self.imageForEmpty) {
- [self showImageInOverlay:self.imageForEmpty];
- }
- }
-
- // Remove the overlay if no longer in use
- [self resetOverlayView];
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
-{
- if ([keyPath isEqualToString:@"state"]) {
- [self updateTableViewForStateChange:change];
- } else if ([keyPath isEqualToString:@"error"]) {
- [self setErrorState:(self.error != nil)];
- }
-}
-
-#pragma mark - Pull to Refresh
-
-- (RKRefreshGestureRecognizer *)pullToRefreshGestureRecognizer
-{
- RKRefreshGestureRecognizer *refreshRecognizer = nil;
- for (RKRefreshGestureRecognizer *recognizer in self.tableView.gestureRecognizers) {
- if ([recognizer isKindOfClass:[RKRefreshGestureRecognizer class]]) {
- refreshRecognizer = recognizer;
- break;
- }
- }
- return refreshRecognizer;
-}
-
-- (void)setPullToRefreshEnabled:(BOOL)pullToRefreshEnabled
-{
- RKRefreshGestureRecognizer *recognizer = nil;
- if (pullToRefreshEnabled) {
- recognizer = [[[RKRefreshGestureRecognizer alloc] initWithTarget:self action:@selector(pullToRefreshStateChanged:)] autorelease];
- [self.tableView addGestureRecognizer:recognizer];
- }
- else {
- recognizer = [self pullToRefreshGestureRecognizer];
- if (recognizer)
- [self.tableView removeGestureRecognizer:recognizer];
- }
- _pullToRefreshEnabled = pullToRefreshEnabled;
-}
-
-- (void)pullToRefreshStateChanged:(UIGestureRecognizer *)gesture
-{
- if (gesture.state == UIGestureRecognizerStateRecognized) {
- if ([self pullToRefreshDataSourceIsLoading:gesture])
- return;
- RKLogDebug(@"%@: pull to refresh triggered from gesture: %@", self, gesture);
- if (self.objectLoader) {
- [self.objectLoader reset];
- [self.objectLoader send];
- }
- }
-}
-
-- (void)resetPullToRefreshRecognizer
-{
- RKRefreshGestureRecognizer *recognizer = [self pullToRefreshGestureRecognizer];
- if (recognizer)
- [recognizer setRefreshState:RKRefreshIdle];
-}
-
-- (BOOL)pullToRefreshDataSourceIsLoading:(UIGestureRecognizer *)gesture
-{
- // If we have already been loaded and we are loading again, a refresh is taking place...
- return [self isLoaded] && [self isLoading] && [self isOnline];
-}
-
-- (NSDate *)pullToRefreshDataSourceLastUpdated:(UIGestureRecognizer *)gesture
-{
- NSDate *dataSourceLastUpdated = [self lastUpdatedDate];
- return dataSourceLastUpdated ? dataSourceLastUpdated : [NSDate date];
-}
-
-#pragma mark - Cell Swipe Menu Methods
-
-- (void)setupSwipeGestureRecognizers
-{
- // Setup a right swipe gesture recognizer
- UISwipeGestureRecognizer *rightSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRight:)];
- rightSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
- [self.tableView addGestureRecognizer:rightSwipeGestureRecognizer];
- [rightSwipeGestureRecognizer release];
-
- // Setup a left swipe gesture recognizer
- UISwipeGestureRecognizer *leftSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeLeft:)];
- leftSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
- [self.tableView addGestureRecognizer:leftSwipeGestureRecognizer];
- [leftSwipeGestureRecognizer release];
-}
-
-- (void)removeSwipeGestureRecognizers
-{
- for (UIGestureRecognizer *recognizer in self.tableView.gestureRecognizers) {
- if ([recognizer isKindOfClass:[UISwipeGestureRecognizer class]]) {
- [self.tableView removeGestureRecognizer:recognizer];
- }
- }
-}
-
-- (void)setCanEditRows:(BOOL)canEditRows
-{
- NSAssert(!_cellSwipeViewsEnabled, @"Table model cannot be made editable when cell swipe menus are enabled");
- _canEditRows = canEditRows;
-}
-
-- (void)setCellSwipeViewsEnabled:(BOOL)cellSwipeViewsEnabled
-{
- NSAssert(!_canEditRows, @"Cell swipe menus cannot be enabled for editable tableModels");
- if (cellSwipeViewsEnabled) {
- [self setupSwipeGestureRecognizers];
- } else {
- [self removeSwipeView:YES];
- [self removeSwipeGestureRecognizers];
- }
- _cellSwipeViewsEnabled = cellSwipeViewsEnabled;
-}
-
-- (void)swipe:(UISwipeGestureRecognizer *)recognizer direction:(UISwipeGestureRecognizerDirection)direction
-{
- if (_cellSwipeViewsEnabled && recognizer && recognizer.state == UIGestureRecognizerStateEnded) {
- CGPoint location = [recognizer locationInView:self.tableView];
- NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
- UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
- id object = [self objectForRowAtIndexPath:indexPath];
-
- if (cell.frame.origin.x != 0) {
- [self removeSwipeView:YES];
- return;
- }
-
- [self removeSwipeView:NO];
-
- if (cell != _swipeCell && !_animatingCellSwipe) {
- [self addSwipeViewTo:cell withObject:object direction:direction];
- }
- }
-}
-
-- (void)swipeLeft:(UISwipeGestureRecognizer *)recognizer
-{
- [self swipe:recognizer direction:UISwipeGestureRecognizerDirectionLeft];
-}
-
-- (void)swipeRight:(UISwipeGestureRecognizer *)recognizer
-{
- [self swipe:recognizer direction:UISwipeGestureRecognizerDirectionRight];
-}
-
-- (void)addSwipeViewTo:(UITableViewCell *)cell withObject:(id)object direction:(UISwipeGestureRecognizerDirection)direction
-{
- if (_cellSwipeViewsEnabled) {
- NSAssert(cell, @"Cannot process swipe view with nil cell");
- NSAssert(object, @"Cannot process swipe view with nil object");
-
- _cellSwipeView.frame = cell.frame;
-
- if ([self.delegate respondsToSelector:@selector(tableController:willAddSwipeView:toCell:forObject:)]) {
- [self.delegate tableController:self
- willAddSwipeView:_cellSwipeView
- toCell:cell
- forObject:object];
- }
-
- [self.tableView insertSubview:_cellSwipeView belowSubview:cell];
-
- _swipeCell = [cell retain];
- _swipeObject = [object retain];
- _swipeDirection = direction;
-
- CGRect cellFrame = cell.frame;
-
- _cellSwipeView.frame = CGRectMake(0, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
-
- _animatingCellSwipe = YES;
- [UIView beginAnimations:nil context:nil];
- [UIView setAnimationDuration:0.2];
- [UIView setAnimationDelegate:self];
- [UIView setAnimationDidStopSelector:@selector(animationDidStopAddingSwipeView:finished:context:)];
-
- cell.frame = CGRectMake(direction == UISwipeGestureRecognizerDirectionRight ? cellFrame.size.width : -cellFrame.size.width, cellFrame.origin.y, cellFrame.size.width, cellFrame.size.height);
- [UIView commitAnimations];
- }
-}
-
-- (void)animationDidStopAddingSwipeView:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
-{
- _animatingCellSwipe = NO;
-}
-
-- (void)removeSwipeView:(BOOL)animated
-{
- if (!_cellSwipeViewsEnabled || !_swipeCell || _animatingCellSwipe) {
- RKLogTrace(@"Exiting early with _cellSwipeViewsEnabled=%d, _swipCell=%@, _animatingCellSwipe=%d",
- _cellSwipeViewsEnabled, _swipeCell, _animatingCellSwipe);
- return;
- }
-
- if ([self.delegate respondsToSelector:@selector(tableController:willRemoveSwipeView:fromCell:forObject:)]) {
- [self.delegate tableController:self
- willRemoveSwipeView:_cellSwipeView
- fromCell:_swipeCell
- forObject:_swipeObject];
- }
-
- if (animated) {
- [UIView beginAnimations:nil context:nil];
- [UIView setAnimationDuration:0.2];
- if (_swipeDirection == UISwipeGestureRecognizerDirectionRight) {
- _swipeCell.frame = CGRectMake(BOUNCE_PIXELS, _swipeCell.frame.origin.y, _swipeCell.frame.size.width, _swipeCell.frame.size.height);
- } else {
- _swipeCell.frame = CGRectMake(-BOUNCE_PIXELS, _swipeCell.frame.origin.y, _swipeCell.frame.size.width, _swipeCell.frame.size.height);
- }
- _animatingCellSwipe = YES;
- [UIView setAnimationDelegate:self];
- [UIView setAnimationDidStopSelector:@selector(animationDidStopOne:finished:context:)];
- [UIView commitAnimations];
- } else {
- [_cellSwipeView removeFromSuperview];
- _swipeCell.frame = CGRectMake(0, _swipeCell.frame.origin.y, _swipeCell.frame.size.width, _swipeCell.frame.size.height);
- [_swipeCell release];
- _swipeCell = nil;
- }
-}
-
-- (void)animationDidStopOne:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
-{
- [UIView beginAnimations:nil context:nil];
- [UIView setAnimationDuration:0.2];
- if (_swipeDirection == UISwipeGestureRecognizerDirectionRight) {
- _swipeCell.frame = CGRectMake(BOUNCE_PIXELS*2, _swipeCell.frame.origin.y, _swipeCell.frame.size.width, _swipeCell.frame.size.height);
- } else {
- _swipeCell.frame = CGRectMake(-BOUNCE_PIXELS*2, _swipeCell.frame.origin.y, _swipeCell.frame.size.width, _swipeCell.frame.size.height);
- }
- [UIView setAnimationDelegate:self];
- [UIView setAnimationDidStopSelector:@selector(animationDidStopTwo:finished:context:)];
- [UIView setAnimationCurve:UIViewAnimationCurveLinear];
- [UIView commitAnimations];
-}
-
-- (void)animationDidStopTwo:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
-{
- [UIView commitAnimations];
- [UIView beginAnimations:nil context:nil];
- [UIView setAnimationDuration:0.2];
- if (_swipeDirection == UISwipeGestureRecognizerDirectionRight) {
- _swipeCell.frame = CGRectMake(0, _swipeCell.frame.origin.y, _swipeCell.frame.size.width, _swipeCell.frame.size.height);
- } else {
- _swipeCell.frame = CGRectMake(0, _swipeCell.frame.origin.y, _swipeCell.frame.size.width, _swipeCell.frame.size.height);
- }
- [UIView setAnimationDelegate:self];
- [UIView setAnimationDidStopSelector:@selector(animationDidStopThree:finished:context:)];
- [UIView setAnimationCurve:UIViewAnimationCurveLinear];
- [UIView commitAnimations];
-}
-
-- (void)animationDidStopThree:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
-{
- _animatingCellSwipe = NO;
- [_swipeCell release];
- _swipeCell = nil;
- [_cellSwipeView removeFromSuperview];
-}
-
-#pragma mark UIScrollViewDelegate methods
-
-- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
-{
- [self removeSwipeView:YES];
-}
-
-- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
-{
- [self removeSwipeView:NO];
- return YES;
-}
-
-- (void)loadTableWithObjectLoader:(RKObjectLoader *)objectLoader
-{
- NSAssert(objectLoader, @"Cannot perform a network load without an object loader");
- if (! [self.objectLoader isEqual:objectLoader]) {
- if (self.objectLoader) {
- RKLogDebug(@"Cancelling in progress table load: asked to load with a new object loader.");
- [self.objectLoader.queue cancelRequest:self.objectLoader];
- }
-
- objectLoader.delegate = self;
- self.objectLoader = objectLoader;
- }
- if ([self.delegate respondsToSelector:@selector(tableController:willLoadTableWithObjectLoader:)]) {
- [self.delegate tableController:self willLoadTableWithObjectLoader:self.objectLoader];
- }
- if (self.objectLoader.queue && ![self.objectLoader.queue containsRequest:self.objectLoader]) {
- [self.objectLoader.queue addRequest:self.objectLoader];
- }
-}
-
-- (void)reloadRowForObject:(id)object withRowAnimation:(UITableViewRowAnimation)rowAnimation
-{
- NSIndexPath *indexPath = [self indexPathForObject:object];
- if (indexPath) {
- [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:rowAnimation];
- }
-}
-
-@end
View
78 Code/UI/RKAbstractTableController_Internals.h
@@ -1,78 +0,0 @@
-//
-// RKAbstractTableController_Internals.h
-// RestKit
-//
-// Created by Jeff Arena on 8/11/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 <UIKit/UIKit.h>
-#import "RKRefreshGestureRecognizer.h"
-
-/*
- A private continuation class for subclass implementations of RKAbstractTableController
- */
-@interface RKAbstractTableController () <RKObjectLoaderDelegate, RKRefreshTriggerProtocol>
-
-@property (nonatomic, readwrite, assign) UITableView *tableView;
-@property (nonatomic, readwrite, assign) UIViewController *viewController;
-@property (nonatomic, assign, readwrite) RKTableControllerState state;
-@property (nonatomic, readwrite, retain) RKObjectLoader *objectLoader;
-@property (nonatomic, readwrite, retain) NSError *error;
-@property (nonatomic, readwrite, retain) NSMutableArray *headerItems;
-@property (nonatomic, readwrite, retain) NSMutableArray *footerItems;
-@property (nonatomic, readonly) UIView *tableOverlayView;
-@property (nonatomic, readonly) UIImageView *stateOverlayImageView;
-@property (nonatomic, readonly) RKCache *cache;
-@property (nonatomic, retain) UIView *pullToRefreshHeaderView;
-
-#pragma mark - Subclass Load Event Hooks
-
-- (void)didStartLoad;
-
-/**
- Must be invoked when the table controller has finished loading.
-
- Responsible for finalizing loading, empty, and loaded states
- and cleaning up the table overlay view.
- */
-- (void)didFinishLoad;
-- (void)didFailLoadWithError:(NSError *)error;
-
-#pragma mark - Table View Overlay
-
-- (void)addToOverlayView:(UIView *)view modally:(BOOL)modally;
-- (void)resetOverlayView;
-- (void)addSubviewOverTableView:(UIView *)view;
-- (BOOL)removeImageFromOverlay:(UIImage *)image;
-- (void)showImageInOverlay:(UIImage *)image;
-- (void)removeImageOverlay;
-
-#pragma mark - Pull to Refresh Private Methods
-
-- (void)pullToRefreshStateChanged:(UIGestureRecognizer *)gesture;
-- (void)resetPullToRefreshRecognizer;
-
-/**
- Returns a Boolean value indicating if the table controller
- should be considered empty and transitioned into the empty state.
- Used by the abstract table controller to trigger state transitions.
-
- **NOTE**: This is an abstract method that MUST be implemented with
- a subclass.
- */
-- (BOOL)isConsideredEmpty;
-
-@end
View
68 Code/UI/RKFetchedResultsTableController.h
@@ -1,68 +0,0 @@
-//
-// RKFetchedResultsTableController.h
-// RestKit
-//
-// Created by Blake Watters on 8/2/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 "RKAbstractTableController.h"
-
-typedef UIView *(^RKFetchedResultsTableViewViewForHeaderInSectionBlock)(NSUInteger sectionIndex, NSString *sectionTitle);
-
-@class RKFetchedResultsTableController;
-@protocol RKFetchedResultsTableControllerDelegate <RKAbstractTableControllerDelegate>
-
-@optional
-
-// Sections
-- (void)tableController:(RKFetchedResultsTableController *)tableController didInsertSectionAtIndex:(NSUInteger)sectionIndex;
-- (void)tableController:(RKFetchedResultsTableController *)tableController didDeleteSectionAtIndex:(NSUInteger)sectionIndex;
-
-@end
-
-/**
- Instances of RKFetchedResultsTableController provide an interface for driving a UITableView
- */
-@interface RKFetchedResultsTableController : RKAbstractTableController <NSFetchedResultsControllerDelegate>
-
-// Delegate
-@property (nonatomic, assign) id<RKFetchedResultsTableControllerDelegate> delegate;
-
-// Fetched Results Controller
-@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
-@property (nonatomic, copy) NSString *resourcePath;
-@property (nonatomic, retain) NSFetchRequest *fetchRequest;
-@property (nonatomic, retain) NSPredicate *predicate;
-@property (nonatomic, retain) NSArray *sortDescriptors;
-@property (nonatomic, copy) NSString *sectionNameKeyPath;
-@property (nonatomic, copy) NSString *cacheName;
-@property (nonatomic, retain, readonly) NSFetchedResultsController *fetchedResultsController;
-
-// Configuring Headers and Sections
-@property (nonatomic, assign) CGFloat heightForHeaderInSection;
-@property (nonatomic, copy) RKFetchedResultsTableViewViewForHeaderInSectionBlock onViewForHeaderInSection;
-@property (nonatomic, assign) BOOL showsSectionIndexTitles;
-
-// Sorting
-@property (nonatomic, assign) SEL sortSelector;
-@property (nonatomic, copy) NSComparator sortComparator;
-
-- (void)setObjectMappingForClass:(Class)objectClass; // TODO: Kill this API... mapping descriptors will cover use case.
-- (void)loadTable;
-- (void)loadTableFromNetwork;
-
-@end
View
709 Code/UI/RKFetchedResultsTableController.m
@@ -1,709 +0,0 @@
-//
-// RKFetchedResultsTableController.m
-// RestKit
-//
-// Created by Blake Watters on 8/2/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 "RKFetchedResultsTableController.h"
-#import "RKAbstractTableController_Internals.h"
-#import "RKManagedObjectStore.h"
-#import "RKMappingOperation.h"
-#import "RKEntityMapping.h"
-#import "RKLog.h"
-#import "RKObjectMappingProvider+CoreData.h"
-
-// Define logging component
-#undef RKLogComponent
-#define RKLogComponent lcl_cRestKitUI
-
-@interface RKFetchedResultsTableController ()
-
-@property (nonatomic, assign) BOOL isEmptyBeforeAnimation;
-@property (nonatomic, retain, readwrite) NSFetchedResultsController *fetchedResultsController;
-@property (nonatomic, retain) NSArray *arraySortedFetchedObjects;
-
-- (BOOL)performFetch:(NSError **)error;
-- (void)updateSortedArray;
-@end
-
-@implementation RKFetchedResultsTableController
-
-@dynamic delegate;
-@synthesize fetchedResultsController = _fetchedResultsController;
-@synthesize resourcePath = _resourcePath;
-@synthesize heightForHeaderInSection = _heightForHeaderInSection;
-@synthesize onViewForHeaderInSection = _onViewForHeaderInSection;
-@synthesize predicate = _predicate;
-@synthesize sortDescriptors = _sortDescriptors;
-@synthesize sectionNameKeyPath = _sectionNameKeyPath;
-@synthesize cacheName = _cacheName;
-@synthesize showsSectionIndexTitles = _showsSectionIndexTitles;
-@synthesize sortSelector = _sortSelector;
-@synthesize sortComparator = _sortComparator;
-@synthesize fetchRequest = _fetchRequest;
-@synthesize arraySortedFetchedObjects = _arraySortedFetchedObjects;
-@synthesize isEmptyBeforeAnimation = _isEmptyBeforeAnimation;
-
-- (void)dealloc
-{
- _fetchedResultsController.delegate = nil;
- [_fetchedResultsController release];
- _fetchedResultsController = nil;
- [_resourcePath release];
- _resourcePath = nil;
- [_predicate release];
- _predicate = nil;
- [_sortDescriptors release];
- _sortDescriptors = nil;
- [_sectionNameKeyPath release];
- _sectionNameKeyPath = nil;
- [_cacheName release];
- _cacheName = nil;
- [_arraySortedFetchedObjects release];
- _arraySortedFetchedObjects = nil;
- [_fetchRequest release];
- _fetchRequest = nil;
- Block_release(_onViewForHeaderInSection);
- Block_release(_sortComparator);
- [super dealloc];
-}
-
-#pragma mark - Helpers
-
-- (BOOL)performFetch:(NSError **)error
-{
- NSAssert(self.fetchedResultsController, @"Cannot perform a fetch: self.fetchedResultsController is nil.");
-
- [NSFetchedResultsController deleteCacheWithName:self.fetchedResultsController.cacheName];
- BOOL success = [self.fetchedResultsController performFetch:error];
- if (!success) {
- RKLogError(@"performFetch failed with error: %@", [*error localizedDescription]);
- return NO;
- } else {
- RKLogTrace(@"performFetch completed successfully");
- for (NSUInteger index = 0; index < [self sectionCount]; index++) {
- if ([self.delegate respondsToSelector:@selector(tableController:didInsertSectionAtIndex:)]) {
- [self.delegate tableController:self didInsertSectionAtIndex:index];
- }
-
- if ([self.delegate respondsToSelector:@selector(tableController:didInsertObject:atIndexPath:)]) {
- for (NSUInteger row = 0; row < [self numberOfRowsInSection:index]; row++) {
- NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:index];
- id object = [self objectForRowAtIndexPath:indexPath];
- [self.delegate tableController:self didInsertObject:object atIndexPath:indexPath];
- }
- }
- }
- }
-
- return YES;
-}
-
-- (void)updateSortedArray
-{
- self.arraySortedFetchedObjects = nil;
-
- if (self.sortSelector || self.sortComparator) {
- if (self.sortSelector) {
- self.arraySortedFetchedObjects = [self.fetchedResultsController.fetchedObjects sortedArrayUsingSelector:self.sortSelector];
- } else if (self.sortComparator) {
- self.arraySortedFetchedObjects = [self.fetchedResultsController.fetchedObjects sortedArrayUsingComparator:self.sortComparator];
- }
-
- NSAssert(self.arraySortedFetchedObjects.count == self.fetchedResultsController.fetchedObjects.count,
- @"sortSelector or sortComparator sort resulted in fewer objects than expected");
- }
-}
-
-- (NSUInteger)headerSectionIndex
-{
- return 0;
-}
-
-- (BOOL)isHeaderSection:(NSUInteger)section
-{
- return (section == [self headerSectionIndex]);
-}
-
-- (BOOL)isHeaderRow:(NSUInteger)row
-{
- BOOL isHeaderRow = NO;
- NSUInteger headerItemCount = [self.headerItems count];
- if ([self isEmpty] && self.emptyItem) {
- isHeaderRow = (row > 0 && row <= headerItemCount);
- } else {
- isHeaderRow = (row < headerItemCount);
- }
- return isHeaderRow;
-}
-
-- (NSUInteger)footerSectionIndex
-{
- return ([self sectionCount] - 1);
-}
-
-- (BOOL)isFooterSection:(NSUInteger)section
-{
- return (section == [self footerSectionIndex]);
-}
-
-- (BOOL)isFooterRow:(NSUInteger)row
-{
- NSUInteger sectionIndex = ([self sectionCount] - 1);
- id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:sectionIndex];
- NSUInteger firstFooterIndex = [sectionInfo numberOfObjects];
- if (sectionIndex == 0) {
- firstFooterIndex += (![self isEmpty] || self.showsHeaderRowsWhenEmpty) ? [self.headerItems count] : 0;
- firstFooterIndex += ([self isEmpty] && self.emptyItem) ? 1 : 0;
- }
-
- return row >= firstFooterIndex;
-}
-
-- (BOOL)isHeaderIndexPath:(NSIndexPath *)indexPath
-{
- return ((! [self isEmpty] || self.showsHeaderRowsWhenEmpty) &&
- [self.headerItems count] > 0 &&
- [self isHeaderSection:indexPath.section] &&
- [self isHeaderRow:indexPath.row]);
-}
-
-- (BOOL)isFooterIndexPath:(NSIndexPath *)indexPath
-{
- return ((! [self isEmpty] || self.showsFooterRowsWhenEmpty) &&
- [self.footerItems count] > 0 &&
- [self isFooterSection:indexPath.section] &&
- [self isFooterRow:indexPath.row]);
-}
-
-- (BOOL)isEmptySection:(NSUInteger)section
-{
- return (section == 0);
-}
-
-- (BOOL)isEmptyRow:(NSUInteger)row
-{
- return (row == 0);
-}
-
-- (BOOL)isEmptyItemIndexPath:(NSIndexPath *)indexPath
-{
- return ([self isEmpty] && self.emptyItem &&
- [self isEmptySection:indexPath.section] &&
- [self isEmptyRow:indexPath.row]);
-}
-
-- (NSIndexPath *)emptyItemIndexPath
-{
- return [NSIndexPath indexPathForRow:0 inSection:0];
-}
-
-- (NSIndexPath *)fetchedResultsIndexPathForIndexPath:(NSIndexPath *)indexPath
-{
- if (([self isEmpty] && self.emptyItem &&
- [self isEmptySection:indexPath.section] &&
- ! [self isEmptyRow:indexPath.row]) ||