Files
RestKit/Code/UI/RKTableViewCellMapping.m

275 lines
8.9 KiB
Objective-C

//
// RKTableViewCellMapping.m
// RestKit
//
// Created by Blake Watters on 8/4/11.
// Copyright (c) 2011 RestKit.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "RKTableViewCellMapping.h"
#import "RKLog.h"
// Define logging component
#undef RKLogComponent
#define RKLogComponent lcl_cRestKitUI
/**
A simple class for wrapping blocks into target/action
invocations that can be used with UIControl events
*/
typedef void(^RKControlBlockActionBlock)(id sender);
@interface RKControlBlockAction : NSObject {
@private
RKControlBlockActionBlock _actionBlock;
}
@property (nonatomic, readonly) SEL actionSelector;
+ (id)actionWithBlock:(void(^)(id sender))block;
- (id)initWithBlock:(void(^)(id sender))block;
/**
The target action to use when wrapping a block
*/
- (void)actionForControlEvent:(id)sender;
@end
@implementation RKControlBlockAction
+ (id)actionWithBlock:(void(^)(id sender))block {
return [[[self alloc] initWithBlock:block] autorelease];
}
- (id)initWithBlock:(void(^)(id sender))block {
self = [self init];
if (self) {
_actionBlock = Block_copy(block);
}
return self;
}
- (void)actionForControlEvent:(id)sender {
_actionBlock(sender);
}
- (SEL)actionSelector {
return @selector(actionForControlEvent:);
}
- (void)dealloc {
Block_release(_actionBlock);
[super dealloc];
}
@end
@implementation RKTableViewCellMapping
@synthesize reuseIdentifier = _reuseIdentifier;
@synthesize style = _style;
@synthesize accessoryType = _accessoryType;
@synthesize selectionStyle = _selectionStyle;
@synthesize onSelectCellForObjectAtIndexPath = _onSelectCellForObjectAtIndexPath;
@synthesize onSelectCell = _onSelectCell;
@synthesize onCellWillAppearForObjectAtIndexPath = _onCellWillAppearForObjectAtIndexPath;
@synthesize heightOfCellForObjectAtIndexPath = _heightOfCellForObjectAtIndexPath;
@synthesize onTapAccessoryButtonForObjectAtIndexPath = _onTapAccessoryButtonForObjectAtIndexPath;
@synthesize titleForDeleteButtonForObjectAtIndexPath = _titleForDeleteButtonForObjectAtIndexPath;
@synthesize editingStyleForObjectAtIndexPath = _editingStyleForObjectAtIndexPath;
@synthesize targetIndexPathForMove = _targetIndexPathForMove;
@synthesize rowHeight = _rowHeight;
@synthesize deselectsRowOnSelection = _deselectsRowOnSelection;
@synthesize managesCellAttributes;
+ (id)cellMapping {
return [self mappingForClass:[UITableViewCell class]];
}
+ (id)defaultCellMapping {
RKTableViewCellMapping *cellMapping = [self cellMapping];
[cellMapping addDefaultMappings];
return cellMapping;
}
+ (id)cellMappingUsingBlock:(void (^)(RKTableViewCellMapping*))block {
RKTableViewCellMapping* cellMapping = [self cellMapping];
block(cellMapping);
return cellMapping;
}
- (id)init {
self = [super init];
if (self) {
self.cellClass = [UITableViewCell class];
self.style = UITableViewCellStyleDefault;
self.managesCellAttributes = NO;
_accessoryType = UITableViewCellAccessoryNone;
_selectionStyle = UITableViewCellSelectionStyleBlue;
self.rowHeight = 44;
self.deselectsRowOnSelection = YES;
_prepareCellBlocks = [NSMutableArray new];
}
return self;
}
- (void)addDefaultMappings {
[self mapKeyPath:@"text" toAttribute:@"textLabel.text"];
[self mapKeyPath:@"detailText" toAttribute:@"detailTextLabel.text"];
[self mapKeyPath:@"image" toAttribute:@"imageView.image"];
}
- (void)dealloc {
[_reuseIdentifier release];
[_prepareCellBlocks release];
Block_release(_onSelectCell);
Block_release(_onSelectCellForObjectAtIndexPath);
Block_release(_onCellWillAppearForObjectAtIndexPath);
Block_release(_heightOfCellForObjectAtIndexPath);
Block_release(_onTapAccessoryButtonForObjectAtIndexPath);
Block_release(_titleForDeleteButtonForObjectAtIndexPath);
Block_release(_editingStyleForObjectAtIndexPath);
Block_release(_targetIndexPathForMove);
[super dealloc];
}
- (NSMutableArray *)prepareCellBlocks {
return _prepareCellBlocks;
}
- (id)copyWithZone:(NSZone *)zone {
RKTableViewCellMapping *copy = [super copyWithZone:zone];
copy.reuseIdentifier = self.reuseIdentifier;
copy.style = self.style;
copy.accessoryType = self.accessoryType;
copy.selectionStyle = self.selectionStyle;
copy.onSelectCellForObjectAtIndexPath = self.onSelectCellForObjectAtIndexPath;
copy.onSelectCell = self.onSelectCell;
copy.onCellWillAppearForObjectAtIndexPath = self.onCellWillAppearForObjectAtIndexPath;
copy.heightOfCellForObjectAtIndexPath = self.heightOfCellForObjectAtIndexPath;
copy.onTapAccessoryButtonForObjectAtIndexPath = self.onTapAccessoryButtonForObjectAtIndexPath;
copy.titleForDeleteButtonForObjectAtIndexPath = self.titleForDeleteButtonForObjectAtIndexPath;
copy.editingStyleForObjectAtIndexPath = self.editingStyleForObjectAtIndexPath;
copy.targetIndexPathForMove = self.targetIndexPathForMove;
copy.rowHeight = self.rowHeight;
@synchronized(_prepareCellBlocks) {
for (void (^block)(UITableViewCell *) in _prepareCellBlocks) {
[copy addPrepareCellBlock:[block copy]];
}
}
return copy;
}
- (id)mappableObjectForData:(UITableView *)tableView {
NSAssert([tableView isKindOfClass:[UITableView class]], @"Expected to be invoked with a tableView as the data. Got %@", tableView);
RKLogTrace(@"About to dequeue reusable cell using self.reuseIdentifier=%@", self.reuseIdentifier);
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:self.reuseIdentifier];
if (! cell) {
cell = [[[self.objectClass alloc] initWithStyle:self.style
reuseIdentifier:self.reuseIdentifier] autorelease];
}
if (self.managesCellAttributes) {
cell.accessoryType = self.accessoryType;
cell.selectionStyle = self.selectionStyle;
}
// Fire the prepare callbacks
for (void (^block)(UITableViewCell *) in _prepareCellBlocks) {
block(cell);
}
return cell;
}
- (void)setSelectionStyle:(UITableViewCellSelectionStyle)selectionStyle {
self.managesCellAttributes = YES;
_selectionStyle = selectionStyle;
}
- (void)setAccessoryType:(UITableViewCellAccessoryType)accessoryType {
self.managesCellAttributes = YES;
_accessoryType = accessoryType;
}
- (void)setObjectClass:(Class)objectClass {
NSAssert([objectClass isSubclassOfClass:[UITableViewCell class]], @"Cell mappings can only target classes that inherit from UITableViewCell");
[super setObjectClass:objectClass];
}
- (void)setCellClass:(Class)cellClass {
[self setObjectClass:cellClass];
}
- (NSString*)cellClassName {
return NSStringFromClass(self.cellClass);
}
- (void)setCellClassName:(NSString *)cellClassName {
self.cellClass = NSClassFromString(cellClassName);
}
- (Class)cellClass {
return [self objectClass];
}
- (NSString *)reuseIdentifier {
return _reuseIdentifier ? _reuseIdentifier : NSStringFromClass(self.objectClass);
}
#pragma mark - Control Action Helpers
- (void)addPrepareCellBlock:(void (^)(UITableViewCell *cell))block {
[_prepareCellBlocks addObject:[block copy]];
}
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents toControlAtKeyPath:(NSString *)keyPath {
[self addPrepareCellBlock:^(UITableViewCell *cell) {
UIControl *control = [cell valueForKeyPath:keyPath];
if (control) {
[control addTarget:target action:action forControlEvents:controlEvents];
} else {
// TODO: Logging...
}
}];
}
- (void)addTarget:(id)target action:(SEL)action forTouchEventToControlAtKeyPath:(NSString *)keyPath {
[self addTarget:target action:action forControlEvents:UIControlEventTouchUpInside toControlAtKeyPath:keyPath];
}
- (void)addBlockAction:(void (^)(id sender))block forControlEvents:(UIControlEvents)controlEvents toControlAtKeyPath:(NSString *)keyPath {
[self addPrepareCellBlock:^(UITableViewCell *cell) {
RKControlBlockAction *blockAction = [RKControlBlockAction actionWithBlock:block];
UIControl *control = [cell valueForKeyPath:keyPath];
if (control) {
[control addTarget:blockAction action:blockAction.actionSelector forControlEvents:controlEvents];
} else {
// TODO: Logging...
}
}];
}
- (void)addBlockAction:(void (^)(id sender))block forTouchEventToControlAtKeyPath:(NSString *)keyPath {
[self addBlockAction:block forControlEvents:UIControlEventTouchUpInside toControlAtKeyPath:keyPath];
}
@end