├── FRCCollapsableSectionTableViewDataSource.h ├── FRCCollapsableSectionTableViewDataSource.m ├── FRCFetchedResultsTableViewDataSource.h ├── FRCFetchedResultsTableViewDataSource.m ├── FRCObjectTableViewDataSource.h ├── FRCObjectTableViewDataSource.m ├── FRCParentTableViewDataSource.h ├── FRCParentTableViewDataSource.m ├── FRCSplitTableViewDataSource.h ├── FRCSplitTableViewDataSource.m ├── FRCTableViewCell.h ├── FRCTableViewCell.m ├── FRCTableViewDataSource.h ├── FRCTableViewDataSource.m ├── Images ├── FRCCollapsableSectionTableViewDataSourceDisclosureIndicator.png ├── FRCCollapsableSectionTableViewDataSourceDisclosureIndicator@2x.png ├── FRCCollapsableSectionTableViewDataSourceDisclosureIndicatorHighlighted.png └── FRCCollapsableSectionTableViewDataSourceDisclosureIndicatorHighlighted@2x.png ├── Readme.textile ├── UITableView+FRCTableViewDataSources.h └── UITableView+FRCTableViewDataSources.m /FRCCollapsableSectionTableViewDataSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | FRCCollapsableSectionTableViewDataSource.h 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 30.06.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCParentTableViewDataSource.h" 38 | 39 | /** A class to represent the header cell for the collapsable data source. 40 | */ 41 | @interface FRCCollapsableSectionTableViewDataSourceHeader : NSObject 42 | 43 | /** The title to use in the header cell. 44 | */ 45 | @property (nonatomic, readonly) NSString *title; 46 | 47 | /** YES if the FRCCollapsableSectionTableViewDataSource is open. 48 | */ 49 | @property (nonatomic, readonly) BOOL open; 50 | 51 | /** YES if the FRCCollapsableSectionTableViewDataSource is empty and has 52 | nothing to expand out for. 53 | 54 | The FRCCollapsableSectionTableViewDataSource is deemed to be empty if 55 | it has no childTableViewDataSource or the childTableViewDataSource returns 56 | 0 for tableView:numberOfRowsInSection:. 57 | */ 58 | @property (nonatomic, readonly) BOOL empty; 59 | @end 60 | 61 | 62 | /** A data source that manages one section of a table view which puts a header cell 63 | above its childTableViewDataSource to allow expanding and collapsing in an 64 | acordian style. 65 | */ 66 | @interface FRCCollapsableSectionTableViewDataSource : FRCParentTableViewDataSource 67 | 68 | /** The child data source to expand. 69 | */ 70 | @property (nonatomic, strong) FRCTableViewDataSource *childTableViewDataSource; 71 | 72 | /** The class to use for header cell. Assuming it conforms to the 73 | FRCTableViewCellObjectConfiguration protocol, it will get an instance of 74 | FRCCollapsableSectionTableViewDataSourceHeader that represents the current state 75 | of the collapsable data source. 76 | */ 77 | @property (nonatomic, assign) Class titleCellClass; 78 | 79 | /** The title that should go in the header cell. 80 | */ 81 | @property (nonatomic, copy) NSString *title; 82 | 83 | /** Shows whether the collapsable data source is open or not. You can 84 | also use this to programatically expand or collapse. 85 | */ 86 | @property (nonatomic, assign, getter = isOpen) BOOL open; 87 | 88 | /** A method for subclasses to override to provide a data source to use 89 | for the childTableViewDataSource. 90 | 91 | This method is only called when childTableViewDataSource is nil. 92 | */ 93 | - (void)loadChildTableViewDataSource; 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /FRCCollapsableSectionTableViewDataSource.m: -------------------------------------------------------------------------------- 1 | /* 2 | FRCCollapsableSectionTableViewDataSource.m 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 30.06.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCCollapsableSectionTableViewDataSource.h" 38 | #import "FRCParentTableViewDataSource.h" 39 | #import "FRCTableViewCell.h" 40 | #import "UITableView+FRCTableViewDataSources.h" 41 | #import 42 | #import "FRCObjectTableViewDataSource.h" 43 | #import "FRCSplitTableViewDataSource.h" 44 | 45 | 46 | 47 | @implementation FRCCollapsableSectionTableViewDataSourceHeader { 48 | __strong NSString *title; 49 | BOOL open; 50 | BOOL empty; 51 | } 52 | @synthesize title; 53 | @synthesize open; 54 | @synthesize empty; 55 | - (id)initWithTitle:(NSString *)aTitle open:(BOOL)isOpen empty:(BOOL)isEmpty { 56 | 57 | if (!(self = [super init])) return nil; 58 | 59 | title = [aTitle copy]; 60 | open = isOpen; 61 | empty = isEmpty; 62 | 63 | return self; 64 | } 65 | @end 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | @interface FRCCollapsableSectionTableViewDataSourceHeaderTableViewCell : FRCTableViewCell 75 | @end 76 | @implementation FRCCollapsableSectionTableViewDataSourceHeaderTableViewCell 77 | - (void)configureWithObject:(FRCCollapsableSectionTableViewDataSourceHeader *)object { 78 | 79 | self.textLabel.text = object.title; 80 | 81 | if (object.empty) { 82 | self.textLabel.textColor = [UIColor lightGrayColor]; 83 | self.selectionStyle = UITableViewCellSelectionStyleNone; 84 | } else { 85 | self.textLabel.textColor = [UIColor blackColor]; 86 | self.selectionStyle = UITableViewCellSelectionStyleBlue; 87 | } 88 | } 89 | @end 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | @interface FRCCollapsableSectionTableViewDataSource () 106 | 107 | 108 | - (NSArray *)frcInternal_tableViewIndexPathsForCollapsableCellsIndexPathEnumator:(void (^)(NSIndexPath *))block; 109 | 110 | - (IBAction)frcInternal_titleTapped:(UITapGestureRecognizer *)sender; 111 | - (void)frcInternal_setOpened; 112 | - (void)frcInternal_setClosed; 113 | 114 | - (void)frcInternal_headerCheck; 115 | - (BOOL)frcInternal_childTableViewDataSourceCurrentlyHasCells; 116 | 117 | - (void)frcInternal_setSplitChild:(FRCTableViewDataSource *)dataSource; 118 | 119 | @property (nonatomic, readonly) NSIndexPath *frcInternal_headerTableViewIndexPath; 120 | @property (nonatomic, readonly) UITableViewCell *frcInternal_headerCell; 121 | 122 | @end 123 | 124 | @implementation FRCCollapsableSectionTableViewDataSource { 125 | BOOL childTableViewDataSourceHasCells; 126 | BOOL canReloadHeaderCell; 127 | 128 | BOOL tableViewHasLoaded; 129 | 130 | __strong FRCSplitTableViewDataSource *splitDataSource; 131 | __strong FRCObjectTableViewDataSource *headerDataSource; 132 | } 133 | 134 | @synthesize childTableViewDataSource; 135 | @synthesize title; 136 | @synthesize open; 137 | @synthesize titleCellClass; 138 | 139 | #pragma mark - NSObject 140 | 141 | - (id)init { 142 | 143 | if (!(self = [super init])) return nil; 144 | 145 | splitDataSource = [[FRCSplitTableViewDataSource alloc] init]; 146 | splitDataSource.type = FRCSplitTableViewDataSourceTypeRow; 147 | splitDataSource.parent = self; 148 | 149 | headerDataSource = [[FRCObjectTableViewDataSource alloc] init]; 150 | headerDataSource.cellClass = [FRCCollapsableSectionTableViewDataSourceHeaderTableViewCell class]; 151 | 152 | [splitDataSource addChildTableViewDataSource:headerDataSource]; 153 | 154 | return self; 155 | } 156 | 157 | #pragma mark - FRCCollapsableSectionTableViewDataSource 158 | 159 | - (FRCTableViewDataSource *)childTableViewDataSource { 160 | 161 | if (!childTableViewDataSource) 162 | [self loadChildTableViewDataSource]; 163 | 164 | return childTableViewDataSource; 165 | } 166 | 167 | - (void)setChildTableViewDataSource:(FRCTableViewDataSource *)ds { 168 | 169 | if (childTableViewDataSource == ds) return; 170 | 171 | childTableViewDataSource = ds; 172 | 173 | if (self.open && ds) 174 | [self frcInternal_setSplitChild:ds]; 175 | else { 176 | ds.parent = self; // This makes it ask us if it should update, to which we'll respond no when it's not showing. 177 | ds.tableView = nil; 178 | } 179 | [self frcInternal_headerCheck]; 180 | } 181 | 182 | - (void)loadChildTableViewDataSource {} 183 | 184 | #pragma mark - FRCTableViewDataSource 185 | 186 | - (id)objectAtIndexPath:(NSIndexPath *)indexPath { 187 | 188 | if (indexPath.row == 0) 189 | return [[FRCCollapsableSectionTableViewDataSourceHeader alloc] initWithTitle:self.title open:self.open empty:![self frcInternal_childTableViewDataSourceCurrentlyHasCells]]; 190 | 191 | return [super objectAtIndexPath:indexPath]; 192 | } 193 | 194 | #pragma mark - FRCParentTableViewDataSource 195 | 196 | - (NSArray *)childTableViewDataSources { 197 | return [NSArray arrayWithObject:splitDataSource]; 198 | } 199 | 200 | - (BOOL)childTableViewDataSourceShouldUpdateCells:(FRCTableViewDataSource *)dataSource { 201 | 202 | canReloadHeaderCell = YES; 203 | [self frcInternal_headerCheck]; 204 | 205 | if (!self.open) return NO; 206 | 207 | if (self.parent == nil) return YES; 208 | 209 | return [self.parent childTableViewDataSourceShouldUpdateCells:self]; 210 | } 211 | 212 | #pragma mark - UITableViewDataSource 213 | 214 | - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath { 215 | 216 | self.tableView = tv; 217 | tableViewHasLoaded = YES; 218 | 219 | if (indexPath.row == 0) 220 | headerDataSource.object = [self objectAtIndexPath:indexPath]; 221 | 222 | UITableViewCell *cell = [super tableView:tv cellForRowAtIndexPath:indexPath]; 223 | 224 | if (indexPath.row == 0) { 225 | 226 | UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(frcInternal_titleTapped:)]; 227 | [cell addGestureRecognizer:gr]; 228 | gr.delaysTouchesBegan = NO; 229 | gr.delaysTouchesEnded = NO; 230 | 231 | if ([self frcInternal_childTableViewDataSourceCurrentlyHasCells]) { 232 | UIImage *image = [UIImage imageNamed:@"FRCCollapsableSectionTableViewDataSourceDisclosureIndicator.png"]; 233 | UIImageView *iv = [[UIImageView alloc] initWithImage:image]; 234 | iv.highlightedImage = [UIImage imageNamed:@"FRCCollapsableSectionTableViewDataSourceDisclosureIndicatorHighlighted.png"]; 235 | cell.accessoryView = iv; 236 | cell.accessoryView.layer.transform = CATransform3DMakeRotation(self.open ? (CGFloat)M_PI : 0.0f, 0.0f, 0.0f, 1.0f); 237 | } else { 238 | cell.accessoryView = nil; 239 | cell.accessoryType = UITableViewCellAccessoryNone; 240 | } 241 | } 242 | 243 | return cell; 244 | } 245 | 246 | #pragma mark - Internal 247 | 248 | - (IBAction)frcInternal_titleTapped:(UITapGestureRecognizer *)sender { 249 | self.open = !self.open; 250 | } 251 | 252 | - (NSArray *)frcInternal_tableViewIndexPathsForCollapsableCellsIndexPathEnumator:(void (^)(NSIndexPath *))block { 253 | 254 | NSInteger numberOfRows = [self.childTableViewDataSource tableView:self.tableView numberOfRowsInSection:0]; 255 | 256 | if (numberOfRows == 0) { 257 | childTableViewDataSourceHasCells = NO; 258 | return nil; 259 | } 260 | 261 | childTableViewDataSourceHasCells = YES; 262 | 263 | NSMutableArray *indexPaths = [[NSMutableArray alloc] initWithCapacity:numberOfRows]; 264 | 265 | for (NSInteger i = 0; i < numberOfRows; i++) { 266 | NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0]; 267 | 268 | if (block) block(ip); 269 | 270 | ip = [self.tableView frc_convertIndexPath:ip fromChildTableViewDataSource:self.childTableViewDataSource]; 271 | [indexPaths addObject:ip]; 272 | } 273 | 274 | return [indexPaths copy]; 275 | } 276 | 277 | - (void)frcInternal_setSplitChild:(FRCTableViewDataSource *)dataSource { 278 | NSArray *children = splitDataSource.childTableViewDataSources; 279 | if ([children count] > 1) [splitDataSource removeChildTableViewDataSource:[children lastObject]]; 280 | 281 | [splitDataSource addChildTableViewDataSource:self.childTableViewDataSource]; 282 | } 283 | 284 | - (void)frcInternal_setOpened { 285 | 286 | [self frcInternal_setSplitChild:self.childTableViewDataSource]; 287 | 288 | if (!tableViewHasLoaded) return; 289 | 290 | __block CGFloat totalCellHeight = self.frcInternal_headerCell.bounds.size.height; 291 | CGFloat tableViewHeight = self.tableView.bounds.size.height; 292 | 293 | // If it's grouped we need room for the space between sections. 294 | if (self.tableView.style == UITableViewStyleGrouped) 295 | tableViewHeight -= 20.0f; 296 | 297 | NSArray *indexPaths = [self frcInternal_tableViewIndexPathsForCollapsableCellsIndexPathEnumator:^(NSIndexPath *ip) { 298 | 299 | if (totalCellHeight < tableViewHeight) { // Add this check so we can reduce the amount of calls to heightForObject:width: 300 | Class cellClass = [self cellClassAtIndexPath:ip]; 301 | totalCellHeight += [cellClass heightForObject:[self objectAtIndexPath:ip] width:self.tableView.bounds.size.width]; 302 | } 303 | 304 | }]; 305 | 306 | if ([indexPaths count] == 0) return; 307 | 308 | NSIndexPath *headerIndexPath = self.frcInternal_headerTableViewIndexPath; 309 | 310 | if (totalCellHeight < tableViewHeight) { 311 | [self.tableView scrollToRowAtIndexPath:[indexPaths lastObject] atScrollPosition:UITableViewScrollPositionNone animated:YES]; 312 | [self.tableView scrollToRowAtIndexPath:headerIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES]; 313 | } else { 314 | [self.tableView scrollToRowAtIndexPath:headerIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; 315 | } 316 | } 317 | 318 | - (void)frcInternal_setClosed { 319 | 320 | NSArray *children = splitDataSource.childTableViewDataSources; 321 | if ([children count] == 1) return; 322 | 323 | [splitDataSource removeChildTableViewDataSource:self.childTableViewDataSource]; 324 | self.childTableViewDataSource.parent = self; // This makes it ask us if it should update, to which we'll respond no when it's not showing. 325 | self.childTableViewDataSource.tableView = nil; 326 | 327 | [self.tableView scrollToRowAtIndexPath:self.frcInternal_headerTableViewIndexPath 328 | atScrollPosition:UITableViewScrollPositionNone 329 | animated:YES]; 330 | } 331 | 332 | - (void)setOpen:(BOOL)aBool { 333 | 334 | if (open == aBool) return; 335 | 336 | open = aBool; 337 | 338 | if (aBool) 339 | [self frcInternal_setOpened]; 340 | else 341 | [self frcInternal_setClosed]; 342 | 343 | UIView *accessoryView = self.frcInternal_headerCell.accessoryView; 344 | 345 | if (!accessoryView) return; 346 | 347 | [UIView beginAnimations:@"some" context:nil]; 348 | [UIView setAnimationDuration:0.33]; 349 | accessoryView.layer.transform = CATransform3DMakeRotation(aBool ? (CGFloat)M_PI : 0.0f, 0.0f, 0.0f, 1.0f); 350 | [UIView commitAnimations]; 351 | } 352 | 353 | - (void)setTitleCellClass:(Class)cellClass { 354 | 355 | if (titleCellClass == cellClass) return; 356 | 357 | titleCellClass = cellClass; 358 | headerDataSource.cellClass = cellClass; 359 | } 360 | 361 | - (void)frcInternal_headerCheck { 362 | 363 | if (!canReloadHeaderCell) return; 364 | 365 | if (childTableViewDataSourceHasCells == [self frcInternal_childTableViewDataSourceCurrentlyHasCells]) return; 366 | 367 | childTableViewDataSourceHasCells = !childTableViewDataSourceHasCells; 368 | 369 | NSIndexPath *headerIndexPath = self.frcInternal_headerTableViewIndexPath; 370 | [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:headerIndexPath] 371 | withRowAnimation:UITableViewRowAnimationFade]; 372 | } 373 | 374 | - (BOOL)frcInternal_childTableViewDataSourceCurrentlyHasCells { 375 | return ([self.childTableViewDataSource tableView:self.tableView numberOfRowsInSection:0] > 0); 376 | } 377 | 378 | 379 | 380 | #pragma mark - Header Cell 381 | 382 | - (NSIndexPath *)frcInternal_headerTableViewIndexPath { 383 | NSIndexPath *headerIndexPath = [NSIndexPath indexPathForRow:0 inSection:0]; 384 | return [self.tableView frc_convertIndexPath:headerIndexPath fromChildTableViewDataSource:self]; 385 | } 386 | 387 | - (UITableViewCell *)frcInternal_headerCell { 388 | return [self.tableView cellForRowAtIndexPath:self.frcInternal_headerTableViewIndexPath]; 389 | } 390 | 391 | @end 392 | -------------------------------------------------------------------------------- /FRCFetchedResultsTableViewDataSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | FRCFetchedResultsTableViewDataSource.h 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 20.05.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCTableViewDataSource.h" 38 | #import 39 | 40 | /** A block that returns a fetch request. This is useful to use in the case 41 | where your fetch request might change, for example a search interface. */ 42 | typedef NSFetchRequest *(^FRCFetchRequestBlock)(); 43 | 44 | /** A data source that stays in sync with a Core Data fetch request using a 45 | NSFetchedResultsController. 46 | 47 | You can set this up in a number of ways: 48 | 49 | - Provide a fetchedResultsController 50 | - Provide a managedObjectContext and a fetchRequest 51 | - Provide a managedObjectContext and a fetchRequestBlock 52 | - Implement loadFetchedResultsController in a subclass 53 | - Provide a managedObjectContext and implement loadFetchRequest in a subclass 54 | 55 | There may be other combinations that work also. Note however that without 56 | a managed object context and some form of fetch request, this will crash. 57 | */ 58 | @interface FRCFetchedResultsTableViewDataSource : FRCTableViewDataSource 59 | 60 | /** The managed obejct context that is associated with the fetched results 61 | controller. 62 | */ 63 | @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; 64 | 65 | /** The fetched results controller that is controlling the data for cells 66 | maintained by this data source. 67 | */ 68 | @property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController; 69 | 70 | /** The fetch request being used. 71 | */ 72 | @property (nonatomic, strong) NSFetchRequest *fetchRequest; 73 | 74 | /** A fetch request block to provide a fetch request. 75 | */ 76 | @property (nonatomic, copy) FRCFetchRequestBlock fetchRequestBlock; 77 | 78 | /** Subclasses should use this method to load a fetch request. 79 | 80 | This method is only called if the fetchRequest property is nil. */ 81 | - (void)loadFetchRequest; 82 | 83 | /** Subclasses should use this method to load a fetched results controller. 84 | 85 | This method is only called if the fetchedResultsController property is nil. */ 86 | - (void)loadFetchedResultsController; 87 | 88 | @property (nonatomic, assign) BOOL showIndexList; 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /FRCFetchedResultsTableViewDataSource.m: -------------------------------------------------------------------------------- 1 | /* 2 | FRCFetchedResultsTableViewDataSource.m 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 20.05.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCFetchedResultsTableViewDataSource.h" 38 | #import "FRCTableViewCell.h" 39 | #import "FRCParentTableViewDataSource.h" 40 | #import "UITableView+FRCTableViewDataSources.h" 41 | 42 | @implementation FRCFetchedResultsTableViewDataSource 43 | 44 | @synthesize managedObjectContext; 45 | @synthesize fetchedResultsController; 46 | @synthesize fetchRequestBlock; 47 | @synthesize fetchRequest; 48 | @synthesize showIndexList; 49 | 50 | #pragma mark - FRCTableViewDataSource 51 | 52 | - (void)reloadData { 53 | 54 | if (self.fetchRequestBlock != nil) 55 | self.fetchRequest = self.fetchRequestBlock(); 56 | } 57 | 58 | - (id)objectAtIndexPath:(NSIndexPath *)indexPath { 59 | return [self.fetchedResultsController objectAtIndexPath:indexPath]; 60 | } 61 | 62 | #pragma mark - FRCFetchedResultsTableViewDataSource 63 | 64 | - (void)setFetchRequest:(NSFetchRequest *)fr { 65 | 66 | if ([fr isEqual:fetchRequest]) return; 67 | 68 | fetchedResultsController = nil; 69 | 70 | fetchRequest = fr; 71 | 72 | if (self.managedObjectContext) [self fetchedResultsController]; // Causes the FRC to load 73 | } 74 | 75 | - (NSFetchRequest *)fetchRequest { 76 | 77 | if (fetchRequest == nil) [self loadFetchRequest]; 78 | 79 | return fetchRequest; 80 | } 81 | 82 | - (void)loadFetchRequest { 83 | 84 | if (self.fetchRequestBlock != nil) 85 | self.fetchRequest = self.fetchRequestBlock(); 86 | } 87 | 88 | - (void)setFetchedResultsController:(NSFetchedResultsController *)frc { 89 | 90 | if ([fetchedResultsController isEqual:frc]) return; 91 | 92 | if (frc && (self.managedObjectContext == nil || self.managedObjectContext != frc.managedObjectContext)) 93 | self.managedObjectContext = frc.managedObjectContext; 94 | 95 | fetchedResultsController.delegate = nil; 96 | fetchedResultsController = frc; 97 | 98 | fetchedResultsController.delegate = self; 99 | [fetchedResultsController performFetch:nil]; 100 | 101 | [self.tableView reloadData]; 102 | } 103 | 104 | - (NSFetchedResultsController *)fetchedResultsController { 105 | 106 | if (fetchedResultsController == nil) [self loadFetchedResultsController]; 107 | 108 | return fetchedResultsController; 109 | } 110 | 111 | - (void)loadFetchedResultsController { 112 | 113 | if (!self.fetchRequest) return; 114 | if (!self.managedObjectContext) return; 115 | 116 | self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:self.fetchRequest 117 | managedObjectContext:self.managedObjectContext 118 | sectionNameKeyPath:nil 119 | cacheName:nil]; 120 | } 121 | 122 | #pragma mark - UITableViewDataSource 123 | 124 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 125 | return [[self.fetchedResultsController sections] count]; 126 | } 127 | 128 | - (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section { 129 | id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; 130 | return [sectionInfo numberOfObjects]; 131 | } 132 | 133 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 134 | 135 | NSInteger amount = [self tableView:tableView numberOfRowsInSection:indexPath.section]; 136 | if (indexPath.row >= amount) { 137 | NSLog(@"%@:%@ RELOADING TABLE VIEW NAH NAH NAH", self, NSStringFromSelector(_cmd)); 138 | [tableView reloadData]; 139 | return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"blah"]; 140 | } 141 | 142 | return [super tableView:tableView cellForRowAtIndexPath:indexPath]; 143 | } 144 | 145 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 146 | id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; 147 | return [sectionInfo name]; 148 | } 149 | 150 | - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { 151 | 152 | if (!showIndexList) return nil; 153 | 154 | return [self.fetchedResultsController sectionIndexTitles]; 155 | } 156 | 157 | - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { 158 | return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index]; 159 | } 160 | 161 | #pragma mark - NSFetchedResultsControllerDelegate 162 | 163 | // These methods are taken straight from Apple's documentation on NSFetchedResultsController. 164 | 165 | - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 166 | 167 | if (self.parent != nil && ![self.parent childTableViewDataSourceShouldUpdateCells:self]) 168 | return; 169 | 170 | [self.tableView beginUpdates]; 171 | } 172 | 173 | 174 | - (void)controller:(NSFetchedResultsController *)controller 175 | didChangeSection:(id )sectionInfo 176 | atIndex:(NSUInteger)sectionIndex 177 | forChangeType:(NSFetchedResultsChangeType)type { 178 | 179 | if (!self.tableView) return; 180 | 181 | if (self.parent != nil && ![self.parent childTableViewDataSourceShouldUpdateCells:self]) 182 | return; 183 | 184 | sectionIndex = [self.tableView frc_convertSection:sectionIndex fromChildTableViewDataSource:self]; 185 | 186 | switch(type) { 187 | case NSFetchedResultsChangeInsert: 188 | [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] 189 | withRowAnimation:UITableViewRowAnimationFade]; 190 | break; 191 | 192 | case NSFetchedResultsChangeDelete: 193 | [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] 194 | withRowAnimation:UITableViewRowAnimationFade]; 195 | break; 196 | } 197 | } 198 | 199 | 200 | - (void)controller:(NSFetchedResultsController *)controller 201 | didChangeObject:(id)anObject 202 | atIndexPath:(NSIndexPath *)indexPath 203 | forChangeType:(NSFetchedResultsChangeType)type 204 | newIndexPath:(NSIndexPath *)newIndexPath { 205 | 206 | if (self.parent != nil && ![self.parent childTableViewDataSourceShouldUpdateCells:self]) 207 | return; 208 | 209 | indexPath = [self.tableView frc_convertIndexPath:indexPath fromChildTableViewDataSource:self]; 210 | newIndexPath = [self.tableView frc_convertIndexPath:newIndexPath fromChildTableViewDataSource:self]; 211 | 212 | UITableView *tv = self.tableView; 213 | 214 | if (!tv) return; 215 | 216 | switch(type) { 217 | 218 | case NSFetchedResultsChangeInsert: 219 | [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 220 | withRowAnimation:FRCTableViewDataSourceTableViewRowAnimationAutomatic]; 221 | break; 222 | 223 | case NSFetchedResultsChangeDelete: 224 | [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 225 | withRowAnimation:FRCTableViewDataSourceTableViewRowAnimationAutomatic]; 226 | break; 227 | 228 | case NSFetchedResultsChangeUpdate: 229 | [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 230 | withRowAnimation:UITableViewRowAnimationNone]; 231 | break; 232 | 233 | case NSFetchedResultsChangeMove: 234 | [tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 235 | withRowAnimation:FRCTableViewDataSourceTableViewRowAnimationAutomatic]; 236 | [tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 237 | withRowAnimation:FRCTableViewDataSourceTableViewRowAnimationAutomatic]; 238 | break; 239 | } 240 | } 241 | 242 | - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 243 | 244 | if (self.parent != nil && ![self.parent childTableViewDataSourceShouldUpdateCells:self]) 245 | return; 246 | 247 | [self.tableView endUpdates]; 248 | } 249 | 250 | 251 | 252 | @end 253 | -------------------------------------------------------------------------------- /FRCObjectTableViewDataSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | FRCObjectTableViewDataSource.h 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 19.09.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCTableViewDataSource.h" 38 | 39 | /** A simple, perhaps the most simple, data source class. It gives back one 40 | section and one row, displaying a cell with the given represented object. 41 | 42 | For example if you wanted a default cell, with the text "Hello world!" to 43 | appear in your table view, you would write this: 44 | 45 | FRCObjectTableViewDataSource *ds = [[FRCObjectTableViewDataSource alloc] init]; 46 | ds.object = @"Hello world!"; 47 | tableview.dataSource = ds; 48 | 49 | If you want a custom cell, you just assign its class to the cellClass property 50 | and an instance of that class will be created, if it conforms to 51 | FRCTableViewCellObjectConfiguration, then it will get a message to 52 | [configureWithObject:]([FRCTableViewCell configureWithObject:]) with the 53 | given object for you to set up with. 54 | */ 55 | @interface FRCObjectTableViewDataSource : FRCTableViewDataSource 56 | 57 | /** The represented object for the single cell in this data soruce. 58 | */ 59 | @property (nonatomic, strong) id object; 60 | @end 61 | -------------------------------------------------------------------------------- /FRCObjectTableViewDataSource.m: -------------------------------------------------------------------------------- 1 | /* 2 | FRCObjectTableViewDataSource.m 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 19.09.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCObjectTableViewDataSource.h" 38 | #import "FRCParentTableViewDataSource.h" 39 | #import "UITableView+FRCTableViewDataSources.h" 40 | 41 | @implementation FRCObjectTableViewDataSource 42 | 43 | @synthesize object; 44 | 45 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 46 | return 1; 47 | } 48 | 49 | - (id)objectAtIndexPath:(NSIndexPath *)indexPath { 50 | return self.object; 51 | } 52 | 53 | - (void)reloadData { 54 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; 55 | indexPath = [self.tableView frc_convertIndexPath:indexPath fromChildTableViewDataSource:self]; 56 | [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /FRCParentTableViewDataSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | FRCParentTableViewDataSource.h 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 20.08.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCTableViewDataSource.h" 38 | 39 | /** This is an abstract class that implements forwarding of the UITableViewDataSource methods to child data source 40 | objects. You should use a subclass or make your own parent subclass, which must implement all of the methods declared 41 | here. 42 | 43 | Examples of concrete subclasses are FRCSplitTableViewDataSource and FRCCollapsableSectionTableViewDataSource. 44 | */ 45 | @interface FRCParentTableViewDataSource : FRCTableViewDataSource 46 | 47 | /// @name Conversion 48 | 49 | /** Conversion method 50 | 51 | @param section The section in the co-ordinate space of the child. 52 | @param dataSource The child data source. 53 | 54 | @return The section in the co-ordinate space of the parent. 55 | */ 56 | - (NSInteger)convertSection:(NSInteger)section fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource; 57 | 58 | /** Conversion method 59 | 60 | @param section The section in the co-ordinate space of the parent. 61 | @param dataSource The child data source. 62 | 63 | @return The section in the co-ordinate space of the child. 64 | */ 65 | - (NSInteger)convertSection:(NSInteger)section toChildTableViewDataSource:(FRCTableViewDataSource *)dataSource; 66 | 67 | /** Conversion method 68 | 69 | @param indexPath The index path in the co-ordinate space of the child. 70 | @param dataSource The child data source. 71 | 72 | @return The index path in the co-ordinate space of the parent. 73 | */ 74 | - (NSIndexPath *)convertIndexPath:(NSIndexPath *)indexPath fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource; 75 | 76 | /** Conversion method 77 | 78 | @param indexPath The index path in the co-ordinate space of the parent. 79 | @param dataSource The child data source. 80 | 81 | @return The index path in the co-ordinate space of the child. 82 | */ 83 | - (NSIndexPath *)convertIndexPath:(NSIndexPath *)indexPath toChildTableViewDataSource:(FRCTableViewDataSource *)dataSource; 84 | 85 | /// @name Retrieving child data sources 86 | 87 | /** This should return an array of all the child data sources. 88 | 89 | All these data sources should have thier parent set as this data source. 90 | */ 91 | @property (nonatomic, readonly) NSArray *childTableViewDataSources; 92 | 93 | 94 | /** Retrieves the child data source for a given section. 95 | 96 | @param section The section the caller wants a data source for. This should be 97 | in the "co-ordinates" of the data source you are calling to. 98 | 99 | @return The data source object for the given section. 100 | */ 101 | - (FRCTableViewDataSource *)childTableViewDataSourceForSection:(NSInteger)section; 102 | 103 | /** Retrieves the child data source for a given index path. 104 | 105 | @param indexPath The indexPath the caller wants a data source for. This should be 106 | in the "co-ordinates" of the data source you are calling to. 107 | 108 | @return The data source object for the given indexPath. 109 | */ 110 | - (FRCTableViewDataSource *)childTableViewDataSourceForIndexPath:(NSIndexPath *)indexPath; 111 | 112 | /// @name Parental guidance 113 | 114 | /** Allows the parent to prevent the child data source from updating. 115 | 116 | Children should use this method to determine whether they should insert, 117 | delete or update cells in their control. 118 | 119 | An example of this is FRCCollapsableSectionTableViewDataSource, which will return NO when 120 | it is closed. This way an updating child, like a FRCFetchedResultsTableViewDataSource 121 | will be prevented from inserting or deleting cells into the tableView. 122 | 123 | @param dataSource The child data source that is asking whether it can update. 124 | 125 | @return YES if the child can update the table, NO if not. 126 | */ 127 | - (BOOL)childTableViewDataSourceShouldUpdateCells:(FRCTableViewDataSource *)dataSource; 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /FRCParentTableViewDataSource.m: -------------------------------------------------------------------------------- 1 | /* 2 | FRCParentTableViewDataSource.m 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 20.08.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCParentTableViewDataSource.h" 38 | 39 | @implementation FRCParentTableViewDataSource 40 | 41 | #pragma mark - FRCTableViewDataSource 42 | 43 | - (void)reloadData { 44 | for (FRCTableViewDataSource * ds in self.childTableViewDataSources) 45 | [ds reloadData]; 46 | } 47 | 48 | - (id)objectAtIndexPath:(NSIndexPath *)indexPath { 49 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForIndexPath:indexPath]; 50 | indexPath = [self convertIndexPath:indexPath toChildTableViewDataSource:ds]; 51 | return [ds objectAtIndexPath:indexPath]; 52 | } 53 | 54 | - (Class)cellClassAtIndexPath:(NSIndexPath *)indexPath { 55 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForIndexPath:indexPath]; 56 | indexPath = [self convertIndexPath:indexPath toChildTableViewDataSource:ds]; 57 | return [ds cellClassAtIndexPath:indexPath]; 58 | } 59 | 60 | - (void)setTableView:(UITableView *)tv { 61 | 62 | if (tv == self.tableView) return; 63 | 64 | [super setTableView:tv]; 65 | 66 | [self.childTableViewDataSources enumerateObjectsUsingBlock:^(FRCTableViewDataSource * ds, NSUInteger idx, BOOL *stop) { 67 | [ds setTableView:self.tableView]; 68 | }]; 69 | } 70 | 71 | #pragma mark - FRCParentTableViewDataSource 72 | 73 | - (NSArray *)childTableViewDataSources { 74 | return nil; 75 | } 76 | 77 | - (NSIndexPath *)convertIndexPath:(NSIndexPath *)indexPath fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 78 | NSAssert([self.childTableViewDataSources containsObject:dataSource], @"dataSource should be in the childTableViewDataSources"); 79 | return indexPath; 80 | } 81 | 82 | - (NSIndexPath *)convertIndexPath:(NSIndexPath *)indexPath toChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 83 | NSAssert([self.childTableViewDataSources containsObject:dataSource], @"dataSource should be in the childTableViewDataSources"); 84 | return indexPath; 85 | } 86 | 87 | - (NSInteger)convertSection:(NSInteger)section fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 88 | NSAssert([self.childTableViewDataSources containsObject:dataSource], @"dataSource should be in the childTableViewDataSources"); 89 | return section; 90 | } 91 | 92 | - (NSInteger)convertSection:(NSInteger)section toChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 93 | NSAssert([self.childTableViewDataSources containsObject:dataSource], @"dataSource should be in the childTableViewDataSources"); 94 | return section; 95 | } 96 | 97 | - (FRCTableViewDataSource *)childTableViewDataSourceForSection:(NSInteger)section { 98 | return [self.childTableViewDataSources lastObject]; 99 | } 100 | 101 | - (FRCTableViewDataSource *)childTableViewDataSourceForIndexPath:(NSIndexPath *)indexPath { 102 | return [self.childTableViewDataSources lastObject]; 103 | } 104 | 105 | - (BOOL)childTableViewDataSourceShouldUpdateCells:(FRCTableViewDataSource *)dataSource { 106 | return NO; 107 | } 108 | 109 | #pragma mark - UITableViewDataSource 110 | 111 | - (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section { 112 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForSection:section]; 113 | section = [self convertSection:section toChildTableViewDataSource:ds]; 114 | return [ds tableView:tv numberOfRowsInSection:section]; 115 | } 116 | 117 | - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath { 118 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForIndexPath:indexPath]; 119 | indexPath = [self convertIndexPath:indexPath toChildTableViewDataSource:ds]; 120 | return [ds tableView:tv cellForRowAtIndexPath:indexPath]; 121 | } 122 | 123 | #pragma mark Optional 124 | 125 | - (NSString *)tableView:(UITableView *)tv titleForHeaderInSection:(NSInteger)section { 126 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForSection:section]; 127 | 128 | if (![ds respondsToSelector:_cmd]) return nil; 129 | 130 | section = [self convertSection:section toChildTableViewDataSource:ds]; 131 | return [ds tableView:tv titleForHeaderInSection:section]; 132 | } 133 | 134 | - (NSString *)tableView:(UITableView *)tv titleForFooterInSection:(NSInteger)section { 135 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForSection:section]; 136 | 137 | if (![ds respondsToSelector:_cmd]) return nil; 138 | 139 | section = [self convertSection:section toChildTableViewDataSource:ds]; 140 | return [ds tableView:tv titleForFooterInSection:section]; 141 | } 142 | 143 | #pragma mark Editing 144 | 145 | - (BOOL)tableView:(UITableView *)tv canEditRowAtIndexPath:(NSIndexPath *)indexPath { 146 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForIndexPath:indexPath]; 147 | 148 | if (![ds respondsToSelector:_cmd]) return NO; 149 | 150 | indexPath = [self convertIndexPath:indexPath toChildTableViewDataSource:ds]; 151 | return [ds tableView:tv canEditRowAtIndexPath:indexPath]; 152 | } 153 | 154 | #pragma mark Moving/reordering 155 | 156 | - (BOOL)tableView:(UITableView *)tv canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 157 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForIndexPath:indexPath]; 158 | 159 | if (![ds respondsToSelector:_cmd]) return NO; 160 | 161 | indexPath = [self convertIndexPath:indexPath toChildTableViewDataSource:ds]; 162 | return [ds tableView:tv canMoveRowAtIndexPath:indexPath]; 163 | } 164 | 165 | #pragma mark Data manipulation - insert and delete support 166 | 167 | - (void)tableView:(UITableView *)tv commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 168 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForIndexPath:indexPath]; 169 | 170 | if (![ds respondsToSelector:_cmd]) return; 171 | 172 | indexPath = [self convertIndexPath:indexPath toChildTableViewDataSource:ds]; 173 | [ds tableView:tv commitEditingStyle:editingStyle forRowAtIndexPath:indexPath]; 174 | } 175 | 176 | - (void)tableView:(UITableView *)tv moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { 177 | FRCTableViewDataSource * ds = [self childTableViewDataSourceForIndexPath:sourceIndexPath]; 178 | NSIndexPath *dsSourceIndexPath = [self convertIndexPath:sourceIndexPath toChildTableViewDataSource:ds]; 179 | NSIndexPath *dsDestinationIndexPath = [self convertIndexPath:sourceIndexPath toChildTableViewDataSource:ds]; 180 | 181 | FRCTableViewDataSource * ds2 = [self childTableViewDataSourceForIndexPath:destinationIndexPath]; 182 | NSIndexPath *ds2SourceIndexPath = [self convertIndexPath:sourceIndexPath toChildTableViewDataSource:ds2]; 183 | NSIndexPath *ds2DestinationIndexPath = [self convertIndexPath:destinationIndexPath toChildTableViewDataSource:ds2]; 184 | 185 | if (![ds respondsToSelector:_cmd] || ![ds2 respondsToSelector:_cmd]) return; 186 | 187 | [ds tableView:tv moveRowAtIndexPath:dsSourceIndexPath toIndexPath:dsDestinationIndexPath]; 188 | [ds2 tableView:tv moveRowAtIndexPath:ds2SourceIndexPath toIndexPath:ds2DestinationIndexPath]; 189 | } 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /FRCSplitTableViewDataSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | FRCSplitTableViewDataSource.h 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 16.09.2010. 6 | 7 | 8 | 9 | Copyright (c) 2010 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import 38 | #import "FRCParentTableViewDataSource.h" 39 | 40 | typedef enum { 41 | FRCSplitTableViewDataSourceTypeSection = 0, 42 | FRCSplitTableViewDataSourceTypeRow 43 | } FRCSplitTableViewDataSourceType; 44 | 45 | /** A class to provide a way of displaying data from multiple data sources in a table view. */ 46 | @interface FRCSplitTableViewDataSource : FRCParentTableViewDataSource 47 | 48 | /** Add a child data source. This calls to the tableView to animate the cells in. 49 | 50 | @param dataSource The data source to add as a child. 51 | */ 52 | - (void)addChildTableViewDataSource:(FRCTableViewDataSource *)dataSource; 53 | 54 | /** Remove a child data source. This calls to the tableView to animate out the cells. 55 | 56 | @param dataSource The child data source to remove. 57 | */ 58 | - (void)removeChildTableViewDataSource:(FRCTableViewDataSource *)dataSource; 59 | 60 | /** The type of the split. 61 | 62 | - *FRCSplitTableViewDataSourceTypeSection* Splits each child 63 | table view data source into separate sections 64 | - *FRCSplitTableViewDataSourceTypeRow* Makes this data source responsible for once section 65 | and joins each child table view data source one after the other inside this section. 66 | */ 67 | @property (nonatomic, assign) FRCSplitTableViewDataSourceType type; 68 | @end 69 | -------------------------------------------------------------------------------- /FRCSplitTableViewDataSource.m: -------------------------------------------------------------------------------- 1 | /* 2 | FRCSplitTableViewDataSource.m 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 16.09.2010. 6 | 7 | 8 | 9 | Copyright (c) 2010 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCSplitTableViewDataSource.h" 38 | #import "UITableView+FRCTableViewDataSources.h" 39 | 40 | @interface FRCSplitTableViewDataSource () 41 | - (NSMutableArray *)frcInternal_tableViewDataSources; 42 | - (void)frcInternal_setupDataSource:(FRCTableViewDataSource *)dataSource; 43 | - (NSArray *)frcInternal_indexPathsForDataSource:(FRCTableViewDataSource *)dataSource; 44 | @end 45 | 46 | @implementation FRCSplitTableViewDataSource { 47 | __strong NSMutableArray *frcInternal_tableViewDataSources; 48 | BOOL tableViewHasSetup; 49 | } 50 | 51 | @synthesize type; 52 | 53 | #pragma mark - FRCParentTableViewDataSource 54 | 55 | - (NSArray *)childTableViewDataSources { 56 | return [[self frcInternal_tableViewDataSources] copy]; 57 | } 58 | 59 | - (NSIndexPath *)convertIndexPath:(NSIndexPath *)indexPath fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 60 | 61 | NSAssert([frcInternal_tableViewDataSources containsObject:dataSource], @"dataSource should be a child table view data source"); 62 | 63 | NSArray *dataSources = [self frcInternal_tableViewDataSources]; 64 | 65 | if (self.type == FRCSplitTableViewDataSourceTypeRow) { 66 | 67 | __block NSInteger row = indexPath.row; 68 | 69 | [dataSources enumerateObjectsUsingBlock:^(FRCTableViewDataSource *ds, NSUInteger idx, BOOL *stop) { 70 | 71 | if ([ds isEqual:dataSource]) 72 | *stop = YES; 73 | else 74 | row += [ds tableView:self.tableView numberOfRowsInSection:0]; 75 | 76 | }]; 77 | 78 | indexPath = [NSIndexPath indexPathForRow:row inSection:0]; 79 | 80 | } else { 81 | 82 | indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:[dataSources indexOfObject:dataSource]]; 83 | } 84 | 85 | return indexPath; 86 | } 87 | 88 | - (NSInteger)convertSection:(NSInteger)section fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 89 | 90 | NSAssert([frcInternal_tableViewDataSources containsObject:dataSource], @"dataSource should be a child table view data source"); 91 | 92 | if (self.type == FRCSplitTableViewDataSourceTypeRow) 93 | section = 0; 94 | else 95 | section = [[self frcInternal_tableViewDataSources] indexOfObject:dataSource]; 96 | 97 | return section; 98 | } 99 | 100 | - (NSIndexPath *)convertIndexPath:(NSIndexPath *)indexPath toChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 101 | 102 | NSAssert([frcInternal_tableViewDataSources containsObject:dataSource], @"dataSource should be a child table view data source"); 103 | 104 | if (self.type == FRCSplitTableViewDataSourceTypeRow) { 105 | 106 | __block NSInteger totalRows = 0; 107 | NSInteger row = indexPath.row; 108 | 109 | [[self frcInternal_tableViewDataSources] enumerateObjectsUsingBlock:^(FRCTableViewDataSource *ds, NSUInteger idx, BOOL *stop) { 110 | 111 | NSInteger numberOfRows = [ds tableView:self.tableView numberOfRowsInSection:0]; 112 | 113 | if ((totalRows + numberOfRows) > row) 114 | *stop = YES; 115 | else 116 | totalRows += numberOfRows; 117 | }]; 118 | 119 | row = indexPath.row - totalRows; 120 | 121 | return [NSIndexPath indexPathForRow:row inSection:0]; 122 | } 123 | 124 | return [NSIndexPath indexPathForRow:indexPath.row inSection:0]; 125 | } 126 | 127 | - (NSInteger)convertSection:(NSInteger)section toChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 128 | NSAssert([frcInternal_tableViewDataSources containsObject:dataSource], @"dataSource should be a child table view data source"); 129 | return 0; 130 | } 131 | 132 | - (FRCTableViewDataSource *)childTableViewDataSourceForSection:(NSInteger)section { 133 | 134 | NSArray *dataSources = [self frcInternal_tableViewDataSources]; 135 | 136 | if (self.type == FRCSplitTableViewDataSourceTypeRow) { 137 | 138 | NSAssert([dataSources count] > 0, @"Something's gone wrong."); 139 | 140 | return [dataSources objectAtIndex:0]; 141 | } 142 | 143 | return [dataSources objectAtIndex:section]; 144 | } 145 | 146 | - (FRCTableViewDataSource *)childTableViewDataSourceForIndexPath:(NSIndexPath *)indexPath { 147 | 148 | if (self.type == FRCSplitTableViewDataSourceTypeRow) { 149 | 150 | __block NSInteger totalRows = 0; 151 | __block FRCTableViewDataSource * dataSource = nil; 152 | NSInteger row = indexPath.row; 153 | 154 | [[self frcInternal_tableViewDataSources] enumerateObjectsUsingBlock:^(FRCTableViewDataSource *ds, NSUInteger idx, BOOL *stop) { 155 | 156 | NSInteger numberOfRows = [ds tableView:self.tableView numberOfRowsInSection:0]; 157 | 158 | totalRows += numberOfRows; 159 | 160 | if (totalRows > row) { 161 | dataSource = ds; 162 | *stop = YES; 163 | } 164 | }]; 165 | 166 | return dataSource; 167 | } 168 | 169 | return [[self frcInternal_tableViewDataSources] objectAtIndex:indexPath.section]; 170 | } 171 | 172 | - (BOOL)childTableViewDataSourceShouldUpdateCells:(FRCTableViewDataSource *)dataSource { 173 | 174 | if (!self.parent) return YES; 175 | 176 | return [self.parent childTableViewDataSourceShouldUpdateCells:self]; 177 | } 178 | 179 | 180 | #pragma mark - FRCSplitTableViewDataSource methods 181 | 182 | - (void)addChildTableViewDataSource:(FRCTableViewDataSource *)tableViewDataSource { 183 | 184 | NSMutableArray *childDataSources = [self frcInternal_tableViewDataSources]; 185 | 186 | [childDataSources addObject:tableViewDataSource]; 187 | 188 | [self frcInternal_setupDataSource:tableViewDataSource]; 189 | 190 | if (!tableViewHasSetup) return; 191 | 192 | if (self.type == FRCSplitTableViewDataSourceTypeRow) { 193 | 194 | NSArray *indexPaths = [self frcInternal_indexPathsForDataSource:tableViewDataSource]; 195 | [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:FRCTableViewDataSourceTableViewRowAnimationAutomatic]; 196 | 197 | } else { 198 | 199 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:[childDataSources indexOfObject:tableViewDataSource]]; 200 | [self.tableView insertSections:indexSet withRowAnimation:FRCTableViewDataSourceTableViewRowAnimationAutomatic]; 201 | 202 | } 203 | } 204 | 205 | - (void)removeChildTableViewDataSource:(FRCTableViewDataSource *)tableViewDataSource { 206 | 207 | NSAssert([frcInternal_tableViewDataSources containsObject:tableViewDataSource], @"dataSource should be a child table view data source"); 208 | 209 | NSMutableArray *childDataSources = [self frcInternal_tableViewDataSources]; 210 | 211 | 212 | if (self.type == FRCSplitTableViewDataSourceTypeRow) { 213 | 214 | NSArray *indexPaths = [self frcInternal_indexPathsForDataSource:tableViewDataSource]; 215 | 216 | [childDataSources removeObject:tableViewDataSource]; 217 | 218 | if (!tableViewHasSetup) return; 219 | 220 | [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:FRCTableViewDataSourceTableViewRowAnimationAutomatic]; 221 | 222 | } else { 223 | 224 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:[childDataSources indexOfObject:tableViewDataSource]]; 225 | 226 | [childDataSources removeObject:tableViewDataSource]; 227 | 228 | if (!tableViewHasSetup) return; 229 | 230 | [self.tableView deleteSections:indexSet withRowAnimation:FRCTableViewDataSourceTableViewRowAnimationAutomatic]; 231 | 232 | } 233 | } 234 | 235 | #pragma mark - UITableViewDataSource methods 236 | 237 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tv { 238 | tableViewHasSetup = YES; 239 | self.tableView = tv; 240 | return [[self frcInternal_tableViewDataSources] count]; 241 | } 242 | 243 | - (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section { 244 | tableViewHasSetup = YES; 245 | if (self.type == FRCSplitTableViewDataSourceTypeSection) 246 | return [super tableView:tv numberOfRowsInSection:section]; 247 | 248 | 249 | __block NSInteger numberOfRows = 0; 250 | 251 | [[self frcInternal_tableViewDataSources] enumerateObjectsUsingBlock:^(FRCTableViewDataSource * ds, NSUInteger idx, BOOL *stop) { 252 | numberOfRows += [ds tableView:self.tableView numberOfRowsInSection:0]; 253 | }]; 254 | 255 | return numberOfRows; 256 | } 257 | 258 | #pragma mark - Private methods 259 | 260 | - (NSArray *)frcInternal_indexPathsForDataSource:(FRCTableViewDataSource *)dataSource { 261 | 262 | NSInteger numberOfRows = [dataSource tableView:self.tableView numberOfRowsInSection:0]; 263 | 264 | NSMutableArray *indexPaths = [[NSMutableArray alloc] initWithCapacity:numberOfRows]; 265 | 266 | for (NSInteger i = 0; i < numberOfRows; i++) { 267 | NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0]; 268 | ip = [self.tableView frc_convertIndexPath:ip fromChildTableViewDataSource:dataSource]; 269 | [indexPaths addObject:ip]; 270 | } 271 | 272 | return [indexPaths copy]; 273 | } 274 | 275 | - (NSMutableArray *)frcInternal_tableViewDataSources { 276 | 277 | if (!frcInternal_tableViewDataSources) 278 | frcInternal_tableViewDataSources = [[NSMutableArray alloc] init]; 279 | 280 | return frcInternal_tableViewDataSources; 281 | } 282 | 283 | - (void)frcInternal_setupDataSource:(FRCTableViewDataSource *)dataSource { 284 | dataSource.tableView = self.tableView; 285 | dataSource.parent = self; 286 | } 287 | 288 | @end 289 | -------------------------------------------------------------------------------- /FRCTableViewCell.h: -------------------------------------------------------------------------------- 1 | /* 2 | FRCTableViewCell.h 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 09.07.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import 38 | 39 | 40 | /** While most cells used in the FRCTableViewDataSource system should be 41 | subclasses of FRCTableViewCell, you might want to use a third party cell 42 | that cannot be a subclass. You can still take advantage of the object 43 | configuration system by implementing this protocol. 44 | */ 45 | @protocol FRCTableViewCellObjectConfiguration 46 | 47 | /** Allows you to configure the cell with the given object. 48 | 49 | After dequeuing the cell (or getting the cell for the first time), the 50 | FRCTableViewDataSource calls this method with the associated object. 51 | 52 | @param object The object the cell is representing. 53 | */ 54 | - (void)configureWithObject:(id)object; 55 | 56 | /** A way to provide a custom height given the object. 57 | 58 | In some cases, you may way to have a custom height for your cell. This 59 | class method allows us to determine how big a cell should be without having 60 | an instance. Use this method to perform calculations for the height of 61 | the cell. 62 | 63 | @param object The object the cell is representing. 64 | @param width The width of the table view the cell will be put into. 65 | 66 | @return The height for the cell. 67 | */ 68 | + (CGFloat)heightForObject:(id)object width:(CGFloat)width; 69 | 70 | @end 71 | 72 | 73 | /** A table view cell class that implments the FRCTableViewCellObjectConfiguration 74 | protocol as well as enabling really easy way to set up a cell inside a nib 75 | or storyboard. 76 | */ 77 | @interface FRCTableViewCell : UITableViewCell 78 | 79 | /** Get an instance of the cell, either from a nib if one exists or via alloc, init. 80 | 81 | @return An instance of cell class. 82 | */ 83 | + (id)cell; 84 | 85 | /** The reuse identifier for the cell. 86 | 87 | By default, in the FRCTableViewDataSource system one cell class maps to 88 | one reuseIdentifier, which is the class name as a string. Subclass cells in 89 | nibs should use the class name as a reuse identifier. 90 | 91 | @return The reuse identifier. 92 | */ 93 | + (NSString *)reuseIdentifier; 94 | 95 | /** This is the nibName to use to load and find the table view cell. 96 | 97 | By default it is the same name as the class. 98 | 99 | @return The nib name. 100 | */ 101 | + (NSString *)nibName; 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /FRCTableViewCell.m: -------------------------------------------------------------------------------- 1 | /* 2 | FRCTableViewCell.m 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 09.07.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCTableViewCell.h" 38 | 39 | @interface FRCTableViewCell () 40 | + (BOOL)frcInternal_nibExistsWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle; 41 | @end 42 | 43 | @implementation FRCTableViewCell 44 | 45 | #pragma mark - UITableViewCell 46 | 47 | - (void)prepareForReuse { 48 | [super prepareForReuse]; 49 | self.textLabel.text = nil; 50 | } 51 | 52 | #pragma mark - FRCTableViewCell 53 | 54 | + (id)cell { 55 | 56 | NSString *nibName = [self nibName]; 57 | 58 | if (!nibName) 59 | return [[self alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[self reuseIdentifier]]; 60 | 61 | NSArray *items = [[NSBundle mainBundle] loadNibNamed:nibName owner:nil options:nil]; 62 | 63 | for (id object in items) 64 | if ([object isKindOfClass:self]) 65 | return object; 66 | 67 | return nil; 68 | } 69 | 70 | + (NSString *)reuseIdentifier { 71 | return NSStringFromClass(self); 72 | } 73 | 74 | - (NSString *)reuseIdentifier { 75 | return [[self class] reuseIdentifier]; 76 | } 77 | 78 | + (NSString *)nibName { 79 | 80 | NSString *nibName = NSStringFromClass(self); 81 | 82 | if ([self frcInternal_nibExistsWithNibName:nibName bundle:nil]) 83 | return nibName; 84 | 85 | return nil; 86 | } 87 | 88 | - (void)configureWithObject:(id)object { 89 | self.textLabel.text = [object description]; 90 | } 91 | 92 | + (CGFloat)heightForObject:(id)object width:(CGFloat)width { 93 | return 44.0f; 94 | } 95 | 96 | #pragma mark - Internal 97 | 98 | + (BOOL)frcInternal_nibExistsWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle { 99 | 100 | if (nibName == nil) return NO; 101 | 102 | if (bundle == nil) bundle = [NSBundle mainBundle]; 103 | 104 | NSString *path = [bundle pathForResource:nibName ofType:@"nib"]; 105 | 106 | if (path == nil) path = [bundle pathForResource:nibName ofType:@"xib"]; // Is this check needed? All xibs will get compiled to nibs right? 107 | 108 | if (path == nil) return NO; 109 | 110 | return YES; 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /FRCTableViewDataSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | FRCTableViewDataSource.m 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 20.05.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import 38 | 39 | #if !defined dct_weak && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_5_0 40 | #define frc_weak weak 41 | #define __frc_weak __weak 42 | #define frc_nil(x) 43 | #define FRCTableViewDataSourceTableViewRowAnimationAutomatic UITableViewRowAnimationAutomatic 44 | #elif !defined dct_weak && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_3 45 | #define frc_weak unsafe_unretained 46 | #define __frc_weak __unsafe_unretained 47 | #define frc_nil(x) x = nil 48 | #define FRCTableViewDataSourceTableViewRowAnimationAutomatic UITableViewRowAnimationFade 49 | #else 50 | #warning "This library uses ARC which is only available in iOS SDK 4.3 and later." 51 | #endif 52 | 53 | #ifndef frctableviewdatasources 54 | #define frctableviewdatasources_1_0 10000 55 | #define frctableviewdatasources_1_0_1 10001 56 | #define frctableviewdatasources_1_0_2 10002 57 | #define frctableviewdatasources frctableviewdatasources_1_0_2 58 | #endif 59 | 60 | #import 61 | #import 62 | 63 | @class FRCParentTableViewDataSource; 64 | 65 | /** An abstract class to represent a core FRCTableViewDataSource object. Examples of concrete 66 | subclasses are FRCObjectTableViewDataSource and FRCFetchedResultsTableViewDataSource. 67 | 68 | When subclassing, generally you should write your own implmentation for the objectAtIndexPath: 69 | and reloadData methods. 70 | */ 71 | @interface FRCTableViewDataSource : NSObject 72 | 73 | /** This is the class to use for cells of this data source. 74 | 75 | Ideally this should should be a subclass of FRCTableViewCell or 76 | implement the FRCTableViewCellObjectConfiguration protocol for best reseults. 77 | */ 78 | @property (nonatomic, assign) Class cellClass; 79 | 80 | 81 | /** The table view that is associated with the data source. 82 | */ 83 | @property (nonatomic, strong) IBOutlet UITableView *tableView; 84 | 85 | /** A parent data source, if one exists. 86 | 87 | To enable nesting any data source has the potential to have a 88 | parent, although this is not always true (for instance the root 89 | data source). 90 | */ 91 | @property (nonatomic, frc_weak) FRCParentTableViewDataSource *parent; 92 | 93 | /** A convinient way to repload the cells of the data source, this 94 | should be overridden by subclasses to provide desired results. 95 | */ 96 | - (void)reloadData; 97 | 98 | /** To get the associated object from the data source for the given 99 | index path. By default this returns the index path, but subclasses 100 | should return the correct object to use. 101 | 102 | If the cellClass conforms to FRCTableViewCellObjectConfiguration, 103 | it is this object that will be given to the cell when 104 | configureWithObject: is called. 105 | 106 | @param indexPath The index path in the co-ordinate space of the data source. 107 | 108 | @return The representing object. 109 | */ 110 | - (id)objectAtIndexPath:(NSIndexPath *)indexPath; 111 | 112 | /** To enable a data source to have different cell classes for different 113 | index paths. 114 | 115 | This method returns the class in the property cellClass. Subclasses 116 | should override for different results. 117 | 118 | @param indexPath The index path in the co-ordinate space of the data source. 119 | 120 | @return The class of the cell to use. 121 | */ 122 | - (Class)cellClassAtIndexPath:(NSIndexPath *)indexPath; 123 | 124 | /** This allows subclasses to simply configure the cell without needing 125 | to implement the standard tableView:cellForRowAtIndexPath: method. 126 | 127 | @param cell The cell to be configured. 128 | @param indexPath The index path in the co-ordinate space of the data source. 129 | @param object The represented object at the indexPath. 130 | */ 131 | - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath withObject:(id)object; 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /FRCTableViewDataSource.m: -------------------------------------------------------------------------------- 1 | /* 2 | FRCTableViewDataSource.h 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 20.05.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "FRCTableViewDataSource.h" 38 | #import "FRCTableViewCell.h" 39 | #import "UITableView+FRCTableViewDataSources.h" 40 | 41 | @implementation FRCTableViewDataSource 42 | 43 | @synthesize tableView; 44 | @synthesize cellClass; 45 | @synthesize parent; 46 | 47 | #pragma mark - NSObject 48 | 49 | - (void)dealloc { 50 | frc_nil(self.parent); 51 | } 52 | 53 | - (id)init { 54 | 55 | if (!(self = [super init])) return nil; 56 | 57 | self.cellClass = [FRCTableViewCell class]; 58 | 59 | return self; 60 | } 61 | 62 | #pragma mark - FRCTableViewDataSource 63 | 64 | - (void)setCellClass:(Class)aCellClass { 65 | 66 | cellClass = aCellClass; 67 | 68 | [self.tableView frc_registerFRCTableViewCellSubclass:self.cellClass]; 69 | } 70 | 71 | - (void)setTableView:(UITableView *)tv { 72 | 73 | if (self.tableView == tv) return; 74 | 75 | tableView = tv; 76 | 77 | [self.tableView frc_registerFRCTableViewCellSubclass:self.cellClass]; 78 | } 79 | 80 | - (void)reloadData {} 81 | 82 | - (id)objectAtIndexPath:(NSIndexPath *)indexPath { 83 | return indexPath; 84 | } 85 | 86 | - (Class)cellClassAtIndexPath:(NSIndexPath *)indexPath { 87 | return [self cellClass]; 88 | } 89 | 90 | - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath withObject:(id)object {} 91 | 92 | #pragma mark - UITableViewDataSource 93 | 94 | - (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section { 95 | return 5; 96 | } 97 | 98 | - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath { 99 | 100 | NSString *cellIdentifier = nil; 101 | 102 | Class theCellClass = [self cellClassAtIndexPath:indexPath]; 103 | 104 | if ([theCellClass isSubclassOfClass:[FRCTableViewCell class]]) 105 | cellIdentifier = [theCellClass reuseIdentifier]; 106 | 107 | UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:cellIdentifier]; 108 | 109 | if (!cell && [theCellClass isSubclassOfClass:[FRCTableViewCell class]]) 110 | cell = [theCellClass cell]; 111 | 112 | if (!cell) 113 | cell = [[theCellClass alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 114 | 115 | id object = [self objectAtIndexPath:indexPath]; 116 | 117 | [self configureCell:cell atIndexPath:indexPath withObject:object]; 118 | 119 | if ([cell conformsToProtocol:@protocol(FRCTableViewCellObjectConfiguration)]) 120 | [(id)cell configureWithObject:object]; 121 | 122 | return cell; 123 | } 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /Images/FRCCollapsableSectionTableViewDataSourceDisclosureIndicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freerangecode/FRCTableViewDataSources/0bf00209486857a387e824d2846040d0567d33cd/Images/FRCCollapsableSectionTableViewDataSourceDisclosureIndicator.png -------------------------------------------------------------------------------- /Images/FRCCollapsableSectionTableViewDataSourceDisclosureIndicator@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freerangecode/FRCTableViewDataSources/0bf00209486857a387e824d2846040d0567d33cd/Images/FRCCollapsableSectionTableViewDataSourceDisclosureIndicator@2x.png -------------------------------------------------------------------------------- /Images/FRCCollapsableSectionTableViewDataSourceDisclosureIndicatorHighlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freerangecode/FRCTableViewDataSources/0bf00209486857a387e824d2846040d0567d33cd/Images/FRCCollapsableSectionTableViewDataSourceDisclosureIndicatorHighlighted.png -------------------------------------------------------------------------------- /Images/FRCCollapsableSectionTableViewDataSourceDisclosureIndicatorHighlighted@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freerangecode/FRCTableViewDataSources/0bf00209486857a387e824d2846040d0567d33cd/Images/FRCCollapsableSectionTableViewDataSourceDisclosureIndicatorHighlighted@2x.png -------------------------------------------------------------------------------- /Readme.textile: -------------------------------------------------------------------------------- 1 | h1. FRCTableViewDataSources 2 | 3 | FRCTableViewDataSources are a more structured way of making an object to use as a data source for a UITableView. 4 | 5 | h2. Features 6 | 7 | * Automatic handling of table view cells created from nibs or a storyboard 8 | * A fetched results data source that can be fed with a managed object context and fetch request to keep the table view in sync. 9 | * A splitter data source that can be used to join multiple data source objects together 10 | * Data source to represent one object, useful if you want to join a couple of different types of cell representing different objects 11 | * A collapsable data source which provides a header cell, which opens and collapses its children when tapped 12 | 13 | h2. iOS 5 and Automatic Reference Counting (ARC) 14 | 15 | This project uses ARC, but will work fine with iOS 4.3-style ARC. 16 | 17 | It will also work fine when compiled to use iOS 4.3 as the base SDK. When doing so, the new iOS 5 call (@registerNib:forCellReuseIdentifier:@ on UITableView) is not used. If you use the FRCTableViewDataSource implementation of @tableView:cellForRowAtIndexPath:@ in data source subclasses, it will yield no ill effect and still give you the nib-based table cell. 18 | 19 | h2. Example 20 | 21 | This will create a table view with a cell to use as a button to add a timestamp and list all the timestamps below it. This is shown in the MasterViewController in the project in the *demo* branch. 22 | 23 | bc.. splitDataSource = [[FRCSplitTableViewDataSource alloc] init]; 24 | splitDataSource.type = FRCSplitTableViewDataSourceTypeSection; 25 | 26 | addingDataSource = [[FRCObjectTableViewDataSource alloc] init]; 27 | addingDataSource.object = @"Add new timestamp"; 28 | [splitDataSource addChildTableViewDataSource:addingDataSource]; 29 | 30 | FRCFetchedResultsTableViewDataSource *fetchedResultsDS = [[FRCFetchedResultsTableViewDataSource alloc] init]; 31 | fetchedResultsDS.cellClass = [EventTableViewCell class]; 32 | fetchedResultsDS.managedObjectContext = self.managedObjectContext; 33 | fetchedResultsDS.fetchRequest = request; // Just some request 34 | [splitDataSource addChildTableViewDataSource:fetchedResultsDS]; 35 | 36 | self.tableView.dataSource = splitDataSource; 37 | 38 | h2. Branch Structure 39 | 40 | There are two branches to this repository, *master* and *demo*. 41 | 42 | h3. master 43 | 44 | The master branch contains the code and should be used if you want to add these extensions as a git submodule in other projects. It will only contain the class files themselves without the Xcode project or example classes. This is preferable as it will keep your directories clean of any code which is unnecessary to your working project. 45 | 46 | To add this project as a submodule you should run the following from inside your project's git repository: 47 | 48 | bc. git submodule add git://github.com/danielctull/FRCTableViewDataSources.git 49 | 50 | To keep up to date with the latest changes `cd` into the directory that contains this submodule and pull the newest changes as usual: 51 | 52 | bc. git pull origin 53 | 54 | h3. demo 55 | 56 | This contains an Xcode project that demonstrates the code and is the branch to use to see how to use the code. The demo branch contains a submodule reference to the master branch to bring in the library classes. 57 | 58 | To clone the demo branch, while also pulling in any necessary submodules run the following command: 59 | 60 | bc. git clone -b demo --recursive git://github.com/danielctull/FRCTableViewDataSources.git 61 | 62 | When changing to the demo branch you will need to run through the following set of commands: 63 | 64 | bc. git checkout demo 65 | git submodule init 66 | git submodule update 67 | 68 | After these you will see the example project and the library code will be in a sub-directory. 69 | 70 | h3. Artefacts 71 | 72 | Sometimes, there may be artefacts left over when switching from demo to master. These are files that are ignored by git and are easily cleaned up by running 73 | 74 | bc. git clean -dxf 75 | 76 | h2. License 77 | 78 | Copyright (C) 2011 Daniel Tull. All rights reserved. 79 | 80 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 81 | 82 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 83 | 84 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 85 | 86 | * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 87 | 88 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /UITableView+FRCTableViewDataSources.h: -------------------------------------------------------------------------------- 1 | /* 2 | UITableView+FRCTableViewDataSources.h 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 08.10.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import 38 | @class FRCTableViewDataSource; 39 | 40 | @interface UITableView (FRCTableViewDataSources) 41 | 42 | /** @name Logging */ 43 | 44 | /** Logs the hierarchy of the table view data sources. 45 | 46 | This is done by traversing the childTableViewDataSources of the parent 47 | data sources as it goes down. 48 | */ 49 | - (void)frc_logTableViewDataSources; 50 | 51 | /** @name Conversion methods */ 52 | 53 | 54 | /** Returns the section, with respect to the table view, of a section in 55 | the given child data source's structure. This uses the conversion 56 | methods of the FRCTableViewDataSources. 57 | 58 | @param section The section in the given data source's co-ordinate space. 59 | @param dataSource The data source to convert the section from. 60 | 61 | @return The section in the table view's co-ordinate space. 62 | */ 63 | - (NSInteger)frc_convertSection:(NSInteger)section fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource; 64 | 65 | /** Returns the indexPath, with respect to the table view, of an index path 66 | in the given child data source's structure. This uses the conversion methods 67 | of the FRCTableViewDataSources. 68 | 69 | @param indexPath The index path in the given data source's co-ordinate space. 70 | @param dataSource The data source to convert the index path from. 71 | 72 | @return The index path in the table view's co-ordinate space. 73 | */ 74 | - (NSIndexPath *)frc_convertIndexPath:(NSIndexPath *)indexPath fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource; 75 | 76 | /** @name Cell registration */ 77 | 78 | /** Uses the iOS 5 method to register a table view cell class with a nib. 79 | This will only work for FRCTableViewCell subclasses, but won't crash for 80 | others. If iOS 5 is not available, this method does nothing. 81 | 82 | @param tableViewCellSubclass The FRCTableViewCell subclass of the cell to register. 83 | */ 84 | - (void)frc_registerFRCTableViewCellSubclass:(Class)tableViewCellSubclass; 85 | 86 | @end -------------------------------------------------------------------------------- /UITableView+FRCTableViewDataSources.m: -------------------------------------------------------------------------------- 1 | /* 2 | UITableView+FRCTableViewDataSources.m 3 | FRCTableViewDataSources 4 | 5 | Created by Daniel Tull on 08.10.2011. 6 | 7 | 8 | 9 | Copyright (c) 2011 Daniel Tull. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of its contributors may be used 22 | to endorse or promote products derived from this software without specific 23 | prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #import "UITableView+FRCTableViewDataSources.h" 38 | #import "FRCTableViewCell.h" 39 | #import "FRCParentTableViewDataSource.h" 40 | #import "FRCTableViewDataSource.h" 41 | 42 | 43 | @interface FRCTableViewDataSource (FRCTableViewDataSources) 44 | - (void)frc_logTableViewDataSourcesLevel:(NSInteger)level; 45 | @end 46 | @implementation FRCTableViewDataSource (FRCTableViewDataSources) 47 | 48 | - (void)frc_logTableViewDataSourcesLevel:(NSInteger)level { 49 | 50 | NSMutableString *string = [[NSMutableString alloc] init]; 51 | 52 | for (NSInteger i = 0; i < level; i++) 53 | [string appendString:@" "]; 54 | 55 | NSLog(@"%@%@", string, self); 56 | 57 | if ([self isKindOfClass:[FRCParentTableViewDataSource class]]) { 58 | for (id object in [(FRCParentTableViewDataSource *)self childTableViewDataSources]) 59 | [object frc_logTableViewDataSourcesLevel:level+1]; 60 | } 61 | } 62 | 63 | @end 64 | 65 | @implementation UITableView (FRCTableViewDataSources) 66 | 67 | - (void)frc_logTableViewDataSources { 68 | 69 | id ds = self.dataSource; 70 | if (![ds isKindOfClass:[FRCTableViewDataSource class]]) return; 71 | 72 | FRCTableViewDataSource *dataSource = (FRCTableViewDataSource *)ds; 73 | 74 | NSLog(@"-------------"); 75 | NSLog(@"Logging data sources for %@", self); 76 | NSLog(@"-------------"); 77 | [dataSource frc_logTableViewDataSourcesLevel:0]; 78 | NSLog(@"-------------"); 79 | } 80 | 81 | - (NSInteger)frc_convertSection:(NSInteger)section fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 82 | 83 | FRCParentTableViewDataSource *parent = dataSource.parent; 84 | 85 | while (parent) { 86 | section = [parent convertSection:section fromChildTableViewDataSource:dataSource]; 87 | dataSource = parent; 88 | parent = dataSource.parent; 89 | } 90 | 91 | NSAssert(parent == nil, @"Parent should equal nil at this point"); 92 | NSAssert(dataSource == self.dataSource, @"dataSource should now be the tableview's dataSource"); 93 | 94 | return section; 95 | } 96 | 97 | - (NSIndexPath *)frc_convertIndexPath:(NSIndexPath *)indexPath fromChildTableViewDataSource:(FRCTableViewDataSource *)dataSource { 98 | 99 | FRCParentTableViewDataSource *parent = dataSource.parent; 100 | 101 | while (parent) { 102 | indexPath = [parent convertIndexPath:indexPath fromChildTableViewDataSource:dataSource]; 103 | dataSource = parent; 104 | parent = dataSource.parent; 105 | } 106 | 107 | NSAssert(parent == nil, @"Parent should equal nil at this point"); 108 | NSAssert(dataSource == self.dataSource, @"dataSource should now be the tableview's dataSource"); 109 | 110 | return indexPath; 111 | } 112 | 113 | - (void)frc_registerFRCTableViewCellSubclass:(Class)tableViewCellClass { 114 | 115 | // Bail if the method doesn't exist; We're on iOS 4.3 116 | if (![self respondsToSelector:@selector(registerNib:forCellReuseIdentifier:)]) 117 | return; 118 | 119 | if (![tableViewCellClass isSubclassOfClass:[FRCTableViewCell class]]) return; 120 | 121 | NSString *nibName = [tableViewCellClass nibName]; 122 | 123 | if (nibName == nil || [nibName length] < 1) return; 124 | 125 | UINib *nib = [UINib nibWithNibName:nibName bundle:nil]; 126 | NSString *reuseIdentifier = [tableViewCellClass reuseIdentifier]; 127 | 128 | [self registerNib:nib forCellReuseIdentifier:reuseIdentifier]; 129 | } 130 | 131 | @end 132 | --------------------------------------------------------------------------------