Last active
August 29, 2015 14:20
-
-
Save royratcliffe/3fcb51f1249a08f17680 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// UITableView TableViewData.h | |
// | |
// Copyright © 2015, Roy Ratcliffe, Pioneering Software, United Kingdom | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the “Software”), to deal | |
// in the Software without restriction, including without limitation the rights | |
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in | |
// all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER | |
// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO | |
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES | |
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
// DEALINGS IN THE SOFTWARE. | |
// | |
//------------------------------------------------------------------------------ | |
#import <UIKit/UIKit.h> | |
@class TableViewDataSection; | |
@interface TableViewDataRow : NSObject | |
@property (nonatomic, strong) NSMutableDictionary *info; | |
@property (nonatomic, weak) TableViewDataSection *section; | |
- (instancetype)initWithSection:(TableViewDataSection *)section NS_DESIGNATED_INITIALIZER; | |
- (instancetype)initWithSection:(TableViewDataSection *)section info:(NSDictionary *)info; | |
/// Answers the row information combined with section and data information. The | |
/// answer is a read-only dictionary that you cannot mutate. The resulting | |
/// key-value pairs collate information from the enclosing table data, table | |
/// section and table row. Keys from the row override keys from the section; | |
/// keys from the section override keys from the data. Precedence goes from row | |
/// to section to data. Hence, section information becomes fall-back information | |
/// for every row and data information becomes fall-back information for every | |
/// section. | |
@property (nonatomic, copy, readonly) NSDictionary *defaults; | |
@end | |
@class TableViewData; | |
@interface TableViewDataSection : NSObject | |
@property (nonatomic, strong) NSMutableDictionary *info; | |
@property (nonatomic, strong) NSMutableArray *rows; | |
@property (nonatomic, weak) TableViewData *data; | |
- (instancetype)initWithData:(TableViewData *)data NS_DESIGNATED_INITIALIZER; | |
- (instancetype)initWithData:(TableViewData *)data info:(NSDictionary *)info; | |
- (TableViewDataRow *)newRowWithInfo:(NSDictionary *)info; | |
- (TableViewDataRow *)rowAtIndex:(NSUInteger)index; | |
- (NSArray *)rowsOfValue:(id)value forInfoKey:(id<NSCopying>)key; | |
@property (nonatomic, copy, readonly) NSDictionary *defaults; | |
@end | |
/// Implements the data model for a UI kit table view using arrays and | |
/// dictionaries. Table views display an ordered collection of sections, each | |
/// comprising an ordered collection of rows. Sections of rows. The data model | |
/// coordinates an array of sections, each an array of rows. Mutable | |
/// dictionaries carry section-specific and row-specific pieces of | |
/// information. Sections carry information as well as rows. | |
@interface TableViewData : NSObject <UITableViewDataSource> | |
- (instancetype)init NS_DESIGNATED_INITIALIZER; | |
- (instancetype)initWithInfo:(NSDictionary *)info; | |
@property (nonatomic, strong) NSMutableDictionary *info; | |
@property (nonatomic, strong) NSMutableArray *sections; | |
- (TableViewDataSection *)newSectionWithInfo:(NSDictionary *)info; | |
- (TableViewDataSection *)sectionAtIndex:(NSUInteger)index; | |
/// Answers an array of sections whose information dictionaries carry a given | |
/// key whose value matches a given value. Values match when @c -isEqual: | |
/// answers @c YES. What happens when the section does not have a matching key? | |
/// The answer excludes all sections without the key. | |
- (NSArray *)sectionsOfValue:(id)value forInfoKey:(id<NSCopying>)key; | |
@property (nonatomic, copy, readonly) NSDictionary *defaults; | |
@end | |
extern NSString *const TableViewDataCellIdentifierKey; | |
extern NSString *const TableViewDataConfigureCellBlockKey; | |
extern NSString *const TableViewDataHeaderTitleKey; | |
extern NSString *const TableViewDataFooterTitleKey; | |
typedef void (^TableViewDataConfigureCellBlock)(UITableViewCell *cell, TableViewDataRow *row); | |
@interface UITableViewCell (TableViewData) | |
- (void)configureCellForTableViewDataRow:(TableViewDataRow *)row; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// UITableView TableViewData.m | |
// | |
// Copyright © 2015, Roy Ratcliffe, Pioneering Software, United Kingdom | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the “Software”), to deal | |
// in the Software without restriction, including without limitation the rights | |
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in | |
// all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER | |
// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO | |
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES | |
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
// DEALINGS IN THE SOFTWARE. | |
// | |
//------------------------------------------------------------------------------ | |
#import "TableViewData.h" | |
@implementation TableViewDataRow | |
// designated initialiser | |
- (instancetype)initWithSection:(TableViewDataSection *)section | |
{ | |
self = [super init]; | |
if (self) { | |
self.info = [NSMutableDictionary dictionary]; | |
self.section = section; | |
} | |
return self; | |
} | |
// convenience initialiser | |
- (instancetype)initWithSection:(TableViewDataSection *)section info:(NSDictionary *)info | |
{ | |
self = [self initWithSection:section]; | |
if (self) { | |
[self.info addEntriesFromDictionary:info]; | |
} | |
return self; | |
} | |
- (NSDictionary *)defaults | |
{ | |
NSMutableDictionary *defaults = [NSMutableDictionary dictionary]; | |
[defaults addEntriesFromDictionary:self.section.defaults]; | |
[defaults addEntriesFromDictionary:self.info]; | |
return [defaults copy]; | |
} | |
@end | |
@implementation TableViewDataSection | |
// designated initialiser | |
- (instancetype)initWithData:(TableViewData *)data | |
{ | |
self = [super init]; | |
if (self) { | |
self.info = [NSMutableDictionary dictionary]; | |
self.rows = [NSMutableArray array]; | |
self.data = data; | |
} | |
return self; | |
} | |
// convenience initialiser | |
- (instancetype)initWithData:(TableViewData *)data info:(NSDictionary *)info | |
{ | |
self = [self initWithData:data]; | |
if (self) { | |
[self.info addEntriesFromDictionary:info]; | |
} | |
return self; | |
} | |
- (TableViewDataRow *)newRowWithInfo:(NSDictionary *)info | |
{ | |
TableViewDataRow *row = [[TableViewDataRow alloc] initWithSection:self info:info]; | |
[self.rows addObject:row]; | |
return row; | |
} | |
- (TableViewDataRow *)rowAtIndex:(NSUInteger)index { return self.rows[index]; } | |
- (NSArray *)rowsOfValue:(id)value forInfoKey:(id<NSCopying>)key | |
{ | |
return [self.rows filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(TableViewDataRow *evaluatedObject, NSDictionary *bindings) { | |
id infoValue = evaluatedObject.info[key]; | |
return infoValue != nil && [infoValue isEqual:value]; | |
}]]; | |
} | |
- (NSDictionary *)defaults | |
{ | |
NSMutableDictionary *defaults = [NSMutableDictionary dictionary]; | |
[defaults addEntriesFromDictionary:self.data.defaults]; | |
[defaults addEntriesFromDictionary:self.info]; | |
return [defaults copy]; | |
} | |
@end | |
@implementation TableViewData | |
// designated initialiser | |
- (instancetype)init | |
{ | |
self = [super init]; | |
if (self) { | |
self.info = [NSMutableDictionary dictionary]; | |
self.sections = [NSMutableArray array]; | |
} | |
return self; | |
} | |
// convenience initialiser | |
- (instancetype)initWithInfo:(NSDictionary *)info | |
{ | |
self = [self init]; | |
if (self) { | |
[self.info addEntriesFromDictionary:info]; | |
} | |
return self; | |
} | |
- (TableViewDataSection *)newSectionWithInfo:(NSDictionary *)info | |
{ | |
TableViewDataSection *section = [[TableViewDataSection alloc] initWithData:self info:info]; | |
[self.sections addObject:section]; | |
return section; | |
} | |
- (TableViewDataSection *)sectionAtIndex:(NSUInteger)index { return self.sections[index]; } | |
- (NSArray *)sectionsOfValue:(id)value forInfoKey:(id<NSCopying>)key | |
{ | |
return [self.sections filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(TableViewDataSection *evaluatedObject, NSDictionary *bindings) { | |
id infoValue = evaluatedObject.info[key]; | |
return infoValue != nil && [infoValue isEqual:value]; | |
}]]; | |
} | |
- (NSDictionary *)defaults { return [self.info copy]; } | |
//------------------------------------------------------------------------------ | |
#pragma mark - Table View Data Source | |
//------------------------------------------------------------------------------ | |
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self sectionAtIndex:section].rows.count; } | |
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath | |
{ | |
TableViewDataSection *section = [self sectionAtIndex:indexPath.section]; | |
TableViewDataRow *row = [section rowAtIndex:indexPath.row]; | |
NSString *identifier = row.info[TableViewDataCellIdentifierKey]; | |
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath]; | |
// Configure the cell after de-queuing it if the row information contains a | |
// cell configuration block. The block's arguments define the cell | |
// configuration context. This includes the cell to configure and its row. | |
TableViewDataConfigureCellBlock configureCellBlock = row.info[TableViewDataConfigureCellBlockKey]; | |
if (configureCellBlock) { | |
configureCellBlock(cell, row); | |
} | |
// If the cell class responds to -configureCellForTableViewDataRow: then | |
// send that message passing the table view data row. From the row, the cell | |
// can determine the section and from the section the data. Rows have weak | |
// back-links to their section, sections have weak back-links to the root | |
// data object. From just the row therefore, cells have access to section | |
// and data information. | |
if ([cell respondsToSelector:@selector(configureCellForTableViewDataRow:)]) { | |
[cell configureCellForTableViewDataRow:row]; | |
} | |
return cell; | |
} | |
//--------------------------------------------------------------------- optional | |
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.sections.count; } | |
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section | |
{ | |
return [self sectionAtIndex:section].info[TableViewDataHeaderTitleKey]; | |
} | |
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section | |
{ | |
return [self sectionAtIndex:section].info[TableViewDataFooterTitleKey]; | |
} | |
@end | |
NSString *const TableViewDataCellIdentifierKey = @"cellIdentifier"; | |
NSString *const TableViewDataConfigureCellBlockKey = @"configureCellBlock"; | |
NSString *const TableViewDataHeaderTitleKey = @"headerTitle"; | |
NSString *const TableViewDataFooterTitleKey = @"footerTitle"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment