mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-29 05:05:34 +08:00
Fixed issues with incorrect retrieval of indexPath for header, footer, and empty items on the fetched results table controller. fixes #798
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "RKTableCellBlockTypes.h"
|
||||
#import "RKTableViewCellMappings.h"
|
||||
#import "RKTableItem.h"
|
||||
#import "RKObjectManager.h"
|
||||
@@ -258,6 +259,20 @@ typedef NSUInteger RKTableControllerState;
|
||||
*/
|
||||
- (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
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
@@ -59,6 +59,5 @@ typedef UIView *(^RKFetchedResultsTableViewViewForHeaderInSectionBlock)(NSUInteg
|
||||
- (void)setObjectMappingForClass:(Class)objectClass;
|
||||
- (void)loadTable;
|
||||
- (void)loadTableFromNetwork;
|
||||
- (NSIndexPath *)indexPathForObject:(id)object;
|
||||
|
||||
@end
|
||||
|
||||
@@ -125,9 +125,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSUInteger)headerSectionIndex
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (BOOL)isHeaderSection:(NSUInteger)section
|
||||
{
|
||||
return (section == 0);
|
||||
return (section == [self headerSectionIndex]);
|
||||
}
|
||||
|
||||
- (BOOL)isHeaderRow:(NSUInteger)row
|
||||
@@ -142,9 +147,14 @@
|
||||
return isHeaderRow;
|
||||
}
|
||||
|
||||
- (NSUInteger)footerSectionIndex
|
||||
{
|
||||
return ([self sectionCount] - 1);
|
||||
}
|
||||
|
||||
- (BOOL)isFooterSection:(NSUInteger)section
|
||||
{
|
||||
return (section == ([self sectionCount] - 1));
|
||||
return (section == [self footerSectionIndex]);
|
||||
}
|
||||
|
||||
- (BOOL)isFooterRow:(NSUInteger)row
|
||||
@@ -352,13 +362,18 @@
|
||||
|
||||
- (UITableViewCell *)cellForObjectAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
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 = [cellMapping mappableObjectForData:self.tableView];
|
||||
// Attempt to get existing cell
|
||||
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
|
||||
if (! cell) {
|
||||
cell = [cellMapping mappableObjectForData:self.tableView];
|
||||
}
|
||||
NSAssert(cell, @"Cell mapping failed to dequeue or allocate a tableViewCell for object: %@", mappableObject);
|
||||
|
||||
// Map the object state into the cell
|
||||
@@ -382,13 +397,38 @@
|
||||
{
|
||||
if ([object isKindOfClass:[NSManagedObject class]]) {
|
||||
return [self indexPathForFetchedResultsIndexPath:[_fetchedResultsController indexPathForObject:object]];
|
||||
} else if ([object isKindOfClass:[RKTableItem class]]) {
|
||||
if ([object isEqual:self.emptyItem]) {
|
||||
return ([self isEmpty]) ? [self emptyItemIndexPath] : nil;
|
||||
} else if ([self.headerItems containsObject:object]) {
|
||||
// Figure out the row number for the object
|
||||
NSUInteger objectIndex = [self.headerItems indexOfObject:object];
|
||||
NSUInteger row = ([self isEmpty] && self.emptyItem) ? (objectIndex + 1) : objectIndex;
|
||||
return [NSIndexPath indexPathForRow:row inSection:[self headerSectionIndex]];
|
||||
} else if ([self.footerItems containsObject:object]) {
|
||||
NSUInteger footerSectionIndex = [self sectionCount] - 1;
|
||||
id <NSFetchedResultsSectionInfo> sectionInfo = [[_fetchedResultsController sections] objectAtIndex:footerSectionIndex];
|
||||
NSUInteger numberOfFetchedResults = sectionInfo.numberOfObjects;
|
||||
NSUInteger objectIndex = [self.footerItems indexOfObject:object];
|
||||
NSUInteger row = numberOfFetchedResults + objectIndex;
|
||||
row += ([self isEmpty] && self.emptyItem) ? 1 : 0;
|
||||
if ([self isHeaderSection:footerSectionIndex]) {
|
||||
row += [self.headerItems count];
|
||||
}
|
||||
|
||||
return [NSIndexPath indexPathForRow:row inSection:footerSectionIndex];
|
||||
}
|
||||
} else {
|
||||
RKLogWarning(@"Asked for indexPath of unsupported object type '%@': %@", [object class], object);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)cellForObject:(id)object
|
||||
{
|
||||
return [self cellForObjectAtIndexPath:[self indexPathForObject:object]];
|
||||
NSIndexPath *indexPath = [self indexPathForObject:object];
|
||||
NSAssert(indexPath, @"Failed to find indexPath for object: %@", object);
|
||||
return [self cellForObjectAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource methods
|
||||
@@ -678,15 +718,6 @@
|
||||
|
||||
#pragma mark - UITableViewDataSource methods
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSAssert(theTableView == self.tableView, @"tableView:cellForRowAtIndexPath: invoked with inappropriate tableView: %@", theTableView);
|
||||
UITableViewCell *cell = [self cellForObjectAtIndexPath:indexPath];
|
||||
|
||||
RKLogTrace(@"%@ cellForRowAtIndexPath:%@ = %@", self, indexPath, cell);
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSUInteger)numberOfRowsInSection:(NSUInteger)index
|
||||
{
|
||||
return [self tableView:self.tableView numberOfRowsInSection:index];
|
||||
|
||||
15
Code/UI/RKTableCellBlockTypes.h
Normal file
15
Code/UI/RKTableCellBlockTypes.h
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// RKTableCellBlockTypes.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 6/6/12.
|
||||
// Copyright (c) 2012 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
typedef NSIndexPath *(^RKTableTargetIndexPathForMoveBlock)(UITableViewCell *cell, id object, NSIndexPath *sourceIndexPath, NSIndexPath *destIndexPath);
|
||||
typedef UITableViewCellEditingStyle(^RKTableCellEditingStyleForObjectAtIndexPathBlock)(UITableViewCell *cell, id object, NSIndexPath *indexPath);
|
||||
typedef NSString *(^RKTableStringForObjectAtIndexPathBlock)(UITableViewCell *cell, id object, NSIndexPath *indexPath);
|
||||
typedef CGFloat(^RKTableHeightOfCellForObjectAtIndexPathBlock)(id object, NSIndexPath *indexPath);
|
||||
typedef void(^RKTableVoidBlock)();
|
||||
typedef void(^RKTableCellBlock)(UITableViewCell *cell);
|
||||
typedef void(^RKTableCellForObjectAtIndexPathBlock)(UITableViewCell *cell, id object, NSIndexPath *indexPath);
|
||||
@@ -431,6 +431,7 @@
|
||||
|
||||
- (UITableViewCell *)cellForObjectAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSAssert(indexPath, @"Cannot retrieve cell for nil indexPath");
|
||||
RKTableSection *section = [self sectionAtIndex:indexPath.section];
|
||||
id mappableObject = [section objectAtIndex:indexPath.row];
|
||||
RKTableViewCellMapping *cellMapping = [self.cellMappings cellMappingForObject:mappableObject];
|
||||
|
||||
@@ -20,17 +20,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "RKObjectMapping.h"
|
||||
|
||||
/** @name Cell Mapping Block Callbacks **/
|
||||
|
||||
typedef void(^RKTableViewCellForObjectAtIndexPathBlock)(UITableViewCell *cell, id object, NSIndexPath *indexPath);
|
||||
typedef CGFloat(^RKTableViewHeightOfCellForObjectAtIndexPathBlock)(id object, NSIndexPath *indexPath);
|
||||
typedef void(^RKTableViewAccessoryButtonTappedForObjectAtIndexPathBlock)(UITableViewCell *cell, id object, NSIndexPath *indexPath);
|
||||
typedef NSString *(^RKTableViewTitleForDeleteButtonForObjectAtIndexPathBlock)(UITableViewCell *cell, id object, NSIndexPath *indexPath);
|
||||
typedef UITableViewCellEditingStyle(^RKTableViewEditingStyleForObjectAtIndexPathBlock)(UITableViewCell *cell, id object, NSIndexPath *indexPath);
|
||||
typedef NSIndexPath *(^RKTableViewTargetIndexPathForMoveBlock)(UITableViewCell *cell, id object, NSIndexPath *sourceIndexPath, NSIndexPath *destIndexPath);
|
||||
typedef void(^RKTableViewAnonymousBlock)();
|
||||
typedef void(^RKTableViewCellBlock)(UITableViewCell *cell);
|
||||
#import "RKTableCellBlockTypes.h"
|
||||
|
||||
/**
|
||||
Defines a RestKit object mapping suitable for mapping generic
|
||||
@@ -46,10 +36,7 @@ typedef void(^RKTableViewCellBlock)(UITableViewCell *cell);
|
||||
|
||||
@see RKTableController
|
||||
*/
|
||||
@interface RKTableViewCellMapping : RKObjectMapping {
|
||||
@protected
|
||||
NSMutableArray *_prepareCellBlocks;
|
||||
}
|
||||
@interface RKTableViewCellMapping : RKObjectMapping
|
||||
|
||||
/**
|
||||
The UITableViewCell subclass that this mapping will target. This
|
||||
@@ -141,7 +128,7 @@ typedef void(^RKTableViewCellBlock)(UITableViewCell *cell);
|
||||
is invoked with a reference to both the UITableViewCell that was touched and the
|
||||
object the cell is representing.
|
||||
*/
|
||||
@property (nonatomic, copy) RKTableViewCellForObjectAtIndexPathBlock onSelectCellForObjectAtIndexPath;
|
||||
@property (nonatomic, copy) RKTableCellForObjectAtIndexPathBlock onSelectCellForObjectAtIndexPath;
|
||||
|
||||
/**
|
||||
Invoked when the user has touched a cell configured with this mapping. The block is invoked
|
||||
@@ -150,7 +137,7 @@ typedef void(^RKTableViewCellBlock)(UITableViewCell *cell);
|
||||
|
||||
@see onSelectCellForObjectAtIndexPath
|
||||
*/
|
||||
@property (nonatomic, copy) RKTableViewAnonymousBlock onSelectCell;
|
||||
@property (nonatomic, copy) RKTableVoidBlock onSelectCell;
|
||||
|
||||
/**
|
||||
A block to invoke when a table view cell created with this mapping is going to appear in the table.
|
||||
@@ -159,37 +146,38 @@ typedef void(^RKTableViewCellBlock)(UITableViewCell *cell);
|
||||
|
||||
This is a good moment to perform any customization to the cell before it becomes visible in the table view.
|
||||
*/
|
||||
@property (nonatomic, copy) RKTableViewCellForObjectAtIndexPathBlock onCellWillAppearForObjectAtIndexPath;
|
||||
@property (nonatomic, copy) RKTableCellForObjectAtIndexPathBlock onCellWillAppearForObjectAtIndexPath;
|
||||
|
||||
/**
|
||||
A block to invoke when the table view is measuring the height of the UITableViewCell.
|
||||
The block will be invoked with the UITableViewCell, an id reference to the mapped object being
|
||||
represented in the cell, and the NSIndexPath for the row position the cell will be appearing at.
|
||||
*/
|
||||
@property (nonatomic, copy) RKTableViewHeightOfCellForObjectAtIndexPathBlock heightOfCellForObjectAtIndexPath;
|
||||
@property (nonatomic, copy) RKTableHeightOfCellForObjectAtIndexPathBlock heightOfCellForObjectAtIndexPath;
|
||||
|
||||
/**
|
||||
A block to invoke when the accessory button for a given cell is tapped by the user.
|
||||
The block will be invoked with the UITableViewCell, an id reference to the mapped object being
|
||||
represented in the cell, and the NSIndexPath for the row position the cell will be appearing at.
|
||||
*/
|
||||
@property (nonatomic, copy) RKTableViewAccessoryButtonTappedForObjectAtIndexPathBlock onTapAccessoryButtonForObjectAtIndexPath;
|
||||
@property (nonatomic, copy) RKTableCellForObjectAtIndexPathBlock onTapAccessoryButtonForObjectAtIndexPath;
|
||||
|
||||
/**
|
||||
A block to invoke when the table view is determining the title for the delete confirmation button.
|
||||
The block will be invoked with the UITableViewCell, an id reference to the mapped object being
|
||||
represented in the cell, and the NSIndexPath for the row position the cell will be appearing at.
|
||||
*/
|
||||
@property (nonatomic, copy) RKTableViewTitleForDeleteButtonForObjectAtIndexPathBlock titleForDeleteButtonForObjectAtIndexPath;
|
||||
@property (nonatomic, copy) RKTableStringForObjectAtIndexPathBlock titleForDeleteButtonForObjectAtIndexPath;
|
||||
|
||||
/**
|
||||
A block to invoke when the table view is determining the editing style for a given row.
|
||||
The block will be invoked with the UITableViewCell, an id reference to the mapped object being
|
||||
represented in the cell, and the NSIndexPath for the row position the cell will be appearing at.
|
||||
*/
|
||||
@property (nonatomic, copy) RKTableViewEditingStyleForObjectAtIndexPathBlock editingStyleForObjectAtIndexPath;
|
||||
@property (nonatomic, copy) RKTableCellEditingStyleForObjectAtIndexPathBlock editingStyleForObjectAtIndexPath;
|
||||
|
||||
@property (nonatomic, copy) RKTableViewTargetIndexPathForMoveBlock targetIndexPathForMove;
|
||||
// TODO: Docs...
|
||||
@property (nonatomic, copy) RKTableTargetIndexPathForMoveBlock targetIndexPathForMove;
|
||||
|
||||
/**
|
||||
Returns a new auto-released mapping targeting UITableViewCell
|
||||
|
||||
@@ -82,6 +82,10 @@ typedef void(^RKControlBlockActionBlock)(id sender);
|
||||
|
||||
@end
|
||||
|
||||
@interface RKTableViewCellMapping ()
|
||||
@property (nonatomic, retain) NSMutableArray *prepareCellBlocks;
|
||||
@end
|
||||
|
||||
@implementation RKTableViewCellMapping
|
||||
|
||||
@synthesize reuseIdentifier = _reuseIdentifier;
|
||||
@@ -98,7 +102,8 @@ typedef void(^RKControlBlockActionBlock)(id sender);
|
||||
@synthesize targetIndexPathForMove = _targetIndexPathForMove;
|
||||
@synthesize rowHeight = _rowHeight;
|
||||
@synthesize deselectsRowOnSelection = _deselectsRowOnSelection;
|
||||
@synthesize managesCellAttributes;
|
||||
@synthesize managesCellAttributes = _managesCellAttributes;
|
||||
@synthesize prepareCellBlocks = _prepareCellBlocks;
|
||||
|
||||
+ (id)cellMapping
|
||||
{
|
||||
@@ -204,9 +209,12 @@ typedef void(^RKControlBlockActionBlock)(id sender);
|
||||
NSAssert([tableView isKindOfClass:[UITableView class]], @"Expected to be invoked with a tableView as the data. Got %@", tableView);
|
||||
RKLogTrace(@"About to dequeue reusable cell using self.reuseIdentifier=%@", self.reuseIdentifier);
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.reuseIdentifier];
|
||||
if (! cell) {
|
||||
if (cell) {
|
||||
RKLogTrace(@"Dequeued existing cell object for reuse identifier '%@': %@", self.reuseIdentifier, cell);
|
||||
} else {
|
||||
cell = [[[self.objectClass alloc] initWithStyle:self.style
|
||||
reuseIdentifier:self.reuseIdentifier] autorelease];
|
||||
RKLogTrace(@"Failed to dequeue existing cell object for reuse identifier '%@', instantiated new cell: %@", self.reuseIdentifier, cell);
|
||||
}
|
||||
|
||||
if (self.managesCellAttributes) {
|
||||
|
||||
@@ -673,6 +673,8 @@
|
||||
25B6EA0414CF943E00B1E881 /* RKMutableBlockDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 25B6E9FC14CF943E00B1E881 /* RKMutableBlockDictionary.m */; };
|
||||
25B6EA0614CF946400B1E881 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25B6EA0514CF946300B1E881 /* QuartzCore.framework */; };
|
||||
25B6EA0814CF947E00B1E881 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25B6EA0714CF947D00B1E881 /* CoreGraphics.framework */; };
|
||||
25C93DF2157FB6370089259B /* RKTableCellBlockTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 25C93DF1157FB6370089259B /* RKTableCellBlockTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
25C93DF3157FB6370089259B /* RKTableCellBlockTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 25C93DF1157FB6370089259B /* RKTableCellBlockTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
25C954A715542A47005C9E08 /* RKTestConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 25C954A415542A47005C9E08 /* RKTestConstants.m */; };
|
||||
25C954A815542A47005C9E08 /* RKTestConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 25C954A415542A47005C9E08 /* RKTestConstants.m */; };
|
||||
25CA7A8F14EC570200888FF8 /* RKObjectMappingDefinition.m in Sources */ = {isa = PBXBuildFile; fileRef = 25CA7A8E14EC570100888FF8 /* RKObjectMappingDefinition.m */; };
|
||||
@@ -1194,6 +1196,7 @@
|
||||
25B6E9FC14CF943E00B1E881 /* RKMutableBlockDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKMutableBlockDictionary.m; sourceTree = "<group>"; };
|
||||
25B6EA0514CF946300B1E881 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||
25B6EA0714CF947D00B1E881 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||
25C93DF1157FB6370089259B /* RKTableCellBlockTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKTableCellBlockTypes.h; sourceTree = "<group>"; };
|
||||
25C954A415542A47005C9E08 /* RKTestConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RKTestConstants.m; path = Testing/RKTestConstants.m; sourceTree = "<group>"; };
|
||||
25CA7A8E14EC570100888FF8 /* RKObjectMappingDefinition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectMappingDefinition.m; sourceTree = "<group>"; };
|
||||
25CAAA9315254E7800CAE5D7 /* ArrayOfHumans.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ArrayOfHumans.json; sourceTree = "<group>"; };
|
||||
@@ -2049,6 +2052,7 @@
|
||||
25EC1A2B14F6FDAC00C3CF3F /* RKObjectManager+RKTableController.m */,
|
||||
25EC1B3714F84B5C00C3CF3F /* UIImage+RKAdditions.h */,
|
||||
25EC1B3814F84B5C00C3CF3F /* UIImage+RKAdditions.m */,
|
||||
25C93DF1157FB6370089259B /* RKTableCellBlockTypes.h */,
|
||||
);
|
||||
path = UI;
|
||||
sourceTree = "<group>";
|
||||
@@ -2310,6 +2314,7 @@
|
||||
258113C815781848009835EB /* RKObjectMappingProvider+CoreData.h in Headers */,
|
||||
25545959155F0527007D7625 /* RKBenchmark.h in Headers */,
|
||||
25E4DAB4156DA97F00A5C84B /* RKTableControllerTestDelegate.h in Headers */,
|
||||
25C93DF2157FB6370089259B /* RKTableCellBlockTypes.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2436,6 +2441,7 @@
|
||||
252028FD1577AE0B00076FB4 /* RKRouter.h in Headers */,
|
||||
252029041577AE1800076FB4 /* RKRoute.h in Headers */,
|
||||
258113C915781848009835EB /* RKObjectMappingProvider+CoreData.h in Headers */,
|
||||
25C93DF3157FB6370089259B /* RKTableCellBlockTypes.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
2552087E14E5B0B500EFD81F /* RKTestEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 2552087D14E5B0B500EFD81F /* RKTestEnvironment.m */; };
|
||||
25AE61DC15ADECAE00B319C8 /* OCClassMockRecorder.m in Sources */ = {isa = PBXBuildFile; fileRef = 25AE61D915ADECAE00B319C8 /* OCClassMockRecorder.m */; };
|
||||
25AE61DD15ADECAE00B319C8 /* OCMockClassObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 25AE61DB15ADECAE00B319C8 /* OCMockClassObject.m */; };
|
||||
25C93E03157FE7C40089259B /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 25C93E02157FE7C40089259B /* Storyboard.storyboard */; };
|
||||
25FABEA914E3698100E609E7 /* blake.png in Resources */ = {isa = PBXBuildFile; fileRef = 25FABE8114E3698100E609E7 /* blake.png */; };
|
||||
25FABEAA14E3698100E609E7 /* ArrayOfNestedDictionaries.json in Resources */ = {isa = PBXBuildFile; fileRef = 25FABE8314E3698100E609E7 /* ArrayOfNestedDictionaries.json */; };
|
||||
25FABEAB14E3698100E609E7 /* ArrayOfResults.json in Resources */ = {isa = PBXBuildFile; fileRef = 25FABE8414E3698100E609E7 /* ArrayOfResults.json */; };
|
||||
@@ -272,6 +273,7 @@
|
||||
25AE61D915ADECAE00B319C8 /* OCClassMockRecorder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCClassMockRecorder.m; sourceTree = "<group>"; };
|
||||
25AE61DA15ADECAE00B319C8 /* OCMockClassObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMockClassObject.h; sourceTree = "<group>"; };
|
||||
25AE61DB15ADECAE00B319C8 /* OCMockClassObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCMockClassObject.m; sourceTree = "<group>"; };
|
||||
25C93E02157FE7C40089259B /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = "<group>"; };
|
||||
25FABE8114E3698100E609E7 /* blake.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = blake.png; sourceTree = "<group>"; };
|
||||
25FABE8314E3698100E609E7 /* ArrayOfNestedDictionaries.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ArrayOfNestedDictionaries.json; sourceTree = "<group>"; };
|
||||
25FABE8414E3698100E609E7 /* ArrayOfResults.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ArrayOfResults.json; sourceTree = "<group>"; };
|
||||
@@ -392,6 +394,7 @@
|
||||
253B487514E3415800B0483F /* RKATAppDelegate.m */,
|
||||
255207EB14E5A50800EFD81F /* RKATTests.xcdatamodeld */,
|
||||
253B486C14E3415800B0483F /* Supporting Files */,
|
||||
25C93E02157FE7C40089259B /* Storyboard.storyboard */,
|
||||
);
|
||||
name = App;
|
||||
path = RKApplicationTests/App;
|
||||
@@ -787,6 +790,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
253B487014E3415800B0483F /* InfoPlist.strings in Resources */,
|
||||
25C93E03157FE7C40089259B /* Storyboard.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.1" toolsVersion="2182" systemVersion="11E53" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="1yr-CK-aHs">
|
||||
<dependencies>
|
||||
<deployment defaultVersion="1296" identifier="iOS"/>
|
||||
<development defaultVersion="4200" identifier="xcode"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="1181"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Table View Controller-->
|
||||
<scene sceneID="b8o-v0-PyV">
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="bOO-KL-fJE" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<tableViewController id="1yr-CK-aHs" sceneMemberID="viewController">
|
||||
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="TLU-pZ-Qvj">
|
||||
<rect key="frame" x="0.0" y="20" width="320" height="460"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="HeaderCell" textLabel="KhK-Gz-eSx" style="IBUITableViewCellStyleDefault" id="qmM-ji-v3M">
|
||||
<rect key="frame" x="0.0" y="22" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="KhK-Gz-eSx">
|
||||
<rect key="frame" x="10" y="0.0" width="300" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="ObjectCell" textLabel="TKX-Yg-pGU" detailTextLabel="xxa-4c-3ki" style="IBUITableViewCellStyleValue1" id="Re2-lX-ZFL">
|
||||
<rect key="frame" x="0.0" y="66" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="TKX-Yg-pGU">
|
||||
<rect key="frame" x="10" y="11" width="35" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="xxa-4c-3ki">
|
||||
<rect key="frame" x="266" y="11" width="44" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.2196078431372549" green="0.32941176470588235" blue="0.52941176470588236" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="FooterCell" textLabel="N6n-tS-fmm" style="IBUITableViewCellStyleDefault" id="kJX-kC-GHc">
|
||||
<rect key="frame" x="0.0" y="110" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="N6n-tS-fmm">
|
||||
<rect key="frame" x="10" y="0.0" width="300" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="1yr-CK-aHs" id="d2i-yI-C8u"/>
|
||||
<outlet property="delegate" destination="1yr-CK-aHs" id="Igd-89-n3h"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</tableViewController>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="76" y="21"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||
<simulatedStatusBarMetrics key="statusBar"/>
|
||||
<simulatedOrientationMetrics key="orientation"/>
|
||||
<simulatedScreenMetrics key="destination"/>
|
||||
</simulatedMetricsContainer>
|
||||
</document>
|
||||
@@ -83,6 +83,10 @@
|
||||
[objectManager.mappingProvider setObjectMapping:humanMapping forResourcePathPattern:@"/JSON/humans/all\\.json" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
|
||||
return [RKHuman requestAllSortedBy:@"name" ascending:YES];
|
||||
}];
|
||||
|
||||
[objectManager.mappingProvider setObjectMapping:humanMapping forResourcePathPattern:@"/JSON/humans/empty\\.json" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
|
||||
return [RKHuman requestAllSortedBy:@"name" ascending:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)bootstrapNakedObjectStoreAndCache
|
||||
@@ -523,9 +527,9 @@
|
||||
{
|
||||
[self bootstrapStoreAndCache];
|
||||
[self stubObjectManagerToOnline];
|
||||
[[RKObjectManager sharedManager].router routeClass:[RKHuman class]
|
||||
toResourcePath:@"/humans/:railsID"
|
||||
forMethod:RKRequestMethodDELETE];
|
||||
[[RKObjectManager sharedManager].router addRouteWithClass:[RKHuman class]
|
||||
resourcePathPattern:@"/humans/:railsID"
|
||||
method:RKRequestMethodDELETE];
|
||||
RKFetchedResultsTableControllerSpecViewController *viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController *tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
@@ -1528,4 +1532,238 @@
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfExistingCellsByObject
|
||||
{
|
||||
[self bootstrapStoreAndCache];
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
UITableViewController *tableViewController = [storyboard instantiateInitialViewController];
|
||||
RKFetchedResultsTableController *tableController;
|
||||
tableController = [RKFetchedResultsTableController tableControllerForTableViewController:tableViewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
|
||||
RKTableItem *tableItem = [RKTableItem tableItemWithText:@"Test"];
|
||||
tableItem.cellMapping.reuseIdentifier = @"HeaderCell";
|
||||
[tableItem.cellMapping addDefaultMappings];
|
||||
[tableController addHeaderRowForItem:tableItem];
|
||||
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:tableViewController];
|
||||
|
||||
[RKTestNotificationObserver waitForNotificationWithName:RKTableControllerDidLoadObjectsNotification usingBlock:^{
|
||||
[tableController loadTable];
|
||||
}];
|
||||
assertThatInt([tableController numberOfRowsInSection:0], is(equalToInteger(3)));
|
||||
|
||||
NSIndexPath *headerIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
|
||||
UITableViewCell *cellFromTableView = [tableViewController.tableView cellForRowAtIndexPath:headerIndexPath];
|
||||
|
||||
UITableViewCell *cellForObject = [tableController cellForObject:tableItem];
|
||||
assertThat(cellForObject, is(equalTo(cellFromTableView)));
|
||||
|
||||
UITableViewCell *cellFromTableController = [tableController cellForObjectAtIndexPath:headerIndexPath];
|
||||
assertThat(cellForObject, is(equalTo(cellFromTableController)));
|
||||
|
||||
assertThat(cellFromTableView, is(equalTo(cellFromTableController)));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfManagedObjectIndexPath
|
||||
{
|
||||
[self bootstrapStoreAndCache];
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
UITableViewController *tableViewController = [storyboard instantiateInitialViewController];
|
||||
RKFetchedResultsTableController *tableController;
|
||||
tableController = [RKFetchedResultsTableController tableControllerForTableViewController:tableViewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
|
||||
RKTableItem *headerItem = [RKTableItem tableItemWithText:@"Header"];
|
||||
headerItem.cellMapping.reuseIdentifier = @"HeaderCell";
|
||||
[headerItem.cellMapping addDefaultMappings];
|
||||
[tableController addHeaderRowForItem:headerItem];
|
||||
|
||||
RKTableItem *footerItem = [RKTableItem tableItemWithText:@"Footer"];
|
||||
footerItem.cellMapping.reuseIdentifier = @"FooterCell";
|
||||
[footerItem.cellMapping addDefaultMappings];
|
||||
[tableController addFooterRowForItem:footerItem];
|
||||
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:tableViewController];
|
||||
|
||||
[RKTestNotificationObserver waitForNotificationWithName:RKTableControllerDidFinishLoadNotification usingBlock:^{
|
||||
[tableController loadTable];
|
||||
}];
|
||||
|
||||
// Let the table update
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInteger(4)));
|
||||
RKHuman *human = [[RKHuman findAllSortedBy:@"name" ascending:YES] objectAtIndex:0];
|
||||
NSIndexPath *indexPath = [tableController indexPathForObject:human];
|
||||
assertThatInteger(indexPath.section, is(equalToInteger(0)));
|
||||
assertThatInteger(indexPath.row, is(equalToInteger(1)));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfHeaderItemIndexPath
|
||||
{
|
||||
[self bootstrapStoreAndCache];
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
UITableViewController *tableViewController = [storyboard instantiateInitialViewController];
|
||||
RKFetchedResultsTableController *tableController;
|
||||
tableController = [RKFetchedResultsTableController tableControllerForTableViewController:tableViewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
|
||||
RKTableItem *headerItem = [RKTableItem tableItemWithText:@"Header"];
|
||||
headerItem.cellMapping.reuseIdentifier = @"HeaderCell";
|
||||
[headerItem.cellMapping addDefaultMappings];
|
||||
[tableController addHeaderRowForItem:headerItem];
|
||||
|
||||
RKTableItem *footerItem = [RKTableItem tableItemWithText:@"Footer"];
|
||||
footerItem.cellMapping.reuseIdentifier = @"FooterCell";
|
||||
[footerItem.cellMapping addDefaultMappings];
|
||||
[tableController addFooterRowForItem:footerItem];
|
||||
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:tableViewController];
|
||||
|
||||
[RKTestNotificationObserver waitForNotificationWithName:RKTableControllerDidFinishLoadNotification usingBlock:^{
|
||||
[tableController loadTable];
|
||||
}];
|
||||
|
||||
// Let the table update
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInteger(4)));
|
||||
NSIndexPath *indexPath = [tableController indexPathForObject:headerItem];
|
||||
assertThatInteger(indexPath.section, is(equalToInteger(0)));
|
||||
assertThatInteger(indexPath.row, is(equalToInteger(0)));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfFooterItemIndexPath
|
||||
{
|
||||
[self bootstrapStoreAndCache];
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
UITableViewController *tableViewController = [storyboard instantiateInitialViewController];
|
||||
RKFetchedResultsTableController *tableController;
|
||||
tableController = [RKFetchedResultsTableController tableControllerForTableViewController:tableViewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
|
||||
RKTableItem *headerItem = [RKTableItem tableItemWithText:@"Header"];
|
||||
headerItem.cellMapping.reuseIdentifier = @"HeaderCell";
|
||||
[headerItem.cellMapping addDefaultMappings];
|
||||
[tableController addHeaderRowForItem:headerItem];
|
||||
|
||||
RKTableItem *footerItem = [RKTableItem tableItemWithText:@"Footer"];
|
||||
footerItem.cellMapping.reuseIdentifier = @"FooterCell";
|
||||
[footerItem.cellMapping addDefaultMappings];
|
||||
[tableController addFooterRowForItem:footerItem];
|
||||
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:tableViewController];
|
||||
|
||||
[RKTestNotificationObserver waitForNotificationWithName:RKTableControllerDidFinishLoadNotification usingBlock:^{
|
||||
[tableController loadTable];
|
||||
}];
|
||||
|
||||
// Let the table update
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInteger(4)));
|
||||
NSIndexPath *indexPath = [tableController indexPathForObject:footerItem];
|
||||
assertThatInteger(indexPath.section, is(equalToInteger(0)));
|
||||
assertThatInteger(indexPath.row, is(equalToInteger(3)));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfEmptyItemReturnsNilIndexPathWhenNotEmpty
|
||||
{
|
||||
[self bootstrapStoreAndCache];
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
UITableViewController *tableViewController = [storyboard instantiateInitialViewController];
|
||||
RKFetchedResultsTableController *tableController;
|
||||
tableController = [RKFetchedResultsTableController tableControllerForTableViewController:tableViewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
|
||||
RKTableItem *emptyItem = [RKTableItem tableItemWithText:@"Empty!"];
|
||||
emptyItem.cellMapping.reuseIdentifier = @"HeaderCell";
|
||||
[emptyItem.cellMapping addDefaultMappings];
|
||||
tableController.emptyItem = emptyItem;
|
||||
|
||||
RKTableItem *headerItem = [RKTableItem tableItemWithText:@"Header"];
|
||||
headerItem.cellMapping.reuseIdentifier = @"HeaderCell";
|
||||
[headerItem.cellMapping addDefaultMappings];
|
||||
[tableController addHeaderRowForItem:headerItem];
|
||||
|
||||
RKTableItem *footerItem = [RKTableItem tableItemWithText:@"Footer"];
|
||||
footerItem.cellMapping.reuseIdentifier = @"FooterCell";
|
||||
[footerItem.cellMapping addDefaultMappings];
|
||||
[tableController addFooterRowForItem:footerItem];
|
||||
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:tableViewController];
|
||||
|
||||
[RKTestNotificationObserver waitForNotificationWithName:RKTableControllerDidFinishLoadNotification usingBlock:^{
|
||||
[tableController loadTable];
|
||||
}];
|
||||
|
||||
// Let the table update
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInteger(4)));
|
||||
NSIndexPath *indexPath = [tableController indexPathForObject:emptyItem];
|
||||
assertThat(indexPath, is(nilValue()));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfEmptyItemReturnsIndexPathWhenEmpty
|
||||
{
|
||||
[self bootstrapStoreAndCache];
|
||||
[RKHuman truncateAll];
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
|
||||
UITableViewController *tableViewController = [storyboard instantiateInitialViewController];
|
||||
RKFetchedResultsTableController *tableController;
|
||||
tableController = [[RKFetchedResultsTableController tableControllerForTableViewController:tableViewController] retain];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/empty.json";
|
||||
tableController.showsFooterRowsWhenEmpty = NO;
|
||||
tableController.showsHeaderRowsWhenEmpty = NO;
|
||||
|
||||
RKTableItem *emptyItem = [RKTableItem tableItemWithText:@"Empty!"];
|
||||
emptyItem.cellMapping.reuseIdentifier = @"HeaderCell";
|
||||
[emptyItem.cellMapping addDefaultMappings];
|
||||
tableController.emptyItem = emptyItem;
|
||||
|
||||
RKTableItem *headerItem = [RKTableItem tableItemWithText:@"Header"];
|
||||
headerItem.cellMapping.reuseIdentifier = @"HeaderCell";
|
||||
[headerItem.cellMapping addDefaultMappings];
|
||||
[tableController addHeaderRowForItem:headerItem];
|
||||
|
||||
RKTableItem *footerItem = [RKTableItem tableItemWithText:@"Footer"];
|
||||
footerItem.cellMapping.reuseIdentifier = @"FooterCell";
|
||||
[footerItem.cellMapping addDefaultMappings];
|
||||
[tableController addFooterRowForItem:footerItem];
|
||||
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:tableViewController];
|
||||
|
||||
[RKTestNotificationObserver waitForNotificationWithName:RKTableControllerDidFinishLoadNotification usingBlock:^{
|
||||
[tableController loadTable];
|
||||
}];
|
||||
|
||||
// Let the table update
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInteger(1)));
|
||||
NSIndexPath *indexPath = [tableController indexPathForObject:emptyItem];
|
||||
assertThatInteger(indexPath.section, is(equalToInteger(0)));
|
||||
assertThatInteger(indexPath.row, is(equalToInteger(0)));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
1
Tests/Fixtures/JSON/humans/empty.json
Normal file
1
Tests/Fixtures/JSON/humans/empty.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
Reference in New Issue
Block a user