mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-06-19 01:56:29 +08:00
Merge branch 'release/0.10.1' into development
This commit is contained in:
@@ -42,7 +42,17 @@ extern NSString * const RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubs
|
||||
Programmatically configured values take precedence over the user info
|
||||
dictionary.
|
||||
*/
|
||||
@property (nonatomic, retain) NSString *primaryKeyAttribute;
|
||||
@property (nonatomic, retain) NSString *primaryKeyAttributeName;
|
||||
|
||||
/**
|
||||
The attribute description object for the attribute designated as the primary key for the receiver.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSAttributeDescription *primaryKeyAttribute;
|
||||
|
||||
/**
|
||||
The class representing the value of the attribute designated as the primary key for the receiver.
|
||||
*/
|
||||
@property (nonatomic, readonly) Class primaryKeyAttributeClass;
|
||||
|
||||
/**
|
||||
Returns a cached predicate specifying that the primary key attribute is equal to the $PRIMARY_KEY_VALUE
|
||||
@@ -61,9 +71,23 @@ extern NSString * const RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubs
|
||||
value. This predicate is constructed by evaluating the cached predicate returned by the
|
||||
predicateForPrimaryKeyAttribute with a dictionary of substitution variables specifying that
|
||||
$PRIMARY_KEY_VALUE is equal to the given value.
|
||||
|
||||
|
||||
**NOTE**: This method considers the type of the receiver's primary key attribute when constructing
|
||||
the predicate. It will coerce the given value into either an NSString or an NSNumber as
|
||||
appropriate. This behavior is a convenience to avoid annoying issues related to Core Data's
|
||||
handling of predicates for NSString and NSNumber types that were not appropriately casted.
|
||||
|
||||
@return A predicate speciying that the value of the primary key attribute is equal to a given value.
|
||||
*/
|
||||
- (NSPredicate *)predicateForPrimaryKeyAttributeWithValue:(id)value;
|
||||
|
||||
/**
|
||||
Coerces the given value into the class representing the primary key. Currently support NSString
|
||||
and NSNumber coercsions.
|
||||
|
||||
@bug **NOTE** This API is temporary and will be deprecated and replaced.
|
||||
@since 0.10.1
|
||||
*/
|
||||
- (id)coerceValueForPrimaryKey:(id)primaryKeyValue;
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
NSString * const RKEntityDescriptionPrimaryKeyAttributeUserInfoKey = @"primaryKeyAttribute";
|
||||
NSString * const RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubstitutionVariable = @"PRIMARY_KEY_VALUE";
|
||||
|
||||
static char primaryKeyAttributeKey, primaryKeyPredicateKey;
|
||||
static char primaryKeyAttributeNameKey, primaryKeyPredicateKey;
|
||||
|
||||
@implementation NSEntityDescription (RKAdditions)
|
||||
|
||||
- (void)setPredicateForPrimaryKeyAttribute:(NSString *)primaryKeyAttribute
|
||||
{
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == $PRIMARY_KEY_VALUE", primaryKeyAttribute];
|
||||
NSPredicate *predicate = (primaryKeyAttribute) ? [NSPredicate predicateWithFormat:@"%K == $PRIMARY_KEY_VALUE", primaryKeyAttribute] : nil;
|
||||
objc_setAssociatedObject(self,
|
||||
&primaryKeyPredicateKey,
|
||||
predicate,
|
||||
@@ -27,10 +27,25 @@ static char primaryKeyAttributeKey, primaryKeyPredicateKey;
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (NSString *)primaryKeyAttribute
|
||||
- (NSAttributeDescription *)primaryKeyAttribute
|
||||
{
|
||||
return [[self attributesByName] valueForKey:[self primaryKeyAttributeName]];
|
||||
}
|
||||
|
||||
- (Class)primaryKeyAttributeClass
|
||||
{
|
||||
NSAttributeDescription *attributeDescription = [self primaryKeyAttribute];
|
||||
if (attributeDescription) {
|
||||
return NSClassFromString(attributeDescription.attributeValueClassName);
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)primaryKeyAttributeName
|
||||
{
|
||||
// Check for an associative object reference
|
||||
NSString *primaryKeyAttribute = (NSString *) objc_getAssociatedObject(self, &primaryKeyAttributeKey);
|
||||
NSString *primaryKeyAttribute = (NSString *) objc_getAssociatedObject(self, &primaryKeyAttributeNameKey);
|
||||
|
||||
// Fall back to the userInfo dictionary
|
||||
if (! primaryKeyAttribute) {
|
||||
@@ -45,24 +60,46 @@ static char primaryKeyAttributeKey, primaryKeyPredicateKey;
|
||||
return primaryKeyAttribute;
|
||||
}
|
||||
|
||||
- (void)setPrimaryKeyAttribute:(NSString *)primaryKeyAttribute
|
||||
- (void)setPrimaryKeyAttributeName:(NSString *)primaryKeyAttributeName
|
||||
{
|
||||
objc_setAssociatedObject(self,
|
||||
&primaryKeyAttributeKey,
|
||||
primaryKeyAttribute,
|
||||
&primaryKeyAttributeNameKey,
|
||||
primaryKeyAttributeName,
|
||||
OBJC_ASSOCIATION_RETAIN);
|
||||
[self setPredicateForPrimaryKeyAttribute:primaryKeyAttribute];
|
||||
[self setPredicateForPrimaryKeyAttribute:primaryKeyAttributeName];
|
||||
}
|
||||
|
||||
|
||||
- (NSPredicate *)predicateForPrimaryKeyAttribute
|
||||
{
|
||||
return (NSPredicate *) objc_getAssociatedObject(self, &primaryKeyPredicateKey);
|
||||
}
|
||||
|
||||
- (id)coerceValueForPrimaryKey:(id)primaryKeyValue
|
||||
{
|
||||
id searchValue = primaryKeyValue;
|
||||
Class theClass = [self primaryKeyAttributeClass];
|
||||
if (theClass) {
|
||||
// TODO: This coercsion behavior should be pluggable and reused from the mapper
|
||||
if ([theClass isSubclassOfClass:[NSNumber class]] && ![searchValue isKindOfClass:[NSNumber class]]) {
|
||||
// Handle NSString -> NSNumber
|
||||
if ([searchValue isKindOfClass:[NSString class]]) {
|
||||
searchValue = [NSNumber numberWithDouble:[searchValue doubleValue]];
|
||||
}
|
||||
} else if ([theClass isSubclassOfClass:[NSString class]] && ![searchValue isKindOfClass:[NSString class]]) {
|
||||
// Coerce to string
|
||||
if ([searchValue respondsToSelector:@selector(stringValue)]) {
|
||||
searchValue = [searchValue stringValue];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return searchValue;
|
||||
}
|
||||
|
||||
- (NSPredicate *)predicateForPrimaryKeyAttributeWithValue:(id)value
|
||||
{
|
||||
NSDictionary *variables = [NSDictionary dictionaryWithObject:value
|
||||
id substitutionValue = [self coerceValueForPrimaryKey:value];
|
||||
NSDictionary *variables = [NSDictionary dictionaryWithObject:substitutionValue
|
||||
forKey:RKEntityDescriptionPrimaryKeyAttributeValuePredicateSubstitutionVariable];
|
||||
return [[self predicateForPrimaryKeyAttribute] predicateWithSubstitutionVariables:variables];
|
||||
}
|
||||
|
||||
@@ -138,14 +138,13 @@ RK_FIX_CATEGORY_BUG(NSManagedObject_ActiveRecord)
|
||||
}
|
||||
|
||||
+ (id)findByPrimaryKey:(id)primaryKeyValue inContext:(NSManagedObjectContext *)context {
|
||||
NSEntityDescription *entity = [self entityDescriptionInContext:context];
|
||||
NSString *primaryKeyAttribute = entity.primaryKeyAttribute;
|
||||
if (! primaryKeyAttribute) {
|
||||
RKLogWarning(@"Attempt to findByPrimaryKey for entity with nil primaryKeyAttribute. Set the primaryKeyAttribute and try again! %@", entity);
|
||||
NSPredicate *predicate = [[self entityDescriptionInContext:context] predicateForPrimaryKeyAttributeWithValue:primaryKeyValue];
|
||||
if (! predicate) {
|
||||
RKLogWarning(@"Attempt to findByPrimaryKey for entity with nil primaryKeyAttribute. Set the primaryKeyAttributeName and try again! %@", self);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [self findFirstByAttribute:primaryKeyAttribute withValue:primaryKeyValue inContext:context];
|
||||
|
||||
return [self findFirstWithPredicate:predicate inContext:context];
|
||||
}
|
||||
|
||||
+ (id)findByPrimaryKey:(id)primaryKeyValue {
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
|
||||
- (void)load
|
||||
{
|
||||
RKLogInfo(@"Loading entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute);
|
||||
RKLogDebug(@"Loading entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute);
|
||||
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
|
||||
[fetchRequest setEntity:self.entity];
|
||||
[fetchRequest setResultType:NSManagedObjectIDResultType];
|
||||
@@ -126,7 +126,7 @@
|
||||
|
||||
- (void)flush
|
||||
{
|
||||
RKLogInfo(@"Flushing entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute);
|
||||
RKLogDebug(@"Flushing entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute);
|
||||
self.attributeValuesToObjectIDs = nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
// Use cached predicate if primary key matches
|
||||
NSPredicate *predicate = nil;
|
||||
if ([entity.primaryKeyAttribute isEqualToString:primaryKeyAttribute]) {
|
||||
if ([entity.primaryKeyAttributeName isEqualToString:primaryKeyAttribute]) {
|
||||
predicate = [entity predicateForPrimaryKeyAttributeWithValue:searchValue];
|
||||
} else {
|
||||
// Parse a predicate
|
||||
|
||||
@@ -182,7 +182,8 @@
|
||||
object = [[[NSManagedObject alloc] initWithEntity:entity
|
||||
insertIntoManagedObjectContext:[_objectStore managedObjectContextForCurrentThread]] autorelease];
|
||||
if (primaryKeyAttribute && primaryKeyValue && ![primaryKeyValue isEqual:[NSNull null]]) {
|
||||
[object setValue:primaryKeyValue forKey:primaryKeyAttribute];
|
||||
id coercedPrimaryKeyValue = [entity coerceValueForPrimaryKey:primaryKeyValue];
|
||||
[object setValue:coercedPrimaryKeyValue forKey:primaryKeyAttribute];
|
||||
}
|
||||
|
||||
if ([self.objectStore.cacheStrategy respondsToSelector:@selector(didCreateObject:)]) {
|
||||
@@ -202,17 +203,17 @@
|
||||
}
|
||||
|
||||
/*
|
||||
Allows the primaryKeyAttribute property on the NSEntityDescription to configure the mapping and vice-versa
|
||||
Allows the primaryKeyAttributeName property on the NSEntityDescription to configure the mapping and vice-versa
|
||||
*/
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
if ([keyPath isEqualToString:@"entity"]) {
|
||||
if (! self.primaryKeyAttribute) {
|
||||
self.primaryKeyAttribute = [self.entity primaryKeyAttribute];
|
||||
self.primaryKeyAttribute = [self.entity primaryKeyAttributeName];
|
||||
}
|
||||
} else if ([keyPath isEqualToString:@"primaryKeyAttribute"]) {
|
||||
if (! self.entity.primaryKeyAttribute) {
|
||||
self.entity.primaryKeyAttribute = self.primaryKeyAttribute;
|
||||
self.entity.primaryKeyAttributeName = self.primaryKeyAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ RKRequestMethod RKRequestMethodTypeFromName(NSString *methodName) {
|
||||
@interface RKRequest ()
|
||||
@property (nonatomic, assign, readwrite, getter = isLoaded) BOOL loaded;
|
||||
@property (nonatomic, assign, readwrite, getter = isLoading) BOOL loading;
|
||||
@property (nonatomic, assign, readwrite) BOOL canceled;
|
||||
@property (nonatomic, assign, readwrite, getter = isCancelled) BOOL cancelled;
|
||||
@property (nonatomic, retain, readwrite) RKResponse *response;
|
||||
@end
|
||||
|
||||
@@ -123,13 +123,12 @@ RKRequestMethod RKRequestMethodTypeFromName(NSString *methodName) {
|
||||
@synthesize onDidFailLoadWithError;
|
||||
@synthesize additionalRootCertificates = _additionalRootCertificates;
|
||||
@synthesize disableCertificateValidation = _disableCertificateValidation;
|
||||
@synthesize cancelled = _cancelled;
|
||||
@synthesize followRedirect = _followRedirect;
|
||||
@synthesize runLoopMode = _runLoopMode;
|
||||
@synthesize loaded = _loaded;
|
||||
@synthesize loading = _loading;
|
||||
@synthesize canceled = _canceled;
|
||||
@synthesize response = _response;
|
||||
@synthesize cancelled = _cancelled;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
@synthesize backgroundPolicy = _backgroundPolicy;
|
||||
@@ -184,7 +183,7 @@ RKRequestMethod RKRequestMethodTypeFromName(NSString *methodName) {
|
||||
_connection = nil;
|
||||
self.loading = NO;
|
||||
self.loaded = NO;
|
||||
self.canceled = NO;
|
||||
self.cancelled = NO;
|
||||
}
|
||||
|
||||
- (void)cleanupBackgroundTask {
|
||||
@@ -407,7 +406,7 @@ RKRequestMethod RKRequestMethodTypeFromName(NSString *methodName) {
|
||||
}
|
||||
|
||||
- (void)cancelAndInformDelegate:(BOOL)informDelegate {
|
||||
_cancelled = YES;
|
||||
self.cancelled = YES;
|
||||
[_connection cancel];
|
||||
[_connection release];
|
||||
_connection = nil;
|
||||
@@ -436,7 +435,7 @@ RKRequestMethod RKRequestMethodTypeFromName(NSString *methodName) {
|
||||
- (void)fireAsynchronousRequest {
|
||||
RKLogDebug(@"Sending asynchronous %@ request to URL %@.", [self HTTPMethod], [[self URL] absoluteString]);
|
||||
if (![self prepareURLRequest]) {
|
||||
// TODO: Logging
|
||||
RKLogWarning(@"Failed to send request asynchronously: prepareURLRequest returned NO.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -565,7 +564,7 @@ RKRequestMethod RKRequestMethodTypeFromName(NSString *methodName) {
|
||||
RKLogDebug(@"Sending synchronous %@ request to URL %@.", [self HTTPMethod], [[self URL] absoluteString]);
|
||||
|
||||
if (![self prepareURLRequest]) {
|
||||
// TODO: Logging
|
||||
RKLogWarning(@"Failed to send request synchronously: prepareURLRequest returned NO.");
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
reference and canceling the request.
|
||||
|
||||
Useful when an object that acts as the delegate for one or more requests
|
||||
is being deallocated and all outstanding requests should be canceled
|
||||
is being deallocated and all outstanding requests should be cancelled
|
||||
without generating any further delegate callbacks.
|
||||
|
||||
@param delegate The object acting as the delegate for all enqueued requests that are to be aborted.
|
||||
@@ -314,7 +314,7 @@
|
||||
- (void)requestQueue:(RKRequestQueue *)queue didLoadResponse:(RKResponse *)response;
|
||||
|
||||
/**
|
||||
Sent when queue has canceled a request.
|
||||
Sent when queue has cancelled a request.
|
||||
|
||||
@param queue The queue that cancelled the request.
|
||||
@param request The cancelled request.
|
||||
|
||||
@@ -389,7 +389,7 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
|
||||
- (void)cancelRequest:(RKRequest*)request loadNext:(BOOL)loadNext {
|
||||
if ([request isUnsent]) {
|
||||
RKLogDebug(@"Canceled undispatched request %@ and removed from queue %@", request, self);
|
||||
RKLogDebug(@"Cancelled undispatched request %@ and removed from queue %@", request, self);
|
||||
|
||||
[self removeRequest:request];
|
||||
request.delegate = nil;
|
||||
@@ -398,7 +398,7 @@ static const NSTimeInterval kFlushDelay = 0.3;
|
||||
[_delegate requestQueue:self didCancelRequest:request];
|
||||
}
|
||||
} else if ([self containsRequest:request] && [request isLoading]) {
|
||||
RKLogDebug(@"Canceled loading request %@ and removed from queue %@", request, self);
|
||||
RKLogDebug(@"Cancelled loading request %@ and removed from queue %@", request, self);
|
||||
|
||||
[request cancel];
|
||||
request.delegate = nil;
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
- (void)finalizeLoad:(BOOL)successful {
|
||||
self.loading = NO;
|
||||
self.loaded = successful;
|
||||
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(objectLoaderDidFinishLoading:)]) {
|
||||
[(NSObject<RKObjectLoaderDelegate>*)self.delegate performSelectorOnMainThread:@selector(objectLoaderDidFinishLoading:)
|
||||
withObject:self waitUntilDone:YES];
|
||||
@@ -407,7 +407,10 @@
|
||||
object:self
|
||||
userInfo:userInfo];
|
||||
}
|
||||
[self informDelegateOfError:error];
|
||||
|
||||
if (! self.isCancelled) {
|
||||
[self informDelegateOfError:error];
|
||||
}
|
||||
|
||||
[self finalizeLoad:NO];
|
||||
}
|
||||
|
||||
@@ -138,6 +138,12 @@ lcl_configure_by_name("App", level);
|
||||
} \
|
||||
} while(false);
|
||||
|
||||
/**
|
||||
Temporarily turns off logging for the given logging component during execution of the block.
|
||||
After the block has finished execution, the logging level is restored to its previous state.
|
||||
*/
|
||||
#define RKLogSilenceComponentWhileExecutingBlock(component, _block) \
|
||||
RKLogToComponentWithLevelWhileExecutingBlock(component, RKLogLevelOff, _block)
|
||||
|
||||
/**
|
||||
Temporarily changes the logging level for the configured RKLogComponent and executes the block. Any logging
|
||||
@@ -149,7 +155,7 @@ lcl_configure_by_name("App", level);
|
||||
|
||||
|
||||
/**
|
||||
Temporarily turns off logging for the execution of the block.
|
||||
Temporarily turns off logging for current logging component during execution of the block.
|
||||
After the block has finished execution, the logging level is restored to its previous state.
|
||||
*/
|
||||
#define RKLogSilenceWhileExecutingBlock(_block) \
|
||||
@@ -205,3 +211,9 @@ void RKLogConfigureFromEnvironment(void);
|
||||
of a failed key-value validation error.
|
||||
*/
|
||||
void RKLogValidationError(NSError *);
|
||||
|
||||
/**
|
||||
Logs the value of an NSUInteger as a binary string. Useful when
|
||||
examining integers containing bitmasked values.
|
||||
*/
|
||||
void RKLogIntegerAsBinary(NSUInteger);
|
||||
|
||||
@@ -159,3 +159,13 @@ void RKLogValidationError(NSError *validationError) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RKLogIntegerAsBinary(NSUInteger bitMask) {
|
||||
NSUInteger bit = ~(NSUIntegerMax >> 1);
|
||||
NSMutableString *string = [NSMutableString string];
|
||||
do {
|
||||
[string appendString:(((NSUInteger)bitMask & bit) ? @"1" : @"0")];
|
||||
} while ( bit >>= 1 );
|
||||
|
||||
NSLog(@"Value of %ld in binary: %@", (long) bitMask, string);
|
||||
}
|
||||
|
||||
31
Code/Testing/RKTableControllerTestDelegate.h
Normal file
31
Code/Testing/RKTableControllerTestDelegate.h
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// RKTableControllerTestDelegate.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 5/23/12.
|
||||
// Copyright (c) 2012 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "RKTableController.h"
|
||||
#import "RKFetchedResultsTableController.h"
|
||||
|
||||
@interface RKAbstractTableControllerTestDelegate : NSObject <RKAbstractTableControllerDelegate>
|
||||
|
||||
@property(nonatomic, readonly, getter = isCancelled) BOOL cancelled;
|
||||
@property(nonatomic, assign) NSTimeInterval timeout;
|
||||
@property(nonatomic, assign) BOOL awaitingResponse;
|
||||
|
||||
+ (id)tableControllerDelegate;
|
||||
- (void)waitForLoad;
|
||||
|
||||
@end
|
||||
|
||||
@interface RKTableControllerTestDelegate : RKAbstractTableControllerTestDelegate <RKTableControllerDelegate>
|
||||
@end
|
||||
|
||||
@interface RKFetchedResultsTableControllerTestDelegate : RKAbstractTableControllerTestDelegate <RKFetchedResultsTableControllerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
139
Code/Testing/RKTableControllerTestDelegate.m
Normal file
139
Code/Testing/RKTableControllerTestDelegate.m
Normal file
@@ -0,0 +1,139 @@
|
||||
//
|
||||
// RKTableControllerTestDelegate.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 5/23/12.
|
||||
// Copyright (c) 2012 RestKit. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKTableControllerTestDelegate.h"
|
||||
#import "RKLog.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
@implementation RKAbstractTableControllerTestDelegate
|
||||
|
||||
@synthesize timeout = _timeout;
|
||||
@synthesize awaitingResponse = _awaitingResponse;
|
||||
@synthesize cancelled = _cancelled;
|
||||
|
||||
+ (id)tableControllerDelegate {
|
||||
return [[self new] autorelease];
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_timeout = 1.0;
|
||||
_awaitingResponse = NO;
|
||||
_cancelled = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)waitForLoad {
|
||||
_awaitingResponse = YES;
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
while (_awaitingResponse) {
|
||||
RKLogTrace(@"Awaiting response = %d", _awaitingResponse);
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
if ([[NSDate date] timeIntervalSinceDate:startDate] > self.timeout) {
|
||||
NSLog(@"%@: Timed out!!!", self);
|
||||
_awaitingResponse = NO;
|
||||
[NSException raise:nil format:@"*** Operation timed out after %f seconds...", self.timeout];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma RKTableControllerDelegate methods
|
||||
|
||||
- (void)tableControllerDidFinishLoad:(RKAbstractTableController *)tableController {
|
||||
_awaitingResponse = NO;
|
||||
}
|
||||
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didFailLoadWithError:(NSError *)error {
|
||||
_awaitingResponse = NO;
|
||||
}
|
||||
|
||||
- (void)tableControllerDidCancelLoad:(RKAbstractTableController *)tableController {
|
||||
_awaitingResponse = NO;
|
||||
_cancelled = YES;
|
||||
}
|
||||
|
||||
- (void)tableControllerDidFinalizeLoad:(RKAbstractTableController *)tableController {
|
||||
_awaitingResponse = NO;
|
||||
}
|
||||
|
||||
// NOTE - Delegate methods below are implemented to allow trampoline through
|
||||
// OCMock expectations
|
||||
|
||||
- (void)tableControllerDidStartLoad:(RKAbstractTableController *)tableController
|
||||
{}
|
||||
|
||||
- (void)tableControllerDidBecomeEmpty:(RKAbstractTableController *)tableController
|
||||
{}
|
||||
|
||||
- (void)tableController:(RKAbstractTableController *)tableController willLoadTableWithObjectLoader:(RKObjectLoader *)objectLoader
|
||||
{}
|
||||
|
||||
- (void)tableController:(RKAbstractTableController *)tableController didLoadTableWithObjectLoader:(RKObjectLoader *)objectLoader
|
||||
{}
|
||||
|
||||
- (void)tableController:(RKAbstractTableController*)tableController willBeginEditing:(id)object atIndexPath:(NSIndexPath*)indexPath
|
||||
{}
|
||||
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didEndEditing:(id)object atIndexPath:(NSIndexPath*)indexPath
|
||||
{}
|
||||
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didInsertSection:(RKTableSection*)section atIndex:(NSUInteger)sectionIndex
|
||||
{}
|
||||
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didRemoveSection:(RKTableSection*)section atIndex:(NSUInteger)sectionIndex
|
||||
{}
|
||||
|
||||
- (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
|
||||
{}
|
||||
|
||||
- (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
|
||||
{}
|
||||
|
||||
- (void)tableController:(RKTableController *)tableController didLoadObjects:(NSArray *)objects inSection:(NSUInteger)sectionIndex
|
||||
{}
|
||||
|
||||
- (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
|
||||
{}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RKTableControllerTestDelegate
|
||||
|
||||
- (void)tableController:(RKTableController *)tableController didLoadObjects:(NSArray *)objects inSection:(RKTableSection *)section
|
||||
{}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RKFetchedResultsTableControllerTestDelegate
|
||||
|
||||
- (void)tableController:(RKFetchedResultsTableController *)tableController didInsertSectionAtIndex:(NSUInteger)sectionIndex
|
||||
{}
|
||||
|
||||
- (void)tableController:(RKFetchedResultsTableController *)tableController didDeleteSectionAtIndex:(NSUInteger)sectionIndex
|
||||
{}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -77,20 +77,32 @@ static RKTestFactory *sharedFactory = nil;
|
||||
- (void)defineDefaultFactories
|
||||
{
|
||||
[self defineFactory:RKTestFactoryDefaultNamesClient withBlock:^id {
|
||||
RKClient *client = [RKClient clientWithBaseURL:self.baseURL];
|
||||
client.requestQueue.suspended = NO;
|
||||
[client.reachabilityObserver getFlags];
|
||||
__block RKClient *client;
|
||||
|
||||
RKLogSilenceComponentWhileExecutingBlock(lcl_cRestKitNetworkReachability, ^{
|
||||
RKLogSilenceComponentWhileExecutingBlock(lcl_cRestKitSupport, ^{
|
||||
client = [RKClient clientWithBaseURL:self.baseURL];
|
||||
client.requestQueue.suspended = NO;
|
||||
[client.reachabilityObserver getFlags];
|
||||
});
|
||||
});
|
||||
|
||||
return client;
|
||||
}];
|
||||
|
||||
[self defineFactory:RKTestFactoryDefaultNamesObjectManager withBlock:^id {
|
||||
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:self.baseURL];
|
||||
RKObjectMappingProvider *mappingProvider = [self objectFromFactory:RKTestFactoryDefaultNamesMappingProvider];
|
||||
objectManager.mappingProvider = mappingProvider;
|
||||
|
||||
// Force reachability determination
|
||||
[objectManager.client.reachabilityObserver getFlags];
|
||||
__block RKObjectManager *objectManager;
|
||||
|
||||
RKLogSilenceComponentWhileExecutingBlock(lcl_cRestKitNetworkReachability, ^{
|
||||
RKLogSilenceComponentWhileExecutingBlock(lcl_cRestKitSupport, ^{
|
||||
objectManager = [RKObjectManager managerWithBaseURL:self.baseURL];
|
||||
RKObjectMappingProvider *mappingProvider = [self objectFromFactory:RKTestFactoryDefaultNamesMappingProvider];
|
||||
objectManager.mappingProvider = mappingProvider;
|
||||
|
||||
// Force reachability determination
|
||||
[objectManager.client.reachabilityObserver getFlags];
|
||||
});
|
||||
});
|
||||
|
||||
return objectManager;
|
||||
}];
|
||||
@@ -194,7 +206,12 @@ static RKTestFactory *sharedFactory = nil;
|
||||
{
|
||||
[RKObjectManager setDefaultMappingQueue:dispatch_queue_create("org.restkit.ObjectMapping", DISPATCH_QUEUE_SERIAL)];
|
||||
[RKObjectMapping setDefaultDateFormatters:nil];
|
||||
[RKManagedObjectStore deleteStoreInApplicationDataDirectoryWithFilename:RKTestFactoryDefaultStoreFilename];
|
||||
|
||||
// Delete the store if it exists
|
||||
NSString *path = [[RKDirectory applicationDataDirectory] stringByAppendingPathComponent:RKTestFactoryDefaultStoreFilename];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||
[RKManagedObjectStore deleteStoreInApplicationDataDirectoryWithFilename:RKTestFactoryDefaultStoreFilename];
|
||||
}
|
||||
|
||||
if ([self respondsToSelector:@selector(didSetUp)]) {
|
||||
[self didSetUp];
|
||||
@@ -218,7 +235,7 @@ static RKTestFactory *sharedFactory = nil;
|
||||
NSString* cachePath = [RKDirectory cachesDirectory];
|
||||
BOOL success = [[NSFileManager defaultManager] removeItemAtPath:cachePath error:&error];
|
||||
if (success) {
|
||||
RKLogInfo(@"Cleared cache directory...");
|
||||
RKLogDebug(@"Cleared cache directory...");
|
||||
success = [[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:&error];
|
||||
if (!success) {
|
||||
RKLogError(@"Failed creation of cache path '%@': %@", cachePath, [error localizedDescription]);
|
||||
|
||||
@@ -21,60 +21,102 @@
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "RKTableSection.h"
|
||||
#import "RKTableViewCellMappings.h"
|
||||
#import "RKTableItem.h"
|
||||
#import "RKObjectManager.h"
|
||||
#import "RKObjectMapping.h"
|
||||
#import "RKObjectLoader.h"
|
||||
|
||||
/** @name Constants */
|
||||
|
||||
/** Posted when the table view model starts loading */
|
||||
extern NSString* const RKTableControllerDidStartLoadNotification;
|
||||
|
||||
/** Posted when the table view model finishes loading */
|
||||
extern NSString* const RKTableControllerDidFinishLoadNotification;
|
||||
|
||||
/** Posted when the table view model has loaded objects into the table view */
|
||||
extern NSString* const RKTableControllerDidLoadObjectsNotification;
|
||||
|
||||
/** Posted when the table view model has loaded an empty collection of objects into the table view */
|
||||
extern NSString* const RKTableControllerDidLoadEmptyNotification;
|
||||
|
||||
/** Posted when the table view model has loaded an error */
|
||||
extern NSString* const RKTableControllerDidLoadErrorNotification;
|
||||
|
||||
/** Posted when the table view model has transitioned from offline to online */
|
||||
extern NSString* const RKTableControllerDidBecomeOnline;
|
||||
|
||||
/** Posted when the table view model has transitioned from online to offline */
|
||||
extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
|
||||
@protocol RKTableControllerDelegate;
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @name Constants
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
RestKit's table view abstraction leverages the object mapping engine to transform
|
||||
local objects into UITableViewCell representations. The table view model encapsulates
|
||||
the functionality of a UITableView dataSource and delegate into a single reusable
|
||||
component.
|
||||
Posted when the table controller starts loading.
|
||||
*/
|
||||
@interface RKAbstractTableController : NSObject <UITableViewDataSource, UITableViewDelegate> {
|
||||
@protected
|
||||
UIView *_tableOverlayView;
|
||||
UIImageView *_stateOverlayImageView;
|
||||
UIView *_pullToRefreshHeaderView;
|
||||
RKCache *_cache;
|
||||
}
|
||||
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 RKTableControllerState {
|
||||
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<RKTableControllerDelegate> delegate;
|
||||
@property (nonatomic, readonly) UIViewController* viewController;
|
||||
@property (nonatomic, readonly) UITableView* tableView;
|
||||
@property (nonatomic, readonly) NSMutableArray* sections;
|
||||
@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;
|
||||
@@ -82,38 +124,39 @@ extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
@property (nonatomic, assign) BOOL canMoveRows;
|
||||
@property (nonatomic, assign) BOOL autoResizesForKeyboard;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @name Instantiation
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
+ (id)tableControllerWithTableView:(UITableView*)tableView
|
||||
forViewController:(UIViewController*)viewController;
|
||||
+ (id)tableControllerWithTableView:(UITableView *)tableView
|
||||
forViewController:(UIViewController *)viewController;
|
||||
|
||||
+ (id)tableControllerForTableViewController:(UITableViewController*)tableViewController;
|
||||
+ (id)tableControllerForTableViewController:(UITableViewController *)tableViewController;
|
||||
|
||||
- (id)initWithTableView:(UITableView*)tableView
|
||||
viewController:(UIViewController*)viewController;
|
||||
- (id)initWithTableView:(UITableView *)tableView
|
||||
viewController:(UIViewController *)viewController;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @name Object to Table View Cell Mappings
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
@property (nonatomic, retain) RKTableViewCellMappings* cellMappings;
|
||||
@property (nonatomic, retain) RKTableViewCellMappings *cellMappings;
|
||||
|
||||
- (void)mapObjectsWithClass:(Class)objectClass toTableCellsWithMapping:(RKTableViewCellMapping*)cellMapping;
|
||||
- (void)mapObjectsWithClassName:(NSString *)objectClassName toTableCellsWithMapping:(RKTableViewCellMapping*)cellMapping;
|
||||
- (void)mapObjectsWithClass:(Class)objectClass toTableCellsWithMapping:(RKTableViewCellMapping *)cellMapping;
|
||||
- (void)mapObjectsWithClassName:(NSString *)objectClassName toTableCellsWithMapping:(RKTableViewCellMapping *)cellMapping;
|
||||
- (id)objectForRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
- (RKTableViewCellMapping*)cellMappingForObjectAtIndexPath:(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;
|
||||
@@ -122,12 +165,12 @@ extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
- (void)removeAllHeaderRows;
|
||||
- (void)removeAllFooterRows;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @name RESTful Table Loading
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
The object manager instance this table view model is associated with.
|
||||
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.
|
||||
@@ -144,42 +187,102 @@ extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
- (void)cancelLoad;
|
||||
- (BOOL)isAutoRefreshNeeded;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
/// @name Model State Views
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @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;
|
||||
|
||||
@property (nonatomic, readonly) BOOL isError;
|
||||
@property (nonatomic, readonly, retain) NSError* error;
|
||||
/**
|
||||
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 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
|
||||
within the table view.
|
||||
*/
|
||||
// TODO: Should be emptyImage
|
||||
@property (nonatomic, retain) UIImage* imageForEmpty;
|
||||
@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.
|
||||
*/
|
||||
// TODO: Should be errorImage
|
||||
@property (nonatomic, retain) UIImage* imageForError;
|
||||
@property (nonatomic, retain) UIImage *imageForError;
|
||||
|
||||
/**
|
||||
An image to overlay onto the table with when the user does
|
||||
not have connectivity to the Internet
|
||||
not have connectivity to the Internet.
|
||||
|
||||
@see RKReachabilityObserver
|
||||
*/
|
||||
// TODO: Should be offlineImage
|
||||
@property (nonatomic, retain) UIImage* imageForOffline;
|
||||
@property (nonatomic, retain) UIImage *imageForOffline;
|
||||
|
||||
/**
|
||||
A UIView to add to the table overlay during loading. It
|
||||
@@ -187,7 +290,19 @@ extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
|
||||
The loading view is always presented non-modally.
|
||||
*/
|
||||
@property (nonatomic, retain) UIView* loadingView;
|
||||
@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
|
||||
@@ -200,6 +315,11 @@ extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
*/
|
||||
@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
|
||||
@@ -213,54 +333,47 @@ extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
@property (nonatomic, assign) BOOL variableHeightRows;
|
||||
@property (nonatomic, assign) BOOL showsHeaderRowsWhenEmpty;
|
||||
@property (nonatomic, assign) BOOL showsFooterRowsWhenEmpty;
|
||||
@property (nonatomic, retain) RKTableItem* emptyItem;
|
||||
@property (nonatomic, retain) RKTableItem *emptyItem;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @name Managing Sections
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
/** The number of sections in the model. */
|
||||
/**
|
||||
The number of sections in the table.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger sectionCount;
|
||||
|
||||
/** The number of rows across all sections in the model. */
|
||||
/**
|
||||
The number of rows across all sections in the model.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger rowCount;
|
||||
|
||||
/** Returns the section at the specified index.
|
||||
* @param index Must be less than the total number of sections. */
|
||||
- (RKTableSection *)sectionAtIndex:(NSUInteger)index;
|
||||
|
||||
/** Returns the first section with the specified header title.
|
||||
* @param title The header title. */
|
||||
- (RKTableSection *)sectionWithHeaderTitle:(NSString *)title;
|
||||
|
||||
/**
|
||||
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
|
||||
@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.
|
||||
equal to the total number of sections in the table.
|
||||
*/
|
||||
- (NSUInteger)numberOfRowsInSectionAtIndex:(NSUInteger)index;
|
||||
- (NSUInteger)numberOfRowsInSection:(NSUInteger)index;
|
||||
|
||||
/** Returns the index of the specified section.
|
||||
* @param section Must be a valid non nil RKTableViewSection.
|
||||
* @return If section is not found, method returns NSNotFound. */
|
||||
- (NSUInteger)indexForSection:(RKTableSection *)section;
|
||||
|
||||
/** Returns the UITableViewCell created by applying the specified
|
||||
* mapping operation to the object identified by indexPath.
|
||||
* @param indexPath The indexPath in the tableView for which a cell
|
||||
* is needed. */
|
||||
/**
|
||||
Returns the UITableViewCell created by applying the specified
|
||||
mapping operation to the object identified by indexPath.
|
||||
|
||||
@param indexPath The indexPath in the tableView for which a cell is needed.
|
||||
*/
|
||||
- (UITableViewCell *)cellForObjectAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @name Managing Swipe View
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
@property (nonatomic, assign) BOOL cellSwipeViewsEnabled;
|
||||
@property (nonatomic, retain) UIView* cellSwipeView;
|
||||
@property (nonatomic, readonly) UITableViewCell* swipeCell;
|
||||
@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;
|
||||
@@ -270,46 +383,45 @@ extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
|
||||
@end
|
||||
|
||||
@protocol RKTableControllerDelegate <NSObject>
|
||||
@protocol RKAbstractTableControllerDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// Network
|
||||
- (void)tableController:(RKAbstractTableController *)tableController willLoadTableWithObjectLoader:(RKObjectLoader*)objectLoader;
|
||||
- (void)tableController:(RKAbstractTableController *)tableController didLoadTableWithObjectLoader:(RKObjectLoader*)objectLoader;
|
||||
- (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 **/
|
||||
/**
|
||||
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)tableController:(RKAbstractTableController *)tableController didFailLoadWithError:(NSError *)error;
|
||||
- (void)tableControllerDidCancelLoad:(RKAbstractTableController *)tableController;
|
||||
- (void)tableController:(RKAbstractTableController *)tableController didLoadObjects:(NSArray*)objects inSection:(NSUInteger)sectionIndex;
|
||||
|
||||
/** 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
|
||||
**/
|
||||
/**
|
||||
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; // didLoadEmpty???
|
||||
- (void)tableControllerDidBecomeEmpty:(RKAbstractTableController *)tableController;
|
||||
|
||||
/**
|
||||
Sent to the delegate when the table view model has transitioned from offline to online
|
||||
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 view model has transitioned from online to offline
|
||||
Sent to the delegate when the table controller has transitioned from online to offline
|
||||
*/
|
||||
- (void)tableControllerDidBecomeOffline:(RKAbstractTableController *)tableController;
|
||||
|
||||
// Sections
|
||||
- (void)tableController:(RKAbstractTableController *)tableController didInsertSection:(RKTableSection *)section atIndex:(NSUInteger)sectionIndex;
|
||||
- (void)tableController:(RKAbstractTableController *)tableController didRemoveSection:(RKTableSection *)section atIndex:(NSUInteger)sectionIndex;
|
||||
|
||||
// Objects
|
||||
- (void)tableController:(RKAbstractTableController *)tableController didInsertObject:(id)object atIndexPath:(NSIndexPath *)indexPath;
|
||||
- (void)tableController:(RKAbstractTableController *)tableController didUpdateObject:(id)object atIndexPath:(NSIndexPath *)indexPath;
|
||||
@@ -320,19 +432,13 @@ extern NSString* const RKTableControllerDidBecomeOffline;
|
||||
- (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;
|
||||
|
||||
// BELOW NOT YET IMPLEMENTED
|
||||
- (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;
|
||||
|
||||
// Objects
|
||||
- (void)tableControllerDidBeginUpdates:(RKAbstractTableController *)tableController;
|
||||
- (void)tableControllerDidEndUpdates:(RKAbstractTableController *)tableController;
|
||||
|
||||
@end
|
||||
|
||||
#endif // TARGET_OS_IPHONE
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,25 +18,29 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#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, readwrite, retain) RKObjectLoader* objectLoader;
|
||||
@property (nonatomic, readwrite, assign) BOOL loading;
|
||||
@property (nonatomic, readwrite, assign) BOOL loaded;
|
||||
@property (nonatomic, readwrite, assign) BOOL empty;
|
||||
@property (nonatomic, readwrite, assign) BOOL online;
|
||||
@property (nonatomic, readwrite, retain) NSError* error;
|
||||
@property (nonatomic, readwrite, retain) NSMutableArray* headerItems;
|
||||
@property (nonatomic, readwrite, retain) NSMutableArray* footerItems;
|
||||
|
||||
@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.
|
||||
@@ -45,7 +49,7 @@
|
||||
and cleaning up the table overlay view.
|
||||
*/
|
||||
- (void)didFinishLoad;
|
||||
- (void)updateOfflineImageForOnlineState:(BOOL)isOnline;
|
||||
- (void)didFailLoadWithError:(NSError *)error;
|
||||
|
||||
#pragma mark - Table View Overlay
|
||||
|
||||
@@ -61,5 +65,14 @@
|
||||
- (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
|
||||
|
||||
@@ -22,6 +22,17 @@
|
||||
|
||||
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
|
||||
*/
|
||||
@@ -33,7 +44,8 @@ typedef UIView *(^RKFetchedResultsTableViewViewForHeaderInSectionBlock)(NSUInteg
|
||||
BOOL _isEmptyBeforeAnimation;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) NSFetchedResultsController *fetchedResultsController;
|
||||
@property (nonatomic, assign) id<RKFetchedResultsTableControllerDelegate> delegate;
|
||||
@property (nonatomic, retain, readonly) NSFetchedResultsController *fetchedResultsController;
|
||||
@property (nonatomic, copy) NSString *resourcePath;
|
||||
@property (nonatomic, retain) NSFetchRequest *fetchRequest;
|
||||
@property (nonatomic, assign) CGFloat heightForHeaderInSection;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "RKFetchedResultsTableController.h"
|
||||
#import "RKAbstractTableController_Internals.h"
|
||||
#import "RKManagedObjectStore.h"
|
||||
@@ -31,12 +32,15 @@
|
||||
#define RKLogComponent lcl_cRestKitUI
|
||||
|
||||
@interface RKFetchedResultsTableController ()
|
||||
- (void)performFetch;
|
||||
@property (nonatomic, retain, readwrite) NSFetchedResultsController *fetchedResultsController;
|
||||
|
||||
- (BOOL)performFetch:(NSError **)error;
|
||||
- (void)updateSortedArray;
|
||||
@end
|
||||
|
||||
@implementation RKFetchedResultsTableController
|
||||
|
||||
@dynamic delegate;
|
||||
@synthesize fetchedResultsController = _fetchedResultsController;
|
||||
@synthesize resourcePath = _resourcePath;
|
||||
@synthesize heightForHeaderInSection = _heightForHeaderInSection;
|
||||
@@ -75,18 +79,31 @@
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (void)performFetch {
|
||||
- (BOOL)performFetch:(NSError **)error {
|
||||
// TODO: We could be doing a KVO on the predicate/sortDescriptors/sectionKeyPath and intelligently deleting the cache
|
||||
[NSFetchedResultsController deleteCacheWithName:_fetchedResultsController.cacheName];
|
||||
|
||||
NSError* error;
|
||||
BOOL success = [_fetchedResultsController performFetch:&error];
|
||||
BOOL success = [_fetchedResultsController performFetch:error];
|
||||
if (!success) {
|
||||
self.error = error;
|
||||
RKLogError(@"performFetch failed with error: %@", [error localizedDescription]);
|
||||
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 {
|
||||
@@ -217,8 +234,7 @@
|
||||
} else {
|
||||
fetchRequest = _fetchRequest;
|
||||
}
|
||||
NSAssert(fetchRequest != nil, @"Attempted to load RKFetchedResultsTableController with nil fetchRequest for resourcePath %@, fetchRequest %@",
|
||||
_resourcePath, _fetchRequest);
|
||||
NSAssert(fetchRequest != nil, @"Attempted to load RKFetchedResultsTableController with nil fetchRequest for resourcePath %@, fetchRequest %@", _resourcePath, _fetchRequest);
|
||||
|
||||
if (_predicate) {
|
||||
[fetchRequest setPredicate:_predicate];
|
||||
@@ -226,21 +242,21 @@
|
||||
if (_sortDescriptors) {
|
||||
[fetchRequest setSortDescriptors:_sortDescriptors];
|
||||
}
|
||||
|
||||
[_fetchedResultsController setDelegate:nil];
|
||||
[_fetchedResultsController release];
|
||||
_fetchedResultsController = nil;
|
||||
|
||||
_fetchedResultsController =
|
||||
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
|
||||
managedObjectContext:[NSManagedObjectContext contextForCurrentThread]
|
||||
sectionNameKeyPath:_sectionNameKeyPath
|
||||
cacheName:_cacheName];
|
||||
|
||||
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
|
||||
managedObjectContext:[NSManagedObjectContext contextForCurrentThread]
|
||||
sectionNameKeyPath:_sectionNameKeyPath
|
||||
cacheName:_cacheName];
|
||||
_fetchedResultsController.delegate = self;
|
||||
|
||||
[self performFetch];
|
||||
|
||||
// Perform the load
|
||||
NSError *error;
|
||||
[self didStartLoad];
|
||||
BOOL success = [self performFetch:&error];
|
||||
if (! success) {
|
||||
[self didFailLoadWithError:error];
|
||||
}
|
||||
[self updateSortedArray];
|
||||
|
||||
[self.tableView reloadData];
|
||||
[self didFinishLoad];
|
||||
|
||||
@@ -470,7 +486,7 @@
|
||||
return self.emptyItem;
|
||||
|
||||
} else if ([self isHeaderIndexPath:indexPath]) {
|
||||
NSUInteger row = (self.empty && self.emptyItem) ? (indexPath.row - 1) : indexPath.row;
|
||||
NSUInteger row = ([self isEmpty] && self.emptyItem) ? (indexPath.row - 1) : indexPath.row;
|
||||
return [self.headerItems objectAtIndex:row];
|
||||
|
||||
} else if ([self isFooterIndexPath:indexPath]) {
|
||||
@@ -499,7 +515,7 @@
|
||||
|
||||
#pragma mark - KVO & Model States
|
||||
|
||||
- (BOOL)isEmpty {
|
||||
- (BOOL)isConsideredEmpty {
|
||||
NSUInteger fetchedObjectsCount = [[_fetchedResultsController fetchedObjects] count];
|
||||
BOOL isEmpty = (fetchedObjectsCount == 0);
|
||||
RKLogTrace(@"Determined isEmpty = %@. fetchedObjects count = %d", isEmpty ? @"YES" : @"NO", fetchedObjectsCount);
|
||||
@@ -511,7 +527,7 @@
|
||||
- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller {
|
||||
RKLogTrace(@"Beginning updates for fetchedResultsController (%@). Current section count = %d (resource path: %@)", controller, [[controller sections] count], _resourcePath);
|
||||
|
||||
if(_sortSelector) return;
|
||||
if (_sortSelector) return;
|
||||
|
||||
[self.tableView beginUpdates];
|
||||
_isEmptyBeforeAnimation = [self isEmpty];
|
||||
@@ -522,17 +538,25 @@
|
||||
atIndex:(NSUInteger)sectionIndex
|
||||
forChangeType:(NSFetchedResultsChangeType)type {
|
||||
|
||||
if(_sortSelector) return;
|
||||
if (_sortSelector) return;
|
||||
|
||||
switch (type) {
|
||||
case NSFetchedResultsChangeInsert:
|
||||
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
|
||||
withRowAnimation:UITableViewRowAnimationFade];
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(tableController:didInsertSectionAtIndex:)]) {
|
||||
[self.delegate tableController:self didInsertSectionAtIndex:sectionIndex];
|
||||
}
|
||||
break;
|
||||
|
||||
case NSFetchedResultsChangeDelete:
|
||||
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
|
||||
withRowAnimation:UITableViewRowAnimationFade];
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(tableController:didDeleteSectionAtIndex:)]) {
|
||||
[self.delegate tableController:self didDeleteSectionAtIndex:sectionIndex];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -547,7 +571,7 @@
|
||||
forChangeType:(NSFetchedResultsChangeType)type
|
||||
newIndexPath:(NSIndexPath *)newIndexPath {
|
||||
|
||||
if(_sortSelector) return;
|
||||
if (_sortSelector) return;
|
||||
|
||||
NSIndexPath* adjIndexPath = [self indexPathForFetchedResultsIndexPath:indexPath];
|
||||
NSIndexPath* adjNewIndexPath = [self indexPathForFetchedResultsIndexPath:newIndexPath];
|
||||
@@ -594,13 +618,27 @@
|
||||
|
||||
[self updateSortedArray];
|
||||
|
||||
if(_sortSelector) {
|
||||
if (_sortSelector) {
|
||||
[self.tableView reloadData];
|
||||
} else {
|
||||
[self.tableView endUpdates];
|
||||
}
|
||||
|
||||
|
||||
[self didFinishLoad];
|
||||
}
|
||||
|
||||
#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];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -29,19 +29,26 @@
|
||||
#import "RKObjectMapping.h"
|
||||
#import "RKObjectLoader.h"
|
||||
|
||||
@protocol RKTableControllerDelegate <RKAbstractTableControllerDelegate>
|
||||
|
||||
@optional
|
||||
|
||||
- (void)tableController:(RKTableController *)tableController didLoadObjects:(NSArray *)objects inSection:(RKTableSection *)section;
|
||||
|
||||
@end
|
||||
|
||||
@interface RKTableController : RKAbstractTableController
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
@property (nonatomic, assign) id<RKTableControllerDelegate> delegate;
|
||||
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @name Static Tables
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
- (void)loadObjects:(NSArray *)objects;
|
||||
- (void)loadObjects:(NSArray *)objects inSection:(NSUInteger)sectionIndex;
|
||||
- (void)loadEmpty;
|
||||
|
||||
// Move to superclass???
|
||||
- (void)reloadRowForObject:(id)object withRowAnimation:(UITableViewRowAnimation)rowAnimation;
|
||||
|
||||
/**
|
||||
Load an array of RKTableItems into table cells of the specified class. A table cell
|
||||
mapping will be constructed on your behalf and yielded to the block for configuration.
|
||||
@@ -78,12 +85,16 @@
|
||||
*/
|
||||
- (void)loadTableItems:(NSArray *)tableItems inSection:(NSUInteger)sectionIndex;
|
||||
|
||||
///-----------------------------------------------------------------------------
|
||||
/** @name Network Tables */
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
- (void)loadTableFromResourcePath:(NSString *)resourcePath;
|
||||
- (void)loadTableFromResourcePath:(NSString *)resourcePath usingBlock:(void (^)(RKObjectLoader *objectLoader))block;
|
||||
|
||||
///-----------------------------------------------------------------------------
|
||||
/** @name Forms */
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
The form that the table has been loaded with (if any)
|
||||
@@ -98,15 +109,37 @@
|
||||
*/
|
||||
- (void)loadForm:(RKForm *)form;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
/// @name Managing Sections
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
///-----------------------------------------------------------------------------
|
||||
|
||||
@property (nonatomic, readonly) NSMutableArray *sections;
|
||||
|
||||
/**
|
||||
The key path on the loaded objects used to determine the section they belong to.
|
||||
*/
|
||||
@property(nonatomic, copy) NSString *sectionNameKeyPath;
|
||||
|
||||
/**
|
||||
Returns the section at the specified index.
|
||||
@param index Must be less than the total number of sections.
|
||||
*/
|
||||
- (RKTableSection *)sectionAtIndex:(NSUInteger)index;
|
||||
|
||||
/**
|
||||
Returns the first section with the specified header title.
|
||||
@param title The header title.
|
||||
*/
|
||||
- (RKTableSection *)sectionWithHeaderTitle:(NSString *)title;
|
||||
|
||||
/**
|
||||
Returns the index of the specified section.
|
||||
|
||||
@param section Must be a valid non nil RKTableViewSection.
|
||||
@return The index of the given section if contained within the receiver, otherwise NSNotFound.
|
||||
*/
|
||||
- (NSUInteger)indexForSection:(RKTableSection *)section;
|
||||
|
||||
// Coalesces a series of table view updates performed within the block into
|
||||
// a single animation using beginUpdates: and endUpdates: on the table view
|
||||
// TODO: Move to super-class?
|
||||
|
||||
@@ -23,27 +23,35 @@
|
||||
#import "RKLog.h"
|
||||
#import "RKFormSection.h"
|
||||
#import "NSArray+RKAdditions.h"
|
||||
#import "RKObjectMappingOperation.h"
|
||||
|
||||
// Define logging component
|
||||
#undef RKLogComponent
|
||||
#define RKLogComponent lcl_cRestKitUI
|
||||
|
||||
@interface RKTableController ()
|
||||
@property (nonatomic, readwrite) NSMutableArray *sections;
|
||||
@end
|
||||
|
||||
@implementation RKTableController
|
||||
|
||||
@dynamic delegate;
|
||||
@synthesize form = _form;
|
||||
@synthesize sectionNameKeyPath = _sectionNameKeyPath;
|
||||
@synthesize sections = _sections;
|
||||
|
||||
#pragma mark - Instantiation
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_sections = [NSMutableArray new];
|
||||
[self addObserver:self
|
||||
forKeyPath:@"sections"
|
||||
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
|
||||
context:nil];
|
||||
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTableSection *section = [RKTableSection section];
|
||||
[self addSection:section];
|
||||
}
|
||||
|
||||
@@ -54,7 +62,8 @@
|
||||
[self removeObserver:self forKeyPath:@"sections"];
|
||||
[_form release];
|
||||
[_sectionNameKeyPath release];
|
||||
|
||||
[_sections release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -77,7 +86,7 @@
|
||||
[self.sections removeObjectsAtIndexes:indexes];
|
||||
}
|
||||
|
||||
- (void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects {
|
||||
- (void)replaceSectionsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects {
|
||||
[self.sections replaceObjectsAtIndexes:indexes withObjects:objects];
|
||||
}
|
||||
|
||||
@@ -89,11 +98,6 @@
|
||||
}
|
||||
|
||||
[[self sectionsProxy] addObject:section];
|
||||
|
||||
// TODO: move into KVO?
|
||||
if ([self.delegate respondsToSelector:@selector(tableController:didInsertSection:atIndex:)]) {
|
||||
[self.delegate tableController:self didInsertSection:section atIndex:[self.sections indexOfObject:section]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeSection:(RKTableSection *)section {
|
||||
@@ -103,10 +107,6 @@
|
||||
reason:@"Tables must always have at least one section"
|
||||
userInfo:nil];
|
||||
}
|
||||
NSUInteger index = [self.sections indexOfObject:section];
|
||||
if ([self.delegate respondsToSelector:@selector(tableController:didRemoveSection:atIndex:)]) {
|
||||
[self.delegate tableController:self didRemoveSection:section atIndex:index];
|
||||
}
|
||||
[[self sectionsProxy] removeObject:section];
|
||||
}
|
||||
|
||||
@@ -114,10 +114,6 @@
|
||||
NSAssert(section, @"Cannot insert a nil section");
|
||||
section.tableController = self;
|
||||
[[self sectionsProxy] insertObject:section atIndex:index];
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(tableController:didInsertSection:atIndex:)]) {
|
||||
[self.delegate tableController:self didInsertSection:section atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeSectionAtIndex:(NSUInteger)index {
|
||||
@@ -126,21 +122,10 @@
|
||||
reason:@"Tables must always have at least one section"
|
||||
userInfo:nil];
|
||||
}
|
||||
RKTableSection* section = [self.sections objectAtIndex:index];
|
||||
if ([self.delegate respondsToSelector:@selector(tableController:didRemoveSection:atIndex:)]) {
|
||||
[self.delegate tableController:self didRemoveSection:section atIndex:index];
|
||||
}
|
||||
[[self sectionsProxy] removeObjectAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)removeAllSections:(BOOL)recreateFirstSection {
|
||||
NSUInteger sectionCount = [self.sections count];
|
||||
for (NSUInteger index = 0; index < sectionCount; index++) {
|
||||
RKTableSection* section = [self.sections objectAtIndex:index];
|
||||
if ([self.delegate respondsToSelector:@selector(tableController:didRemoveSection:atIndex:)]) {
|
||||
[self.delegate tableController:self didRemoveSection:section atIndex:index];
|
||||
}
|
||||
}
|
||||
[[self sectionsProxy] removeAllObjects];
|
||||
|
||||
if (recreateFirstSection) {
|
||||
@@ -194,7 +179,11 @@
|
||||
}
|
||||
|
||||
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:self.defaultRowAnimation];
|
||||
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(tableController:didLoadObjects:inSection:)]) {
|
||||
[self.delegate tableController:self didLoadObjects:objects inSection:section];
|
||||
}
|
||||
|
||||
// The load is finalized via network callbacks for
|
||||
// dynamic table controllers
|
||||
if (nil == self.objectLoader) {
|
||||
@@ -325,6 +314,9 @@
|
||||
|
||||
if (self.sectionNameKeyPath) {
|
||||
NSArray *sectionedObjects = [objects sectionsGroupedByKeyPath:self.sectionNameKeyPath];
|
||||
if ([sectionedObjects count] == 0) {
|
||||
[self removeAllSections];
|
||||
}
|
||||
for (NSArray *sectionOfObjects in sectionedObjects) {
|
||||
NSUInteger sectionIndex = [sectionedObjects indexOfObject:sectionOfObjects];
|
||||
if (sectionIndex >= [self sectionCount]) {
|
||||
@@ -337,13 +329,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reloadRowForObject:(id)object withRowAnimation:(UITableViewRowAnimation)rowAnimation {
|
||||
NSIndexPath *indexPath = [self indexPathForObject:object];
|
||||
if (indexPath) {
|
||||
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:rowAnimation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
if ([keyPath isEqualToString:@"sections"]) {
|
||||
@@ -376,4 +361,153 @@
|
||||
// TODO: KVO should be used for managing the row level manipulations on the table view as well...
|
||||
}
|
||||
|
||||
#pragma mark - Managing Sections
|
||||
|
||||
- (NSUInteger)sectionCount {
|
||||
return [_sections count];
|
||||
}
|
||||
|
||||
- (NSUInteger)rowCount {
|
||||
return [[_sections valueForKeyPath:@"@sum.rowCount"] intValue];
|
||||
}
|
||||
|
||||
- (RKTableSection *)sectionAtIndex:(NSUInteger)index {
|
||||
return [_sections objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (NSUInteger)indexForSection:(RKTableSection *)section {
|
||||
NSAssert(section, @"Cannot return index for a nil section");
|
||||
return [_sections indexOfObject:section];
|
||||
}
|
||||
|
||||
- (RKTableSection *)sectionWithHeaderTitle:(NSString *)title {
|
||||
for (RKTableSection* section in _sections) {
|
||||
if ([section.headerTitle isEqualToString:title]) {
|
||||
return section;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSUInteger)numberOfRowsInSection:(NSUInteger)index {
|
||||
return [self sectionAtIndex:index].rowCount;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)cellForObjectAtIndexPath:(NSIndexPath *)indexPath {
|
||||
RKTableSection* section = [self sectionAtIndex:indexPath.section];
|
||||
id mappableObject = [section objectAtIndex:indexPath.row];
|
||||
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];
|
||||
NSAssert(cell, @"Cell mapping failed to dequeue or allocate a tableViewCell for object: %@", mappableObject);
|
||||
|
||||
// Map the object state into the cell
|
||||
RKObjectMappingOperation* mappingOperation = [[RKObjectMappingOperation 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 to generate table cell for object: %@", error);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Cell Mappings
|
||||
|
||||
- (id)objectForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSAssert(indexPath, @"Cannot lookup object with a nil indexPath");
|
||||
RKTableSection* section = [self sectionAtIndex:indexPath.section];
|
||||
return [section objectAtIndex:indexPath.row];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource methods
|
||||
|
||||
- (NSString*)tableView:(UITableView*)theTableView titleForHeaderInSection:(NSInteger)section {
|
||||
NSAssert(theTableView == self.tableView, @"tableView:titleForHeaderInSection: invoked with inappropriate tableView: %@", theTableView);
|
||||
return [[_sections objectAtIndex:section] headerTitle];
|
||||
}
|
||||
|
||||
- (NSString*)tableView:(UITableView*)theTableView titleForFooterInSection:(NSInteger)section {
|
||||
NSAssert(theTableView == self.tableView, @"tableView:titleForFooterInSection: invoked with inappropriate tableView: %@", theTableView);
|
||||
return [[_sections objectAtIndex:section] footerTitle];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView*)theTableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSAssert(theTableView == self.tableView, @"tableView:canEditRowAtIndexPath: invoked with inappropriate tableView: %@", theTableView);
|
||||
return self.canEditRows;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView*)theTableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSAssert(theTableView == self.tableView, @"tableView:canMoveRowAtIndexPath: invoked with inappropriate tableView: %@", theTableView);
|
||||
return self.canMoveRows;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView*)theTableView {
|
||||
NSAssert(theTableView == self.tableView, @"numberOfSectionsInTableView: invoked with inappropriate tableView: %@", theTableView);
|
||||
RKLogTrace(@"%@ numberOfSectionsInTableView = %d", self, self.sectionCount);
|
||||
return self.sectionCount;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView*)theTableView numberOfRowsInSection:(NSInteger)section {
|
||||
NSAssert(theTableView == self.tableView, @"tableView:numberOfRowsInSection: invoked with inappropriate tableView: %@", theTableView);
|
||||
RKLogTrace(@"%@ numberOfRowsInSection:%d = %d", self, section, self.sectionCount);
|
||||
return [[_sections objectAtIndex:section] rowCount];
|
||||
}
|
||||
|
||||
- (NSIndexPath *)indexPathForObject:(id)object {
|
||||
NSUInteger sectionIndex = 0;
|
||||
for (RKTableSection *section in self.sections) {
|
||||
NSUInteger rowIndex = 0;
|
||||
for (id rowObject in section.objects) {
|
||||
if ([rowObject isEqual:object]) {
|
||||
return [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
|
||||
}
|
||||
|
||||
rowIndex++;
|
||||
}
|
||||
sectionIndex++;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)theTableView heightForHeaderInSection:(NSInteger)sectionIndex {
|
||||
NSAssert(theTableView == self.tableView, @"heightForHeaderInSection: invoked with inappropriate tableView: %@", theTableView);
|
||||
RKTableSection *section = [self sectionAtIndex:sectionIndex];
|
||||
return section.headerHeight;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)theTableView heightForFooterInSection:(NSInteger)sectionIndex {
|
||||
NSAssert(theTableView == self.tableView, @"heightForFooterInSection: invoked with inappropriate tableView: %@", theTableView);
|
||||
RKTableSection *section = [self sectionAtIndex:sectionIndex];
|
||||
return section.footerHeight;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)theTableView viewForHeaderInSection:(NSInteger)sectionIndex {
|
||||
NSAssert(theTableView == self.tableView, @"viewForHeaderInSection: invoked with inappropriate tableView: %@", theTableView);
|
||||
RKTableSection *section = [self sectionAtIndex:sectionIndex];
|
||||
return section.headerView;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)theTableView viewForFooterInSection:(NSInteger)sectionIndex {
|
||||
NSAssert(theTableView == self.tableView, @"viewForFooterInSection: invoked with inappropriate tableView: %@", theTableView);
|
||||
RKTableSection *section = [self sectionAtIndex:sectionIndex];
|
||||
return section.footerView;
|
||||
}
|
||||
|
||||
- (BOOL)isConsideredEmpty {
|
||||
NSUInteger nonRowItemsCount = [self.headerItems count] + [self.footerItems count];
|
||||
nonRowItemsCount += self.emptyItem ? 1 : 0;
|
||||
BOOL isEmpty = (self.rowCount - nonRowItemsCount) == 0;
|
||||
RKLogTrace(@"Determined isConsideredEmpty = %@. self.rowCount = %d with %d nonRowItems in the table", isEmpty ? @"YES" : @"NO", self.rowCount, nonRowItemsCount);
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -675,6 +675,10 @@
|
||||
25DB7509151BD551009F01AF /* NSManagedObject+ActiveRecordTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DB7507151BD551009F01AF /* NSManagedObject+ActiveRecordTest.m */; };
|
||||
25E36E0215195CED00F9E448 /* RKFetchRequestMappingCacheTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E36E0115195CED00F9E448 /* RKFetchRequestMappingCacheTest.m */; };
|
||||
25E36E0315195CED00F9E448 /* RKFetchRequestMappingCacheTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E36E0115195CED00F9E448 /* RKFetchRequestMappingCacheTest.m */; };
|
||||
25E4DAB4156DA97F00A5C84B /* RKTableControllerTestDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E4DAB2156DA97F00A5C84B /* RKTableControllerTestDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
25E4DAB5156DA97F00A5C84B /* RKTableControllerTestDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 25E4DAB2156DA97F00A5C84B /* RKTableControllerTestDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
25E4DAB6156DA97F00A5C84B /* RKTableControllerTestDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E4DAB3156DA97F00A5C84B /* RKTableControllerTestDelegate.m */; };
|
||||
25E4DAB7156DA97F00A5C84B /* RKTableControllerTestDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 25E4DAB3156DA97F00A5C84B /* RKTableControllerTestDelegate.m */; };
|
||||
25EC1A2C14F6FDAD00C3CF3F /* RKObjectManager+RKTableController.h in Headers */ = {isa = PBXBuildFile; fileRef = 25EC1A2A14F6FDAC00C3CF3F /* RKObjectManager+RKTableController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
25EC1A2D14F6FDAD00C3CF3F /* RKObjectManager+RKTableController.h in Headers */ = {isa = PBXBuildFile; fileRef = 25EC1A2A14F6FDAC00C3CF3F /* RKObjectManager+RKTableController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
25EC1A2E14F6FDAD00C3CF3F /* RKObjectManager+RKTableController.m in Sources */ = {isa = PBXBuildFile; fileRef = 25EC1A2B14F6FDAC00C3CF3F /* RKObjectManager+RKTableController.m */; };
|
||||
@@ -1173,6 +1177,8 @@
|
||||
25CAAA9315254E7800CAE5D7 /* ArrayOfHumans.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ArrayOfHumans.json; sourceTree = "<group>"; };
|
||||
25DB7507151BD551009F01AF /* NSManagedObject+ActiveRecordTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObject+ActiveRecordTest.m"; sourceTree = "<group>"; };
|
||||
25E36E0115195CED00F9E448 /* RKFetchRequestMappingCacheTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKFetchRequestMappingCacheTest.m; sourceTree = "<group>"; };
|
||||
25E4DAB2156DA97F00A5C84B /* RKTableControllerTestDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RKTableControllerTestDelegate.h; path = Testing/RKTableControllerTestDelegate.h; sourceTree = "<group>"; };
|
||||
25E4DAB3156DA97F00A5C84B /* RKTableControllerTestDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RKTableControllerTestDelegate.m; path = Testing/RKTableControllerTestDelegate.m; sourceTree = "<group>"; };
|
||||
25EC1A2A14F6FDAC00C3CF3F /* RKObjectManager+RKTableController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RKObjectManager+RKTableController.h"; sourceTree = "<group>"; };
|
||||
25EC1A2B14F6FDAC00C3CF3F /* RKObjectManager+RKTableController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RKObjectManager+RKTableController.m"; sourceTree = "<group>"; };
|
||||
25EC1AB814F8019F00C3CF3F /* RKRefreshGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKRefreshGestureRecognizer.h; sourceTree = "<group>"; };
|
||||
@@ -1974,6 +1980,8 @@
|
||||
25055B8E14EEF40000B9C4DD /* RKMappingTestExpectation.m */,
|
||||
252EFB2414D9B6F2004863C8 /* Testing.h */,
|
||||
25C954A415542A47005C9E08 /* RKTestConstants.m */,
|
||||
25E4DAB2156DA97F00A5C84B /* RKTableControllerTestDelegate.h */,
|
||||
25E4DAB3156DA97F00A5C84B /* RKTableControllerTestDelegate.m */,
|
||||
);
|
||||
name = Testing;
|
||||
sourceTree = "<group>";
|
||||
@@ -2264,6 +2272,7 @@
|
||||
259D98541550C69A008C90F5 /* RKEntityByAttributeCache.h in Headers */,
|
||||
259D985E155218E5008C90F5 /* RKEntityCache.h in Headers */,
|
||||
25545959155F0527007D7625 /* RKBenchmark.h in Headers */,
|
||||
25E4DAB4156DA97F00A5C84B /* RKTableControllerTestDelegate.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2388,6 +2397,7 @@
|
||||
259D98551550C69A008C90F5 /* RKEntityByAttributeCache.h in Headers */,
|
||||
259D985F155218E5008C90F5 /* RKEntityCache.h in Headers */,
|
||||
2554595A155F0527007D7625 /* RKBenchmark.h in Headers */,
|
||||
25E4DAB5156DA97F00A5C84B /* RKTableControllerTestDelegate.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2796,6 +2806,7 @@
|
||||
259D98561550C69A008C90F5 /* RKEntityByAttributeCache.m in Sources */,
|
||||
259D9860155218E5008C90F5 /* RKEntityCache.m in Sources */,
|
||||
2554595B155F0527007D7625 /* RKBenchmark.m in Sources */,
|
||||
25E4DAB6156DA97F00A5C84B /* RKTableControllerTestDelegate.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2985,6 +2996,7 @@
|
||||
259D98571550C69A008C90F5 /* RKEntityByAttributeCache.m in Sources */,
|
||||
259D9861155218E5008C90F5 /* RKEntityCache.m in Sources */,
|
||||
2554595C155F0527007D7625 /* RKBenchmark.m in Sources */,
|
||||
25E4DAB7156DA97F00A5C84B /* RKTableControllerTestDelegate.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#import "RKEvent.h"
|
||||
#import "RKAbstractTableController_Internals.h"
|
||||
#import "RKManagedObjectCaching.h"
|
||||
#import "RKTableControllerTestDelegate.h"
|
||||
|
||||
// Expose the object loader delegate for testing purposes...
|
||||
@interface RKFetchedResultsTableController () <RKObjectLoaderDelegate>
|
||||
@@ -31,20 +32,21 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface RKFetchedResultsTableControllerSpecViewController : UIViewController
|
||||
@interface RKFetchedResultsTableControllerSpecViewController : UITableViewController
|
||||
@end
|
||||
|
||||
@implementation RKFetchedResultsTableControllerSpecViewController
|
||||
@end
|
||||
|
||||
@interface RKFetchedResultsTableControllerTest : RKTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation RKFetchedResultsTableControllerTest
|
||||
|
||||
- (void)setUp {
|
||||
[RKTestFactory setUp];
|
||||
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:nil];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
@@ -57,7 +59,7 @@
|
||||
[humanMapping mapKeyPath:@"id" toAttribute:@"railsID"];
|
||||
[humanMapping mapAttributes:@"name", nil];
|
||||
humanMapping.primaryKeyAttribute = @"railsID";
|
||||
|
||||
|
||||
[RKHuman truncateAll];
|
||||
assertThatInt([RKHuman count:nil], is(equalToInt(0)));
|
||||
RKHuman* blake = [RKHuman createEntity];
|
||||
@@ -70,11 +72,11 @@
|
||||
[store save:&error];
|
||||
assertThat(error, is(nilValue()));
|
||||
assertThatInt([RKHuman count:nil], is(equalToInt(2)));
|
||||
|
||||
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
[objectManager.mappingProvider setMapping:humanMapping forKeyPath:@"human"];
|
||||
objectManager.objectStore = store;
|
||||
|
||||
|
||||
[objectManager.mappingProvider setObjectMapping:humanMapping forResourcePathPattern:@"/JSON/humans/all\\.json" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
|
||||
return [RKHuman requestAllSortedBy:@"name" ascending:YES];
|
||||
}];
|
||||
@@ -88,7 +90,7 @@
|
||||
[eventMapping mapAttributes:@"location", @"summary", nil];
|
||||
eventMapping.primaryKeyAttribute = @"eventID";
|
||||
[RKEvent truncateAll];
|
||||
|
||||
|
||||
assertThatInt([RKEvent count:nil], is(equalToInt(0)));
|
||||
RKEvent *nakedEvent = [RKEvent createEntity];
|
||||
nakedEvent.eventID = @"RK4424";
|
||||
@@ -99,11 +101,11 @@
|
||||
[store save:&error];
|
||||
assertThat(error, is(nilValue()));
|
||||
assertThatInt([RKEvent count:nil], is(equalToInt(1)));
|
||||
|
||||
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
[objectManager.mappingProvider addObjectMapping:eventMapping];
|
||||
objectManager.objectStore = store;
|
||||
|
||||
|
||||
id mockMappingProvider = [OCMockObject partialMockForObject:objectManager.mappingProvider];
|
||||
[[[mockMappingProvider stub] andReturn:[RKEvent requestAllSortedBy:@"eventType" ascending:YES]] fetchRequestForResourcePath:@"/JSON/NakedEvents.json"];
|
||||
}
|
||||
@@ -114,14 +116,14 @@
|
||||
[humanMapping mapKeyPath:@"id" toAttribute:@"railsID"];
|
||||
[humanMapping mapAttributes:@"name", nil];
|
||||
humanMapping.primaryKeyAttribute = @"railsID";
|
||||
|
||||
|
||||
[RKHuman truncateAll];
|
||||
assertThatInt([RKHuman count:nil], is(equalToInt(0)));
|
||||
|
||||
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
[objectManager.mappingProvider setMapping:humanMapping forKeyPath:@"human"];
|
||||
objectManager.objectStore = store;
|
||||
|
||||
|
||||
id mockMappingProvider = [OCMockObject partialMockForObject:objectManager.mappingProvider];
|
||||
[[[mockMappingProvider stub] andReturn:[RKHuman requestAllSortedBy:@"name" ascending:YES]] fetchRequestForResourcePath:@"/JSON/humans/all.json"];
|
||||
[[[mockMappingProvider stub] andReturn:[RKHuman requestAllSortedBy:@"name" ascending:YES]] fetchRequestForResourcePath:@"/empty/array"];
|
||||
@@ -139,40 +141,34 @@
|
||||
|
||||
- (void)testLoadWithATableViewControllerAndResourcePath {
|
||||
[self bootstrapStoreAndCache];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
RKFetchedResultsTableController* tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThat(tableController.viewController, is(equalTo(viewController)));
|
||||
assertThat(tableController.tableView, is(equalTo(tableView)));
|
||||
assertThat(tableController.tableView, is(equalTo(viewController.tableView)));
|
||||
assertThat(tableController.resourcePath, is(equalTo(@"/JSON/humans/all.json")));
|
||||
}
|
||||
|
||||
- (void)testLoadWithATableViewControllerAndResourcePathFromNakedObjects {
|
||||
[self bootstrapNakedObjectStoreAndCache];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
RKFetchedResultsTableController* tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/NakedEvents.json";
|
||||
[tableController setObjectMappingForClass:[RKEvent class]];
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThat(tableController.viewController, is(equalTo(viewController)));
|
||||
assertThat(tableController.tableView, is(equalTo(tableView)));
|
||||
assertThat(tableController.tableView, is(equalTo(viewController.tableView)));
|
||||
assertThat(tableController.resourcePath, is(equalTo(@"/JSON/NakedEvents.json")));
|
||||
|
||||
|
||||
RKTableViewCellMapping* cellMapping = [RKTableViewCellMapping mappingForClass:[UITableViewCell class]];
|
||||
[cellMapping mapKeyPath:@"summary" toAttribute:@"textLabel.text"];
|
||||
RKTableViewCellMappings* mappings = [RKTableViewCellMappings new];
|
||||
[mappings setCellMapping:cellMapping forClass:[RKEvent class]];
|
||||
tableController.cellMappings = mappings;
|
||||
|
||||
|
||||
UITableViewCell* cell = [tableController tableView:tableController.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
assertThat(cell.textLabel.text, is(equalTo(@"Shindig")));
|
||||
}
|
||||
@@ -180,21 +176,17 @@
|
||||
|
||||
- (void)testLoadWithATableViewControllerAndResourcePathAndPredicateAndSortDescriptors {
|
||||
[self bootstrapStoreAndCache];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
NSPredicate* predicate = [NSPredicate predicateWithValue:TRUE];
|
||||
NSArray* sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name"
|
||||
ascending:YES]];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
RKFetchedResultsTableController* tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.predicate = predicate;
|
||||
tableController.sortDescriptors = sortDescriptors;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThat(tableController.viewController, is(equalTo(viewController)));
|
||||
assertThat(tableController.tableView, is(equalTo(tableView)));
|
||||
assertThat(tableController.resourcePath, is(equalTo(@"/JSON/humans/all.json")));
|
||||
assertThat(tableController.fetchRequest, is(notNilValue()));
|
||||
assertThat([tableController.fetchRequest predicate], is(equalTo(predicate)));
|
||||
@@ -203,18 +195,14 @@
|
||||
|
||||
- (void)testLoadWithATableViewControllerAndResourcePathAndSectionNameAndCacheName {
|
||||
[self bootstrapStoreAndCache];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
RKFetchedResultsTableController* tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
tableController.cacheName = @"allHumansCache";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThat(tableController.viewController, is(equalTo(viewController)));
|
||||
assertThat(tableController.tableView, is(equalTo(tableView)));
|
||||
assertThat(tableController.resourcePath, is(equalTo(@"/JSON/humans/all.json")));
|
||||
assertThat(tableController.fetchRequest, is(notNilValue()));
|
||||
assertThat(tableController.fetchedResultsController.sectionNameKeyPath, is(equalTo(@"name")));
|
||||
@@ -223,23 +211,19 @@
|
||||
|
||||
- (void)testLoadWithAllParams {
|
||||
[self bootstrapStoreAndCache];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
NSPredicate* predicate = [NSPredicate predicateWithValue:TRUE];
|
||||
NSArray* sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name"
|
||||
ascending:YES]];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
RKFetchedResultsTableController* tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.predicate = predicate;
|
||||
tableController.sortDescriptors = sortDescriptors;
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
tableController.cacheName = @"allHumansCache";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThat(tableController.viewController, is(equalTo(viewController)));
|
||||
assertThat(tableController.tableView, is(equalTo(tableView)));
|
||||
assertThat(tableController.resourcePath, is(equalTo(@"/JSON/humans/all.json")));
|
||||
assertThat(tableController.fetchRequest, is(notNilValue()));
|
||||
assertThat([tableController.fetchRequest predicate], is(equalTo(predicate)));
|
||||
@@ -254,10 +238,10 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(1)));
|
||||
}
|
||||
|
||||
@@ -269,7 +253,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
[tableController loadTable];
|
||||
@@ -282,7 +266,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
@@ -294,7 +278,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -312,7 +296,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController setEmptyItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Empty";
|
||||
@@ -330,7 +314,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController setEmptyItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Empty";
|
||||
@@ -348,7 +332,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -369,11 +353,8 @@
|
||||
|
||||
- (void)testProperlyCountRowsWithHeaderAndEmptyItemsWhenEmptyShowHeaders {
|
||||
[self bootstrapEmptyStoreAndCache];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
RKFetchedResultsTableController* tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -394,11 +375,8 @@
|
||||
|
||||
- (void)testProperlyCountRowsWithHeaderAndEmptyItemsWhenFull {
|
||||
[self bootstrapStoreAndCache];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
RKFetchedResultsTableController* tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -440,11 +418,11 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThatInt([tableController numberOfSectionsInTableView:tableView], is(equalToInt(2)));
|
||||
}
|
||||
|
||||
@@ -454,10 +432,10 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThatInt([tableController tableView:tableView numberOfRowsInSection:0], is(equalToInt(2)));
|
||||
}
|
||||
|
||||
@@ -467,11 +445,11 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThat([tableController tableView:tableView titleForHeaderInSection:1], is(equalTo(@"other")));
|
||||
}
|
||||
|
||||
@@ -481,16 +459,16 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
RKTableViewCellMapping* cellMapping = [RKTableViewCellMapping mappingForClass:[UITableViewCell class]];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
RKTableViewCellMappings* mappings = [RKTableViewCellMappings new];
|
||||
[mappings setCellMapping:cellMapping forClass:[RKHuman class]];
|
||||
tableController.cellMappings = mappings;
|
||||
|
||||
|
||||
UITableViewCell* cell = [tableController tableView:tableController.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
assertThat(cell.textLabel.text, is(equalTo(@"blake")));
|
||||
}
|
||||
@@ -503,13 +481,14 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
assertThatBool(blake == [tableController objectForRowAtIndexPath:indexPath], is(equalToBool(YES)));
|
||||
[tableController release];
|
||||
}
|
||||
|
||||
#pragma mark - Editing
|
||||
@@ -520,35 +499,33 @@
|
||||
[[RKObjectManager sharedManager].router routeClass:[RKHuman class]
|
||||
toResourcePath:@"/humans/:railsID"
|
||||
forMethod:RKRequestMethodDELETE];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
RKFetchedResultsTableController* tableController = [RKFetchedResultsTableController tableControllerForTableViewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.canEditRows = YES;
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
|
||||
NSIndexPath* deleteIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
RKHuman* other = [RKHuman findFirstByAttribute:@"name" withValue:@"other"];
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
assertThat([tableController objectForRowAtIndexPath:indexPath], is(equalTo(other)));
|
||||
assertThat([tableController objectForRowAtIndexPath:deleteIndexPath], is(equalTo(blake)));
|
||||
BOOL delegateCanEdit = [tableController tableView:tableController.tableView
|
||||
canEditRowAtIndexPath:deleteIndexPath];
|
||||
canEditRowAtIndexPath:deleteIndexPath];
|
||||
assertThatBool(delegateCanEdit, is(equalToBool(YES)));
|
||||
|
||||
// RKTestNotificationObserver* observer = [RKTestNotificationObserver notificationObserverForNotificationName:RKRequestDidLoadResponseNotification];
|
||||
|
||||
[RKTestNotificationObserver waitForNotificationWithName:RKRequestDidLoadResponseNotification usingBlock:^{
|
||||
[tableController tableView:tableController.tableView
|
||||
commitEditingStyle:UITableViewCellEditingStyleDelete
|
||||
forRowAtIndexPath:deleteIndexPath];
|
||||
commitEditingStyle:UITableViewCellEditingStyleDelete
|
||||
forRowAtIndexPath:deleteIndexPath];
|
||||
}];
|
||||
// observer.timeout = 30;
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(1)));
|
||||
assertThat([tableController objectForRowAtIndexPath:deleteIndexPath], is(equalTo(other)));
|
||||
assertThatBool([blake isDeleted], is(equalToBool(YES)));
|
||||
@@ -557,36 +534,36 @@
|
||||
- (void)testLocallyCommitADeleteWhenTheCanEditRowsPropertyIsSet {
|
||||
[self bootstrapStoreAndCache];
|
||||
[self stubObjectManagerToOnline];
|
||||
|
||||
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.canEditRows = YES;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
|
||||
NSIndexPath* deleteIndexPath = [NSIndexPath indexPathForRow:1 inSection:0];
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
RKHuman* other = [RKHuman findFirstByAttribute:@"name" withValue:@"other"];
|
||||
blake.railsID = nil;
|
||||
other.railsID = nil;
|
||||
|
||||
|
||||
NSError* error = nil;
|
||||
[blake.managedObjectContext save:&error];
|
||||
assertThat(error, is(nilValue()));
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
assertThat([tableController objectForRowAtIndexPath:indexPath], is(equalTo(blake)));
|
||||
assertThat([tableController objectForRowAtIndexPath:deleteIndexPath], is(equalTo(other)));
|
||||
BOOL delegateCanEdit = [tableController tableView:tableController.tableView
|
||||
canEditRowAtIndexPath:deleteIndexPath];
|
||||
canEditRowAtIndexPath:deleteIndexPath];
|
||||
assertThatBool(delegateCanEdit, is(equalToBool(YES)));
|
||||
[tableController tableView:tableController.tableView
|
||||
commitEditingStyle:UITableViewCellEditingStyleDelete
|
||||
forRowAtIndexPath:deleteIndexPath];
|
||||
commitEditingStyle:UITableViewCellEditingStyleDelete
|
||||
forRowAtIndexPath:deleteIndexPath];
|
||||
assertThatInt([tableController rowCount], is(equalToInt(1)));
|
||||
assertThat([tableController objectForRowAtIndexPath:indexPath], is(equalTo(blake)));
|
||||
}
|
||||
@@ -594,26 +571,26 @@
|
||||
- (void)testNotCommitADeletionWhenTheCanEditRowsPropertyIsNotSet {
|
||||
[self bootstrapStoreAndCache];
|
||||
[self stubObjectManagerToOnline];
|
||||
|
||||
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
RKHuman* other = [RKHuman findFirstByAttribute:@"name" withValue:@"other"];
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
BOOL delegateCanEdit = [tableController tableView:tableController.tableView
|
||||
canEditRowAtIndexPath:indexPath];
|
||||
canEditRowAtIndexPath:indexPath];
|
||||
assertThatBool(delegateCanEdit, is(equalToBool(NO)));
|
||||
[tableController tableView:tableController.tableView
|
||||
commitEditingStyle:UITableViewCellEditingStyleDelete
|
||||
forRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
|
||||
commitEditingStyle:UITableViewCellEditingStyleDelete
|
||||
forRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
assertThat([tableController objectForRowAtIndexPath:indexPath], is(equalTo(blake)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]],
|
||||
@@ -623,27 +600,27 @@
|
||||
- (void)testDoNothingToCommitAnInsertionWhenTheCanEditRowsPropertyIsSet {
|
||||
[self bootstrapStoreAndCache];
|
||||
[self stubObjectManagerToOnline];
|
||||
|
||||
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.canEditRows = YES;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
RKHuman* other = [RKHuman findFirstByAttribute:@"name" withValue:@"other"];
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
BOOL delegateCanEdit = [tableController tableView:tableController.tableView
|
||||
canEditRowAtIndexPath:indexPath];
|
||||
canEditRowAtIndexPath:indexPath];
|
||||
assertThatBool(delegateCanEdit, is(equalToBool(YES)));
|
||||
[tableController tableView:tableController.tableView
|
||||
commitEditingStyle:UITableViewCellEditingStyleInsert
|
||||
forRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
|
||||
commitEditingStyle:UITableViewCellEditingStyleInsert
|
||||
forRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
assertThat([tableController objectForRowAtIndexPath:indexPath], is(equalTo(blake)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]],
|
||||
@@ -656,22 +633,22 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.canMoveRows = YES;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
RKHuman* other = [RKHuman findFirstByAttribute:@"name" withValue:@"other"];
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
BOOL delegateCanMove = [tableController tableView:tableController.tableView
|
||||
canMoveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
canMoveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
assertThatBool(delegateCanMove, is(equalToBool(YES)));
|
||||
[tableController tableView:tableController.tableView
|
||||
moveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
|
||||
toIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
|
||||
moveRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
|
||||
toIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
assertThat([tableController objectForRowAtIndexPath:indexPath], is(equalTo(blake)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]],
|
||||
@@ -686,7 +663,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
assertThatBool([tableController isHeaderSection:0], is(equalToBool(YES)));
|
||||
@@ -700,7 +677,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -720,7 +697,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addFooterRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Footer";
|
||||
@@ -740,7 +717,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
[tableController addFooterRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
@@ -761,7 +738,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addFooterRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Footer";
|
||||
@@ -781,7 +758,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
assertThatBool([tableController isEmptySection:0], is(equalToBool(YES)));
|
||||
@@ -795,7 +772,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController loadTable];
|
||||
assertThatBool([tableController isEmptyRow:0], is(equalToBool(YES)));
|
||||
@@ -809,7 +786,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -832,7 +809,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addFooterRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Footer";
|
||||
@@ -855,7 +832,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController setEmptyItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Empty";
|
||||
@@ -878,7 +855,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -899,7 +876,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addFooterRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Footer";
|
||||
@@ -919,7 +896,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
[tableController addFooterRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
@@ -941,7 +918,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController setEmptyItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Empty";
|
||||
@@ -962,7 +939,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -989,7 +966,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
@@ -1018,7 +995,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -1052,7 +1029,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
@@ -1086,7 +1063,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -1112,7 +1089,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
RKTableItem* headerRow = [RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -1124,10 +1101,10 @@
|
||||
tableController.showsHeaderRowsWhenEmpty = NO;
|
||||
tableController.showsFooterRowsWhenEmpty = NO;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
RKHuman* other = [RKHuman findFirstByAttribute:@"name" withValue:@"other"];
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(3)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]], is(equalTo(headerRow)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]], is(equalTo(blake)));
|
||||
@@ -1141,7 +1118,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
RKTableItem* footerRow = [RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Footer";
|
||||
@@ -1153,10 +1130,10 @@
|
||||
tableController.showsHeaderRowsWhenEmpty = NO;
|
||||
tableController.showsFooterRowsWhenEmpty = NO;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
RKHuman* other = [RKHuman findFirstByAttribute:@"name" withValue:@"other"];
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(3)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]], is(equalTo(blake)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]], is(equalTo(other)));
|
||||
@@ -1170,7 +1147,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -1181,7 +1158,7 @@
|
||||
tableController.showsHeaderRowsWhenEmpty = NO;
|
||||
tableController.showsFooterRowsWhenEmpty = NO;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThatBool(tableController.isLoaded, is(equalToBool(YES)));
|
||||
assertThatInt([tableController rowCount], is(equalToInt(0)));
|
||||
assertThatBool(tableController.isEmpty, is(equalToBool(YES)));
|
||||
@@ -1193,7 +1170,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addFooterRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Footer";
|
||||
@@ -1204,7 +1181,7 @@
|
||||
tableController.showsHeaderRowsWhenEmpty = NO;
|
||||
tableController.showsFooterRowsWhenEmpty = NO;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThatBool(tableController.isLoaded, is(equalToBool(YES)));
|
||||
assertThatInt([tableController rowCount], is(equalToInt(0)));
|
||||
assertThatBool(tableController.isEmpty, is(equalToBool(YES)));
|
||||
@@ -1216,7 +1193,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -1239,7 +1216,7 @@
|
||||
tableController.showsHeaderRowsWhenEmpty = NO;
|
||||
tableController.showsFooterRowsWhenEmpty = NO;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThatBool(tableController.isLoaded, is(equalToBool(YES)));
|
||||
assertThatInt([tableController rowCount], is(equalToInt(1)));
|
||||
assertThatBool(tableController.isEmpty, is(equalToBool(YES)));
|
||||
@@ -1251,9 +1228,9 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
|
||||
|
||||
RKTableItem* headerRow = [RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
tableItem.cellMapping = [RKTableViewCellMapping cellMappingUsingBlock:^(RKTableViewCellMapping* cellMapping) {
|
||||
@@ -1261,7 +1238,7 @@
|
||||
}];
|
||||
}];
|
||||
[tableController addHeaderRowForItem:headerRow];
|
||||
|
||||
|
||||
RKTableItem* footerRow = [RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Footer";
|
||||
tableItem.cellMapping = [RKTableViewCellMapping cellMappingUsingBlock:^(RKTableViewCellMapping* cellMapping) {
|
||||
@@ -1269,7 +1246,7 @@
|
||||
}];
|
||||
}];
|
||||
[tableController addFooterRowForItem:footerRow];
|
||||
|
||||
|
||||
RKTableItem* emptyItem = [RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Empty";
|
||||
tableItem.cellMapping = [RKTableViewCellMapping cellMappingUsingBlock:^(RKTableViewCellMapping* cellMapping) {
|
||||
@@ -1280,10 +1257,10 @@
|
||||
tableController.showsHeaderRowsWhenEmpty = NO;
|
||||
tableController.showsFooterRowsWhenEmpty = NO;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
RKHuman* blake = [RKHuman findFirstByAttribute:@"name" withValue:@"blake"];
|
||||
RKHuman* other = [RKHuman findFirstByAttribute:@"name" withValue:@"other"];
|
||||
|
||||
|
||||
assertThatInt([tableController rowCount], is(equalToInt(4)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]], is(equalTo(headerRow)));
|
||||
assertThat([tableController objectForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]], is(equalTo(blake)));
|
||||
@@ -1298,7 +1275,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -1321,7 +1298,7 @@
|
||||
tableController.showsHeaderRowsWhenEmpty = NO;
|
||||
tableController.showsFooterRowsWhenEmpty = NO;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThatBool(tableController.isLoaded, is(equalToBool(YES)));
|
||||
assertThatInt([tableController rowCount], is(equalToInt(1)));
|
||||
assertThatBool(tableController.isEmpty, is(equalToBool(YES)));
|
||||
@@ -1333,7 +1310,7 @@
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
[tableController addHeaderRowForItem:[RKTableItem tableItemUsingBlock:^(RKTableItem* tableItem) {
|
||||
tableItem.text = @"Header";
|
||||
@@ -1356,7 +1333,7 @@
|
||||
tableController.showsHeaderRowsWhenEmpty = YES;
|
||||
tableController.showsFooterRowsWhenEmpty = YES;
|
||||
[tableController loadTable];
|
||||
|
||||
|
||||
assertThatBool(tableController.isLoaded, is(equalToBool(YES)));
|
||||
assertThatInt([tableController rowCount], is(equalToInt(3)));
|
||||
assertThatBool(tableController.isEmpty, is(equalToBool(YES)));
|
||||
@@ -1365,20 +1342,20 @@
|
||||
- (void)testShowTheEmptyImageAfterLoadingAnEmptyCollectionIntoAnEmptyFetch {
|
||||
[self bootstrapEmptyStoreAndCache];
|
||||
[self stubObjectManagerToOnline];
|
||||
|
||||
|
||||
UITableView* tableView = [UITableView new];
|
||||
|
||||
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController = [[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
|
||||
viewController:viewController];
|
||||
|
||||
UIImage *image = [RKTestFixture imageWithContentsOfFixture:@"blake.png"];
|
||||
|
||||
|
||||
tableController.imageForEmpty = image;
|
||||
tableController.resourcePath = @"/empty/array";
|
||||
tableController.autoRefreshFromNetwork = YES;
|
||||
[tableController.cache invalidateAll];
|
||||
|
||||
|
||||
[RKTestNotificationObserver waitForNotificationWithName:RKTableControllerDidFinishLoadNotification usingBlock:^{
|
||||
[tableController loadTable];
|
||||
}];
|
||||
@@ -1388,4 +1365,103 @@
|
||||
assertThat(tableController.stateOverlayImageView.image, is(notNilValue()));
|
||||
}
|
||||
|
||||
- (void)testPostANotificationWhenObjectsAreLoaded {
|
||||
[self bootstrapNakedObjectStoreAndCache];
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:tableView
|
||||
viewController:viewController];
|
||||
tableController.resourcePath = @"/JSON/NakedEvents.json";
|
||||
[tableController setObjectMappingForClass:[RKEvent class]];
|
||||
|
||||
id observerMock = [OCMockObject observerMock];
|
||||
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:RKTableControllerDidLoadObjectsNotification object:tableController];
|
||||
[[observerMock expect] notificationWithName:RKTableControllerDidLoadObjectsNotification object:tableController];
|
||||
[tableController loadTable];
|
||||
[observerMock verify];
|
||||
}
|
||||
|
||||
#pragma mark - Delegate Methods
|
||||
|
||||
- (void)testDelegateIsInformedOnInsertSection {
|
||||
[self bootstrapStoreAndCache];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:viewController.tableView viewController:viewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.cacheName = @"allHumansCache";
|
||||
|
||||
RKFetchedResultsTableControllerTestDelegate *delegate = [RKFetchedResultsTableControllerTestDelegate tableControllerDelegate];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[mockDelegate expect] tableController:tableController didInsertSectionAtIndex:0];
|
||||
tableController.delegate = mockDelegate;
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:viewController];
|
||||
[tableController loadTable];
|
||||
assertThatInt([tableController rowCount], is(equalToInt(2)));
|
||||
assertThatInt([tableController sectionCount], is(equalToInt(1)));
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
- (void)testDelegateIsInformedOfDidStartLoad {
|
||||
[self bootstrapStoreAndCache];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:viewController.tableView viewController:viewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.cacheName = @"allHumansCache";
|
||||
|
||||
id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKFetchedResultsTableControllerDelegate)];
|
||||
[[mockDelegate expect] tableControllerDidStartLoad:tableController];
|
||||
tableController.delegate = mockDelegate;
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:viewController];
|
||||
[tableController loadTable];
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
- (void)testDelegateIsInformedOfDidFinishLoad {
|
||||
[self bootstrapStoreAndCache];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:viewController.tableView viewController:viewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.cacheName = @"allHumansCache";
|
||||
|
||||
id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKFetchedResultsTableControllerDelegate)];
|
||||
[[mockDelegate expect] tableControllerDidFinishLoad:tableController];
|
||||
tableController.delegate = mockDelegate;
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:viewController];
|
||||
[tableController loadTable];
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
- (void)testDelegateIsInformedOfDidInsertObjectAtIndexPath {
|
||||
[self bootstrapStoreAndCache];
|
||||
RKFetchedResultsTableControllerSpecViewController* viewController = [RKFetchedResultsTableControllerSpecViewController new];
|
||||
RKFetchedResultsTableController* tableController =
|
||||
[[RKFetchedResultsTableController alloc] initWithTableView:viewController.tableView viewController:viewController];
|
||||
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
|
||||
[cellMapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[tableController mapObjectsWithClass:[RKHuman class] toTableCellsWithMapping:cellMapping];
|
||||
tableController.resourcePath = @"/JSON/humans/all.json";
|
||||
tableController.cacheName = @"allHumansCache";
|
||||
|
||||
id mockDelegate = [OCMockObject niceMockForProtocol:@protocol(RKFetchedResultsTableControllerDelegate)];
|
||||
[[mockDelegate expect] tableController:tableController didInsertObject:OCMOCK_ANY atIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
[[mockDelegate expect] tableController:tableController didInsertObject:OCMOCK_ANY atIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
|
||||
tableController.delegate = mockDelegate;
|
||||
[[[[UIApplication sharedApplication] windows] objectAtIndex:0] setRootViewController:viewController];
|
||||
[tableController loadTable];
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,103 +12,23 @@
|
||||
#import "RKTestUser.h"
|
||||
#import "RKMappableObject.h"
|
||||
#import "RKAbstractTableController_Internals.h"
|
||||
#import "RKTableControllerTestDelegate.h"
|
||||
|
||||
// Expose the object loader delegate for testing purposes...
|
||||
@interface RKTableController () <RKObjectLoaderDelegate>
|
||||
- (void)animationDidStopAddingSwipeView:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context;
|
||||
@end
|
||||
|
||||
@interface RKTestTableControllerDelegate : NSObject <RKTableControllerDelegate>
|
||||
|
||||
@property(nonatomic, readonly, getter = isCancelled) BOOL cancelled;
|
||||
@property(nonatomic, assign) NSTimeInterval timeout;
|
||||
@property(nonatomic, assign) BOOL awaitingResponse;
|
||||
|
||||
+ (id)tableControllerDelegate;
|
||||
- (void)waitForLoad;
|
||||
@end
|
||||
|
||||
@implementation RKTestTableControllerDelegate
|
||||
|
||||
@synthesize timeout = _timeout;
|
||||
@synthesize awaitingResponse = _awaitingResponse;
|
||||
@synthesize cancelled = _cancelled;
|
||||
|
||||
+ (id)tableControllerDelegate {
|
||||
return [[self new] autorelease];
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_timeout = 3;
|
||||
_awaitingResponse = NO;
|
||||
_cancelled = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)waitForLoad {
|
||||
_awaitingResponse = YES;
|
||||
NSDate* startDate = [NSDate date];
|
||||
|
||||
while (_awaitingResponse) {
|
||||
NSLog(@"Awaiting response = %d", _awaitingResponse);
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
if ([[NSDate date] timeIntervalSinceDate:startDate] > self.timeout) {
|
||||
NSLog(@"%@: Timed out!!!", self);
|
||||
_awaitingResponse = NO;
|
||||
[NSException raise:nil format:@"*** Operation timed out after %f seconds...", self.timeout];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma RKTableControllerDelegate methods
|
||||
|
||||
- (void)tableControllerDidFinishLoad:(RKAbstractTableController*)tableController {
|
||||
_awaitingResponse = NO;
|
||||
}
|
||||
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didFailLoadWithError:(NSError *)error {
|
||||
_awaitingResponse = NO;
|
||||
}
|
||||
|
||||
- (void)tableControllerDidCancelLoad:(RKAbstractTableController*)tableController {
|
||||
_awaitingResponse = NO;
|
||||
_cancelled = YES;
|
||||
}
|
||||
|
||||
// NOTE - Delegate methods below are implemented to allow trampoline through
|
||||
// OCMock expectations
|
||||
|
||||
- (void)tableControllerDidStartLoad:(RKAbstractTableController*)tableController {}
|
||||
- (void)tableControllerDidBecomeEmpty:(RKAbstractTableController*)tableController {}
|
||||
- (void)tableController:(RKAbstractTableController*)tableController willLoadTableWithObjectLoader:(RKObjectLoader*)objectLoader {}
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didLoadTableWithObjectLoader:(RKObjectLoader*)objectLoader {}
|
||||
- (void)tableController:(RKAbstractTableController*)tableController willBeginEditing:(id)object atIndexPath:(NSIndexPath*)indexPath {}
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didEndEditing:(id)object atIndexPath:(NSIndexPath*)indexPath {}
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didInsertSection:(RKTableSection*)section atIndex:(NSUInteger)sectionIndex {}
|
||||
- (void)tableController:(RKAbstractTableController*)tableController didRemoveSection:(RKTableSection*)section atIndex:(NSUInteger)sectionIndex {}
|
||||
- (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 {}
|
||||
- (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 {}
|
||||
- (void)tableControllerDidFinalizeLoad:(RKAbstractTableController *)tableController {}
|
||||
|
||||
@end
|
||||
|
||||
@interface RKTableControllerTestTableViewController : UITableViewController
|
||||
@end
|
||||
|
||||
@implementation RKTableControllerTestTableViewController
|
||||
@end
|
||||
|
||||
@interface RKTableControllerSpecViewController : UIViewController
|
||||
@interface RKTableControllerTestViewController : UIViewController
|
||||
@end
|
||||
|
||||
@implementation RKTableControllerSpecViewController
|
||||
@implementation RKTableControllerTestViewController
|
||||
@end
|
||||
|
||||
@interface RKTestUserTableViewCell : UITableViewCell
|
||||
@@ -119,7 +39,7 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface RKTableControllerTest : SenTestCase
|
||||
@interface RKTableControllerTest : RKTestCase
|
||||
|
||||
@end
|
||||
|
||||
@@ -145,12 +65,18 @@
|
||||
|
||||
- (void)testInitializeWithATableViewAndViewController {
|
||||
UITableView* tableView = [UITableView new];
|
||||
RKTableControllerSpecViewController* viewController = [RKTableControllerSpecViewController new];
|
||||
RKTableControllerTestViewController* viewController = [RKTableControllerTestViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerWithTableView:tableView forViewController:viewController];
|
||||
assertThat(tableController.viewController, is(equalTo(viewController)));
|
||||
assertThat(tableController.tableView, is(equalTo(tableView)));
|
||||
}
|
||||
|
||||
- (void)testInitializesToUnloadedState {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(NO)));
|
||||
}
|
||||
|
||||
- (void)testAlwaysHaveAtLeastOneSection {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
assertThat(viewController.tableView, is(notNilValue()));
|
||||
@@ -186,153 +112,84 @@
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:section
|
||||
atIndex:1];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController addSection:section];
|
||||
assertThatInt([tableController.sections count], is(equalToInt(2)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testConnectTheSectionToTheTableModelOnAdd {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:section
|
||||
atIndex:1];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController addSection:section];
|
||||
assertThat(section.tableController, is(equalTo(tableController)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testConnectTheSectionToTheCellMappingsOfTheTableModelWhenNil {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:section
|
||||
atIndex:1];
|
||||
tableController.delegate = mockDelegate;
|
||||
assertThat(section.cellMappings, is(nilValue()));
|
||||
[tableController addSection:section];
|
||||
assertThat(section.cellMappings, is(equalTo(tableController.cellMappings)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testNotConnectTheSectionToTheCellMappingsOfTheTableModelWhenNonNil {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:section
|
||||
atIndex:1];
|
||||
tableController.delegate = mockDelegate;
|
||||
section.cellMappings = [NSMutableDictionary dictionary];
|
||||
[tableController addSection:section];
|
||||
assertThatBool(section.cellMappings == tableController.cellMappings, is(equalToBool(NO)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testCountTheSections {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:section
|
||||
atIndex:1];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController addSection:section];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(2)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testRemoveASection {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:section
|
||||
atIndex:1];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didRemoveSection:section
|
||||
atIndex:1];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController addSection:section];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(2)));
|
||||
[tableController removeSection:section];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(1)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testNotLetRemoveTheLastSection {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:section
|
||||
atIndex:1];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController addSection:section];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(2)));
|
||||
[tableController removeSection:section];
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testInsertASectionAtASpecificIndex {
|
||||
- (void)testInsertASectionAtATestificIndex {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* referenceSection = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:referenceSection
|
||||
atIndex:2];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController insertSection:referenceSection atIndex:2];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(6)));
|
||||
assertThat([tableController.sections objectAtIndex:2], is(equalTo(referenceSection)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testRemoveASectionByIndex {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* section = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:section
|
||||
atIndex:1];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didRemoveSection:section
|
||||
atIndex:1];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController addSection:section];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(2)));
|
||||
[tableController removeSectionAtIndex:1];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(1)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testRaiseAnExceptionWhenAttemptingToRemoveTheLastSection {
|
||||
@@ -354,58 +211,18 @@
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableSection* referenceSection = [RKTableSection section];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:referenceSection
|
||||
atIndex:2];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController insertSection:referenceSection atIndex:2];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(6)));
|
||||
assertThat([tableController sectionAtIndex:2], is(equalTo(referenceSection)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testRemoveAllSections {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:OCMOCK_ANY
|
||||
atIndex:0];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:OCMOCK_ANY
|
||||
atIndex:1];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:OCMOCK_ANY
|
||||
atIndex:2];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:OCMOCK_ANY
|
||||
atIndex:3];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertSection:OCMOCK_ANY
|
||||
atIndex:4];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didRemoveSection:OCMOCK_ANY
|
||||
atIndex:0];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didRemoveSection:OCMOCK_ANY
|
||||
atIndex:1];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didRemoveSection:OCMOCK_ANY
|
||||
atIndex:2];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didRemoveSection:OCMOCK_ANY
|
||||
atIndex:3];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didRemoveSection:OCMOCK_ANY
|
||||
atIndex:4];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
@@ -413,7 +230,6 @@
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(5)));
|
||||
[tableController removeAllSections];
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(1)));
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testReturnASectionByHeaderTitle {
|
||||
@@ -429,7 +245,7 @@
|
||||
}
|
||||
|
||||
- (void)testNotifyTheTableViewOnSectionInsertion {
|
||||
RKTableControllerSpecViewController *viewController = [RKTableControllerSpecViewController new];
|
||||
RKTableControllerTestViewController *viewController = [RKTableControllerTestViewController new];
|
||||
id mockTableView = [OCMockObject niceMockForClass:[UITableView class]];
|
||||
RKTableController *tableController = [RKTableController tableControllerWithTableView:mockTableView forViewController:viewController];
|
||||
[[mockTableView expect] insertSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:tableController.defaultRowAnimation];
|
||||
@@ -438,7 +254,7 @@
|
||||
}
|
||||
|
||||
- (void)testNotifyTheTableViewOnSectionRemoval {
|
||||
RKTableControllerSpecViewController *viewController = [RKTableControllerSpecViewController new];
|
||||
RKTableControllerTestViewController *viewController = [RKTableControllerTestViewController new];
|
||||
id mockTableView = [OCMockObject niceMockForClass:[UITableView class]];
|
||||
RKTableController *tableController = [RKTableController tableControllerWithTableView:mockTableView forViewController:viewController];
|
||||
[[mockTableView expect] insertSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:tableController.defaultRowAnimation];
|
||||
@@ -450,7 +266,7 @@
|
||||
}
|
||||
|
||||
- (void)testNotifyTheTableOfSectionRemovalAndReaddWhenRemovingAllSections {
|
||||
RKTableControllerSpecViewController *viewController = [RKTableControllerSpecViewController new];
|
||||
RKTableControllerTestViewController *viewController = [RKTableControllerTestViewController new];
|
||||
id mockTableView = [OCMockObject niceMockForClass:[UITableView class]];
|
||||
RKTableController *tableController = [RKTableController tableControllerWithTableView:mockTableView forViewController:viewController];
|
||||
[[mockTableView expect] deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:tableController.defaultRowAnimation];
|
||||
@@ -462,7 +278,7 @@
|
||||
[mockTableView verify];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource specs
|
||||
#pragma mark - UITableViewDataSource Tests
|
||||
|
||||
- (void)testRaiseAnExceptionIfSentAMessageWithATableViewItIsNotBoundTo {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
@@ -643,7 +459,7 @@
|
||||
assertThat([tableController sectionAtIndex:0].objects, is(equalTo(objects)));
|
||||
}
|
||||
|
||||
- (void)testLoadAnArrayOfObjectsToTheSpecifiedSection {
|
||||
- (void)testLoadAnArrayOfObjectsToTheTestifiedSection {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
[tableController addSection:[RKTableSection section]];
|
||||
@@ -690,7 +506,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate tableControllerDelegate];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate tableControllerDelegate];
|
||||
delegate.timeout = 10;
|
||||
tableController.delegate = delegate;
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
@@ -726,6 +542,71 @@
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testErrorIsClearedAfterSubsequentLoad {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
id mockObjectLoader = [OCMockObject niceMockForClass:[RKObjectLoader class]];
|
||||
NSError* error = [NSError errorWithDomain:@"Test" code:0 userInfo:nil];
|
||||
[tableController objectLoader:mockObjectLoader didFailWithError:error];
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isError], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
|
||||
[tableController objectLoader:mockObjectLoader didLoadObjects:[NSArray array]];
|
||||
assertThatBool([tableController isError], is(equalToBool(NO)));
|
||||
assertThat(tableController.error, is(nilValue()));
|
||||
}
|
||||
|
||||
- (void)testDisplayOfErrorImageTakesPresendenceOverEmpty {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
UIImage *imageForEmpty = [RKTestFixture imageWithContentsOfFixture:@"blake.png"];
|
||||
UIImage *imageForError = [imageForEmpty copy];
|
||||
tableController.imageForEmpty = imageForEmpty;
|
||||
tableController.imageForError = imageForError;
|
||||
|
||||
id mockObjectLoader = [OCMockObject niceMockForClass:[RKObjectLoader class]];
|
||||
NSError* error = [NSError errorWithDomain:@"Test" code:0 userInfo:nil];
|
||||
[tableController objectLoader:mockObjectLoader didFailWithError:error];
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isError], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
|
||||
UIImage *overlayImage = [tableController overlayImage];
|
||||
assertThat(overlayImage, isNot(nilValue()));
|
||||
assertThat(overlayImage, is(equalTo(imageForError)));
|
||||
}
|
||||
|
||||
- (void)testBitwiseLoadingTransition {
|
||||
RKTableControllerState oldState = RKTableControllerStateNotYetLoaded;
|
||||
RKTableControllerState newState = RKTableControllerStateLoading;
|
||||
|
||||
BOOL loadingTransitioned = ((oldState ^ newState) & RKTableControllerStateLoading);
|
||||
assertThatBool(loadingTransitioned, is(equalToBool(YES)));
|
||||
|
||||
oldState = RKTableControllerStateOffline | RKTableControllerStateEmpty;
|
||||
newState = RKTableControllerStateOffline | RKTableControllerStateEmpty | RKTableControllerStateLoading;
|
||||
loadingTransitioned = ((oldState ^ newState) & RKTableControllerStateLoading);
|
||||
assertThatBool(loadingTransitioned, is(equalToBool(YES)));
|
||||
|
||||
oldState = RKTableControllerStateNormal;
|
||||
newState = RKTableControllerStateLoading;
|
||||
loadingTransitioned = ((oldState ^ newState) & RKTableControllerStateLoading);
|
||||
assertThatBool(loadingTransitioned, is(equalToBool(YES)));
|
||||
|
||||
oldState = RKTableControllerStateOffline | RKTableControllerStateEmpty | RKTableControllerStateLoading;
|
||||
newState = RKTableControllerStateOffline | RKTableControllerStateLoading;
|
||||
loadingTransitioned = ((oldState ^ newState) & RKTableControllerStateLoading);
|
||||
assertThatBool(loadingTransitioned, is(equalToBool(NO)));
|
||||
|
||||
oldState = RKTableControllerStateNotYetLoaded;
|
||||
newState = RKTableControllerStateOffline;
|
||||
loadingTransitioned = ((oldState ^ newState) & RKTableControllerStateLoading);
|
||||
assertThatBool(loadingTransitioned, is(equalToBool(NO)));
|
||||
}
|
||||
|
||||
- (void)testSetTheModelToAnEmptyStateIfTheObjectLoaderReturnsAnEmptyCollection {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
@@ -764,7 +645,7 @@
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
id mockLoader = [OCMockObject mockForClass:[RKObjectLoader class]];
|
||||
id mockLoader = [OCMockObject niceMockForClass:[RKObjectLoader class]];
|
||||
[tableController requestDidStartLoad:mockLoader];
|
||||
assertThatBool([tableController isLoading], is(equalToBool(YES)));
|
||||
[tableController objectLoaderDidFinishLoading:mockLoader];
|
||||
@@ -811,7 +692,7 @@
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate tableControllerDelegate];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate tableControllerDelegate];
|
||||
delegate.timeout = 10;
|
||||
tableController.delegate = delegate;
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
@@ -825,7 +706,44 @@
|
||||
assertThatInt(tableController.rowCount, is(equalToInt(3)));
|
||||
}
|
||||
|
||||
#pragma mark - RKTableViewDelegate specs
|
||||
- (void)testLoadingACollectionOfObjectsIntoSectionsAndThenLoadingAnEmptyCollectionChangesTableToEmpty {
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
objectManager.client.cachePolicy = RKRequestCachePolicyNone;
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
tableController.objectManager = objectManager;
|
||||
[tableController mapObjectsWithClass:[RKTestUser class] toTableCellsWithMapping:[RKTableViewCellMapping cellMappingUsingBlock:^(RKTableViewCellMapping* mapping) {
|
||||
mapping.cellClass = [RKTestUserTableViewCell class];
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
tableController.sectionNameKeyPath = @"name";
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate tableControllerDelegate];
|
||||
delegate.timeout = 10;
|
||||
tableController.delegate = delegate;
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
objectLoader.objectMapping = [RKObjectMapping mappingForClass:[RKTestUser class] usingBlock:^(RKObjectMapping* mapping) {
|
||||
[mapping mapAttributes:@"name", nil];
|
||||
}];
|
||||
}];
|
||||
[delegate waitForLoad];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(YES)));
|
||||
assertThatInt(tableController.sectionCount, is(equalToInt(3)));
|
||||
assertThatInt(tableController.rowCount, is(equalToInt(3)));
|
||||
delegate = [RKTableControllerTestDelegate tableControllerDelegate];
|
||||
delegate.timeout = 10;
|
||||
tableController.delegate = delegate;
|
||||
[tableController loadTableFromResourcePath:@"/204" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
objectLoader.objectMapping = [RKObjectMapping mappingForClass:[RKTestUser class] usingBlock:^(RKObjectMapping* mapping) {
|
||||
[mapping mapAttributes:@"name", nil];
|
||||
}];
|
||||
}];
|
||||
[delegate waitForLoad];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
#pragma mark - RKTableViewDelegate Tests
|
||||
|
||||
- (void)testNotifyTheDelegateWhenLoadingStarts {
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
@@ -837,7 +755,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:[RKTestTableControllerDelegate new]];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:[RKTableControllerTestDelegate new]];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableControllerDidStartLoad:tableController];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
@@ -859,7 +777,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableControllerDidFinishLoad:tableController];
|
||||
tableController.delegate = mockDelegate;
|
||||
@@ -882,7 +800,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[mockDelegate expect] tableControllerDidFinalizeLoad:tableController];
|
||||
tableController.delegate = mockDelegate;
|
||||
@@ -905,7 +823,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController didFailLoadWithError:OCMOCK_ANY];
|
||||
tableController.delegate = mockDelegate;
|
||||
@@ -929,7 +847,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
delegate.timeout = 5;
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableControllerDidBecomeEmpty:tableController];
|
||||
@@ -953,7 +871,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController willLoadTableWithObjectLoader:OCMOCK_ANY];
|
||||
tableController.delegate = mockDelegate;
|
||||
@@ -976,7 +894,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController didLoadTableWithObjectLoader:OCMOCK_ANY];
|
||||
tableController.delegate = mockDelegate;
|
||||
@@ -999,7 +917,7 @@
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableControllerDidCancelLoad:tableController];
|
||||
tableController.delegate = mockDelegate;
|
||||
@@ -1016,7 +934,7 @@
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableItem* tableItem = [RKTableItem tableItem];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didEndEditing:OCMOCK_ANY
|
||||
@@ -1031,7 +949,7 @@
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTableItem* tableItem = [RKTableItem tableItem];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
willBeginEditing:OCMOCK_ANY
|
||||
@@ -1046,7 +964,7 @@
|
||||
NSArray* objects = [NSArray arrayWithObject:@"first object"];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertObject:@"first object"
|
||||
@@ -1068,7 +986,7 @@
|
||||
NSArray* objects = [NSArray arrayWithObjects:@"first object", @"second object", nil];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertObject:@"first object"
|
||||
@@ -1092,7 +1010,7 @@
|
||||
NSArray* objects = [NSArray arrayWithObjects:@"first object", @"second object", nil];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
didInsertObject:@"first object"
|
||||
@@ -1112,6 +1030,82 @@
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testNotifyTheDelegateWhenObjectsAreLoadedInASection {
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
tableController.objectManager = objectManager;
|
||||
[tableController mapObjectsWithClass:[RKTestUser class] toTableCellsWithMapping:[RKTableViewCellMapping cellMappingUsingBlock:^(RKTableViewCellMapping* mapping) {
|
||||
mapping.cellClass = [RKTestUserTableViewCell class];
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[mockDelegate expect] tableController:tableController didLoadObjects:OCMOCK_ANY inSection:OCMOCK_ANY];
|
||||
tableController.delegate = mockDelegate;
|
||||
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
objectLoader.objectMapping = [RKObjectMapping mappingForClass:[RKTestUser class] usingBlock:^(RKObjectMapping* mapping) {
|
||||
[mapping mapAttributes:@"name", nil];
|
||||
}];
|
||||
}];
|
||||
[mockDelegate waitForLoad];
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testDelegateIsNotifiedOfWillDisplayCellForObjectAtIndexPath {
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
tableController.objectManager = objectManager;
|
||||
[tableController mapObjectsWithClass:[RKTestUser class] toTableCellsWithMapping:[RKTableViewCellMapping cellMappingUsingBlock:^(RKTableViewCellMapping* mapping) {
|
||||
mapping.cellClass = [RKTestUserTableViewCell class];
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
}]];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController willLoadTableWithObjectLoader:OCMOCK_ANY];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
objectLoader.objectMapping = [RKObjectMapping mappingForClass:[RKTestUser class] usingBlock:^(RKObjectMapping* mapping) {
|
||||
[mapping mapAttributes:@"name", nil];
|
||||
}];
|
||||
}];
|
||||
[[mockDelegate expect] tableController:tableController willDisplayCell:OCMOCK_ANY forObject:OCMOCK_ANY atIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
[[mockDelegate expect] tableController:tableController willDisplayCell:OCMOCK_ANY forObject:OCMOCK_ANY atIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
|
||||
[[mockDelegate expect] tableController:tableController willDisplayCell:OCMOCK_ANY forObject:OCMOCK_ANY atIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
|
||||
[[[UIApplication sharedApplication].windows objectAtIndex:0] setRootViewController:viewController];
|
||||
[mockDelegate waitForLoad];
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
- (void)testDelegateIsNotifiedOfDidSelectRowForObjectAtIndexPath {
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
tableController.objectManager = objectManager;
|
||||
[tableController mapObjectsWithClass:[RKTestUser class] toTableCellsWithMapping:[RKTableViewCellMapping cellMappingUsingBlock:^(RKTableViewCellMapping* mapping) {
|
||||
mapping.cellClass = [RKTestUserTableViewCell class];
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
}]];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController willLoadTableWithObjectLoader:OCMOCK_ANY];
|
||||
tableController.delegate = mockDelegate;
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
objectLoader.objectMapping = [RKObjectMapping mappingForClass:[RKTestUser class] usingBlock:^(RKObjectMapping* mapping) {
|
||||
[mapping mapAttributes:@"name", nil];
|
||||
}];
|
||||
}];
|
||||
[[mockDelegate expect] tableController:tableController didSelectCell:OCMOCK_ANY forObject:OCMOCK_ANY atIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
[[[UIApplication sharedApplication].windows objectAtIndex:0] setRootViewController:viewController];
|
||||
[mockDelegate waitForLoad];
|
||||
[tableController tableView:tableController.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
STAssertNoThrow([mockDelegate verify], nil);
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)testPostANotificationWhenLoadingStarts {
|
||||
@@ -1127,7 +1121,7 @@
|
||||
id observerMock = [OCMockObject observerMock];
|
||||
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:RKTableControllerDidStartLoadNotification object:tableController];
|
||||
[[observerMock expect] notificationWithName:RKTableControllerDidStartLoadNotification object:tableController];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
tableController.delegate = delegate;
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
objectLoader.objectMapping = [RKObjectMapping mappingForClass:[RKTestUser class] usingBlock:^(RKObjectMapping* mapping) {
|
||||
@@ -1152,7 +1146,7 @@
|
||||
id observerMock = [OCMockObject observerMock];
|
||||
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:RKTableControllerDidFinishLoadNotification object:tableController];
|
||||
[[observerMock expect] notificationWithName:RKTableControllerDidFinishLoadNotification object:tableController];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
tableController.delegate = delegate;
|
||||
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
@@ -1164,6 +1158,32 @@
|
||||
[observerMock verify];
|
||||
}
|
||||
|
||||
- (void)testPostANotificationWhenObjectsAreLoaded {
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
tableController.objectManager = objectManager;
|
||||
[tableController mapObjectsWithClass:[RKTestUser class] toTableCellsWithMapping:[RKTableViewCellMapping cellMappingUsingBlock:^(RKTableViewCellMapping* mapping) {
|
||||
mapping.cellClass = [RKTestUserTableViewCell class];
|
||||
[mapping mapKeyPath:@"name" toAttribute:@"textLabel.text"];
|
||||
[mapping mapKeyPath:@"nickName" toAttribute:@"detailTextLabel.text"];
|
||||
}]];
|
||||
|
||||
id observerMock = [OCMockObject observerMock];
|
||||
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:RKTableControllerDidLoadObjectsNotification object:tableController];
|
||||
[[observerMock expect] notificationWithName:RKTableControllerDidLoadObjectsNotification object:tableController];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
tableController.delegate = delegate;
|
||||
|
||||
[tableController loadTableFromResourcePath:@"/JSON/users.json" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
objectLoader.objectMapping = [RKObjectMapping mappingForClass:[RKTestUser class] usingBlock:^(RKObjectMapping* mapping) {
|
||||
[mapping mapAttributes:@"name", nil];
|
||||
}];
|
||||
}];
|
||||
[delegate waitForLoad];
|
||||
[observerMock verify];
|
||||
}
|
||||
|
||||
- (void)testPostANotificationWhenAnErrorOccurs {
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
@@ -1178,7 +1198,7 @@
|
||||
id observerMock = [OCMockObject observerMock];
|
||||
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:RKTableControllerDidLoadErrorNotification object:tableController];
|
||||
[[observerMock expect] notificationWithName:RKTableControllerDidLoadErrorNotification object:tableController userInfo:OCMOCK_ANY];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
tableController.delegate = delegate;
|
||||
|
||||
[tableController loadTableFromResourcePath:@"/fail" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
@@ -1205,7 +1225,7 @@
|
||||
id observerMock = [OCMockObject observerMock];
|
||||
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:RKTableControllerDidLoadEmptyNotification object:tableController];
|
||||
[[observerMock expect] notificationWithName:RKTableControllerDidLoadEmptyNotification object:tableController];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
tableController.delegate = delegate;
|
||||
[tableController loadTableFromResourcePath:@"/empty/array" usingBlock:^(RKObjectLoader* objectLoader) {
|
||||
objectLoader.objectMapping = [RKObjectMapping mappingForClass:[RKTestUser class] usingBlock:^(RKObjectMapping* mapping) {
|
||||
@@ -1216,6 +1236,109 @@
|
||||
[observerMock verify];
|
||||
}
|
||||
|
||||
#pragma mark - State Transitions
|
||||
|
||||
- (void)testInitializesToNotYetLoadedState {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
assertThatBool(tableController.state == RKTableControllerStateNotYetLoaded, is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testInitialLoadSetsStateToLoading {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
id mockLoader = [OCMockObject mockForClass:[RKObjectLoader class]];
|
||||
[tableController requestDidStartLoad:mockLoader];
|
||||
assertThatBool([tableController isLoading], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(NO)));
|
||||
}
|
||||
|
||||
- (void)testSuccessfulLoadSetsStateToNormal {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
id mockLoader = [OCMockObject mockForClass:[RKObjectLoader class]];
|
||||
[tableController objectLoader:mockLoader didLoadObjects:[NSArray arrayWithObject:@"test"]];
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(YES)));
|
||||
assertThatInteger(tableController.state, is(equalToInteger(RKTableControllerStateNormal)));
|
||||
}
|
||||
|
||||
- (void)testErrorLoadsSetsStateToError {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
id mockLoader = [OCMockObject mockForClass:[RKObjectLoader class]];
|
||||
NSError *error = [NSError errorWithDomain:@"Test" code:1234 userInfo:nil];
|
||||
[tableController objectLoader:mockLoader didFailWithError:error];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isError], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testSecondaryLoadAfterErrorSetsStateToErrorAndLoading {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
id mockLoader = [OCMockObject mockForClass:[RKObjectLoader class]];
|
||||
NSError *error = [NSError errorWithDomain:@"Test" code:1234 userInfo:nil];
|
||||
[tableController objectLoader:mockLoader didFailWithError:error];
|
||||
assertThatBool([tableController isLoaded], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isError], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
[tableController requestDidStartLoad:mockLoader];
|
||||
assertThatBool([tableController isLoading], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isError], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testEmptyLoadSetsStateToEmpty {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
[tableController loadEmpty];
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testSecondaryLoadAfterEmptySetsStateToEmptyAndLoading {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
[tableController loadEmpty];
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
id mockLoader = [OCMockObject mockForClass:[RKObjectLoader class]];
|
||||
[tableController requestDidStartLoad:mockLoader];
|
||||
assertThatBool([tableController isLoading], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testTransitionToOfflineAfterLoadSetsStateToOfflineAndLoaded {
|
||||
RKObjectManager* objectManager = [RKTestFactory objectManager];
|
||||
id mockManager = [OCMockObject partialMockForObject:objectManager];
|
||||
BOOL isOnline = YES;
|
||||
[[[mockManager stub] andReturnValue:OCMOCK_VALUE(isOnline)] isOnline];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
tableController.objectManager = mockManager;
|
||||
[tableController loadEmpty];
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isLoading], is(equalToBool(NO)));
|
||||
assertThatBool([tableController isOffline], is(equalToBool(NO)));
|
||||
id mockLoader = [OCMockObject mockForClass:[RKObjectLoader class]];
|
||||
[tableController requestDidStartLoad:mockLoader];
|
||||
assertThatBool([tableController isLoading], is(equalToBool(YES)));
|
||||
assertThatBool([tableController isEmpty], is(equalToBool(YES)));
|
||||
isOnline = NO;
|
||||
id mockManager2 = [OCMockObject partialMockForObject:objectManager];
|
||||
[[[mockManager2 stub] andReturnValue:OCMOCK_VALUE(isOnline)] isOnline];
|
||||
tableController.objectManager = mockManager2;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RKObjectManagerDidBecomeOfflineNotification object:tableController.objectManager];
|
||||
assertThatBool(tableController.isOffline, is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
#pragma mark - State Views
|
||||
|
||||
- (void)testPermitYouToOverlayAnImageOnTheTable {
|
||||
@@ -1582,7 +1705,7 @@
|
||||
assertThatBool(cellThree.hidden, is(equalToBool(NO)));
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate specs
|
||||
#pragma mark - UITableViewDelegate Tests
|
||||
|
||||
- (void)testInvokeTheOnSelectCellForObjectAtIndexPathBlockHandler {
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
@@ -2019,6 +2142,7 @@
|
||||
[[[mockManager expect] andReturnValue:OCMOCK_VALUE(online)] isOnline];
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
[tableController loadEmpty]; // Load to change the isLoaded state
|
||||
UIImage* image = [RKTestFixture imageWithContentsOfFixture:@"blake.png"];
|
||||
tableController.imageForOffline = image;
|
||||
|
||||
@@ -2081,7 +2205,7 @@
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
tableController.cellSwipeViewsEnabled = YES;
|
||||
RKTableItem* tableItem = [RKTableItem tableItem];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
willAddSwipeView:OCMOCK_ANY
|
||||
@@ -2096,12 +2220,11 @@
|
||||
}
|
||||
|
||||
- (void)testCallTheDelegateBeforeHidingTheSwipeView {
|
||||
// RKLogConfigureByName("RestKit/UI", RKLogLevelTrace);
|
||||
RKTableControllerTestTableViewController* viewController = [RKTableControllerTestTableViewController new];
|
||||
RKTableController* tableController = [RKTableController tableControllerForTableViewController:viewController];
|
||||
tableController.cellSwipeViewsEnabled = YES;
|
||||
RKTableItem* tableItem = [RKTableItem tableItem];
|
||||
RKTestTableControllerDelegate* delegate = [RKTestTableControllerDelegate new];
|
||||
RKTableControllerTestDelegate* delegate = [RKTableControllerTestDelegate new];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:delegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] tableController:tableController
|
||||
willAddSwipeView:OCMOCK_ANY
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKCat" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
assertThat(entity.primaryKeyAttribute, is(equalTo(@"railsID")));
|
||||
assertThat(entity.primaryKeyAttributeName, is(equalTo(@"railsID")));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfUnconfiguredPrimaryKeyAttributeReturnsNil
|
||||
@@ -29,28 +29,28 @@
|
||||
assertThat(entity.primaryKeyAttribute, is(nilValue()));
|
||||
}
|
||||
|
||||
- (void)testSettingPrimaryKeyAttributeProgramatically
|
||||
- (void)testSettingPrimaryKeyAttributeNameProgramatically
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKHouse" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
entity.primaryKeyAttribute = @"houseID";
|
||||
assertThat(entity.primaryKeyAttribute, is(equalTo(@"houseID")));
|
||||
entity.primaryKeyAttributeName = @"houseID";
|
||||
assertThat(entity.primaryKeyAttributeName, is(equalTo(@"houseID")));
|
||||
}
|
||||
|
||||
- (void)testSettingExistingPrimaryKeyAttributeProgramatically
|
||||
- (void)testSettingExistingPrimaryKeyAttributeNameProgramatically
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKCat" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
assertThat(entity.primaryKeyAttribute, is(equalTo(@"railsID")));
|
||||
entity.primaryKeyAttribute = @"catID";
|
||||
assertThat(entity.primaryKeyAttribute, is(equalTo(@"catID")));
|
||||
assertThat(entity.primaryKeyAttributeName, is(equalTo(@"railsID")));
|
||||
entity.primaryKeyAttributeName = @"catID";
|
||||
assertThat(entity.primaryKeyAttributeName, is(equalTo(@"catID")));
|
||||
}
|
||||
|
||||
- (void)testSettingPrimaryKeyAttributeCreatesCachedPredicate
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKCat" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
assertThat(entity.primaryKeyAttribute, is(equalTo(@"railsID")));
|
||||
assertThat(entity.primaryKeyAttributeName, is(equalTo(@"railsID")));
|
||||
assertThat([entity.predicateForPrimaryKeyAttribute predicateFormat], is(equalTo(@"railsID == $PRIMARY_KEY_VALUE")));
|
||||
}
|
||||
|
||||
@@ -58,10 +58,83 @@
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKCat" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
assertThat(entity.primaryKeyAttribute, is(equalTo(@"railsID")));
|
||||
assertThat(entity.primaryKeyAttributeName, is(equalTo(@"railsID")));
|
||||
NSNumber *primaryKeyValue = [NSNumber numberWithInt:12345];
|
||||
NSPredicate *predicate = [entity predicateForPrimaryKeyAttributeWithValue:primaryKeyValue];
|
||||
assertThat([predicate predicateFormat], is(equalTo(@"railsID == 12345")));
|
||||
}
|
||||
|
||||
- (void)testThatPredicateForPrimaryKeyAttributeCastsStringValueToNumber
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKCat" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
assertThat(entity.primaryKeyAttributeName, is(equalTo(@"railsID")));
|
||||
NSPredicate *predicate = [entity predicateForPrimaryKeyAttributeWithValue:@"12345"];
|
||||
assertThat([predicate predicateFormat], is(equalTo(@"railsID == 12345")));
|
||||
}
|
||||
|
||||
- (void)testThatPredicateForPrimaryKeyAttributeCastsNumberToString
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKHouse" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
entity.primaryKeyAttributeName = @"city";
|
||||
NSPredicate *predicate = [entity predicateForPrimaryKeyAttributeWithValue:[NSNumber numberWithInteger:12345]];
|
||||
assertThat([predicate predicateFormat], is(equalTo(@"city == \"12345\"")));
|
||||
}
|
||||
|
||||
- (void)testThatPredicateForPrimaryKeyAttributeReturnsNilForEntityWithoutPrimaryKey
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKHouse" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
entity.primaryKeyAttributeName = nil;
|
||||
NSPredicate *predicate = [entity predicateForPrimaryKeyAttributeWithValue:@"12345"];
|
||||
assertThat([predicate predicateFormat], is(nilValue()));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfPrimaryKeyAttributeReturnsNilIfNotSet
|
||||
{
|
||||
NSEntityDescription *entity = [NSEntityDescription new];
|
||||
assertThat(entity.primaryKeyAttribute, is(nilValue()));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfPrimaryKeyAttributeReturnsNilWhenSetToInvalidAttributeName
|
||||
{
|
||||
NSEntityDescription *entity = [NSEntityDescription new];
|
||||
entity.primaryKeyAttributeName = @"invalidName!";
|
||||
assertThat(entity.primaryKeyAttribute, is(nilValue()));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfPrimaryKeyAttributeForValidAttributeName
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKCat" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
entity.primaryKeyAttributeName = @"railsID";
|
||||
NSAttributeDescription *attribute = entity.primaryKeyAttribute;
|
||||
assertThat(attribute, is(notNilValue()));
|
||||
assertThat(attribute.name, is(equalTo(@"railsID")));
|
||||
assertThat(attribute.attributeValueClassName, is(equalTo(@"NSNumber")));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfPrimaryKeyAttributeClassReturnsNilIfNotSet
|
||||
{
|
||||
NSEntityDescription *entity = [NSEntityDescription new];
|
||||
assertThat([entity primaryKeyAttributeClass], is(nilValue()));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfPrimaryKeyAttributeClassReturnsNilWhenSetToInvalidAttributeName
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKHouse" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
entity.primaryKeyAttributeName = @"invalid";
|
||||
assertThat([entity primaryKeyAttributeClass], is(nilValue()));
|
||||
}
|
||||
|
||||
- (void)testRetrievalOfPrimaryKeyAttributeClassForValidAttributeName
|
||||
{
|
||||
RKManagedObjectStore *objectStore = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKHouse" inManagedObjectContext:objectStore.primaryManagedObjectContext];
|
||||
entity.primaryKeyAttributeName = @"railsID";
|
||||
assertThat([entity primaryKeyAttributeClass], is(equalTo([NSNumber class])));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{
|
||||
RKManagedObjectStore *store = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [RKHuman entityDescription];
|
||||
entity.primaryKeyAttribute = @"railsID";
|
||||
entity.primaryKeyAttributeName = @"railsID";
|
||||
|
||||
RKHuman *human = [RKHuman createEntity];
|
||||
human.railsID = [NSNumber numberWithInt:12345];
|
||||
@@ -35,7 +35,7 @@
|
||||
RKManagedObjectStore *store = [RKTestFactory managedObjectStore];
|
||||
NSManagedObjectContext *context = [[RKTestFactory managedObjectStore] newManagedObjectContext];
|
||||
NSEntityDescription *entity = [RKHuman entityDescription];
|
||||
entity.primaryKeyAttribute = @"railsID";
|
||||
entity.primaryKeyAttributeName = @"railsID";
|
||||
|
||||
RKHuman *human = [RKHuman createInContext:context];
|
||||
human.railsID = [NSNumber numberWithInt:12345];
|
||||
@@ -48,4 +48,18 @@
|
||||
assertThat(foundHuman, is(equalTo(human)));
|
||||
}
|
||||
|
||||
- (void)testFindByPrimaryKeyWithStringValueForNumericProperty
|
||||
{
|
||||
RKManagedObjectStore *store = [RKTestFactory managedObjectStore];
|
||||
NSEntityDescription *entity = [RKHuman entityDescription];
|
||||
entity.primaryKeyAttributeName = @"railsID";
|
||||
|
||||
RKHuman *human = [RKHuman createEntity];
|
||||
human.railsID = [NSNumber numberWithInt:12345];
|
||||
[store save:nil];
|
||||
|
||||
RKHuman *foundHuman = [RKHuman findByPrimaryKey:@"12345" inContext:store.primaryManagedObjectContext];
|
||||
assertThat(foundHuman, is(equalTo(human)));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -175,8 +175,9 @@
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"RKCloud" inManagedObjectContext:store.primaryManagedObjectContext];
|
||||
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntity:entity inManagedObjectStore:store];
|
||||
assertThat(mapping.primaryKeyAttribute, is(nilValue()));
|
||||
mapping.primaryKeyAttribute = @"cloudID";
|
||||
assertThat(entity.primaryKeyAttribute, is(equalTo(@"cloudID")));
|
||||
mapping.primaryKeyAttribute = @"name";
|
||||
assertThat(entity.primaryKeyAttributeName, is(equalTo(@"name")));
|
||||
assertThat(entity.primaryKeyAttribute, is(notNilValue()));
|
||||
}
|
||||
|
||||
#pragma mark - Fetched Results Cache
|
||||
@@ -271,7 +272,7 @@
|
||||
[RKHuman truncateAll];
|
||||
RKManagedObjectMapping* mapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:store];
|
||||
mapping.primaryKeyAttribute = @"name";
|
||||
[RKHuman entity].primaryKeyAttribute = @"railsID";
|
||||
[RKHuman entity].primaryKeyAttributeName = @"railsID";
|
||||
[mapping addAttributeMapping:[RKObjectAttributeMapping mappingFromKeyPath:@"monkey.name" toKeyPath:@"name"]];
|
||||
|
||||
[RKHuman truncateAll];
|
||||
@@ -297,7 +298,7 @@
|
||||
[RKHuman truncateAll];
|
||||
RKManagedObjectMapping* mapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:store];
|
||||
mapping.primaryKeyAttribute = @"name";
|
||||
[RKHuman entity].primaryKeyAttribute = @"railsID";
|
||||
[RKHuman entity].primaryKeyAttributeName = @"railsID";
|
||||
[mapping addAttributeMapping:[RKObjectAttributeMapping mappingFromKeyPath:@"monkey.name" toKeyPath:@"name"]];
|
||||
|
||||
[RKHuman truncateAll];
|
||||
@@ -316,4 +317,30 @@
|
||||
assertThat(cachedObject, is(equalTo(human)));
|
||||
}
|
||||
|
||||
- (void)testThatCreationOfNewObjectWithIncorrectTypeValueForPrimaryKeyAddsToCache
|
||||
{
|
||||
RKManagedObjectStore* store = [RKTestFactory managedObjectStore];
|
||||
store.cacheStrategy = [RKInMemoryManagedObjectCache new];
|
||||
[RKHuman truncateAll];
|
||||
RKManagedObjectMapping* mapping = [RKManagedObjectMapping mappingForClass:[RKHuman class] inManagedObjectStore:store];
|
||||
mapping.primaryKeyAttribute = @"railsID";
|
||||
[RKHuman entity].primaryKeyAttributeName = @"railsID";
|
||||
[mapping addAttributeMapping:[RKObjectAttributeMapping mappingFromKeyPath:@"monkey.name" toKeyPath:@"name"]];
|
||||
[mapping addAttributeMapping:[RKObjectAttributeMapping mappingFromKeyPath:@"monkey.railsID" toKeyPath:@"railsID"]];
|
||||
|
||||
[RKHuman truncateAll];
|
||||
RKHuman* human = [RKHuman object];
|
||||
human.name = @"Testing";
|
||||
human.railsID = [NSNumber numberWithInteger:12345];
|
||||
[store save:nil];
|
||||
assertThatBool([RKHuman hasAtLeastOneEntity], is(equalToBool(YES)));
|
||||
|
||||
NSDictionary* data = [NSDictionary dictionaryWithObject:@"12345" forKey:@"railsID"];
|
||||
NSDictionary* nestedDictionary = [NSDictionary dictionaryWithObject:data forKey:@"monkey"];
|
||||
RKHuman *object = [mapping mappableObjectForData:nestedDictionary];
|
||||
assertThat(object, isNot(nilValue()));
|
||||
assertThat(object, is(equalTo(human)));
|
||||
assertThatInteger([object.railsID integerValue], is(equalToInteger(12345)));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -99,6 +99,12 @@ class RestKitTestServer < Sinatra::Base
|
||||
content_type 'application/json'
|
||||
"".to_json
|
||||
end
|
||||
|
||||
get '/204' do
|
||||
status 204
|
||||
content_type 'application/json'
|
||||
"".to_json
|
||||
end
|
||||
|
||||
get '/403' do
|
||||
status 403
|
||||
|
||||
Reference in New Issue
Block a user