Skip to content

Commit cc28d96

Browse files
author
Florian Kugler
committed
Initial commit
0 parents  commit cc28d96

30 files changed

+1701
-0
lines changed

Item.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// Item.h
3+
// NestedTodoList
4+
//
5+
// Created by Chris Eidhof on 8/14/13.
6+
// Copyright (c) 2013 Chris Eidhof. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
#import <CoreData/CoreData.h>
11+
12+
@class Item;
13+
14+
@interface Item : NSManagedObject
15+
16+
@property (nonatomic, retain) NSString* title;
17+
@property (nonatomic, assign) NSNumber* order;
18+
@property (nonatomic, retain) Item* parent;
19+
@property (nonatomic, retain) NSSet* children;
20+
21+
+ (instancetype)insertItemWithTitle:(NSString*)title
22+
parent:(Item*)parent
23+
inManagedObjectContext:(NSManagedObjectContext*)managedObjectContext;
24+
25+
- (NSFetchedResultsController*)childrenFetchedResultsController;
26+
27+
@end

Item.m

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//
2+
// Item.m
3+
// NestedTodoList
4+
//
5+
// Created by Chris Eidhof on 8/14/13.
6+
// Copyright (c) 2013 Chris Eidhof. All rights reserved.
7+
//
8+
9+
#import "Item.h"
10+
#import "Item.h"
11+
12+
13+
@implementation Item
14+
15+
@dynamic title;
16+
@dynamic parent;
17+
@dynamic children;
18+
@dynamic order;
19+
20+
+ (instancetype)insertItemWithTitle:(NSString*)title
21+
parent:(Item*)parent
22+
inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
23+
{
24+
NSUInteger order = parent.numberOfChildren;
25+
Item* item = [NSEntityDescription insertNewObjectForEntityForName:self.entityName
26+
inManagedObjectContext:managedObjectContext];
27+
item.title = title;
28+
item.parent = parent;
29+
item.order = @(order);
30+
return item;
31+
}
32+
33+
+ (NSString*)entityName
34+
{
35+
return @"Item";
36+
}
37+
38+
- (NSUInteger)numberOfChildren
39+
{
40+
return self.children.count;
41+
}
42+
43+
- (NSFetchedResultsController*)childrenFetchedResultsController
44+
{
45+
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:[self.class entityName]];
46+
request.predicate = [NSPredicate predicateWithFormat:@"parent = %@", self];
47+
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"order" ascending:YES]];
48+
return [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
49+
}
50+
51+
- (void)prepareForDeletion
52+
{
53+
if (self.parent.isDeleted) return;
54+
55+
NSSet* siblings = self.parent.children;
56+
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"order > %@", self.order];
57+
NSSet* itemsAfterSelf = [siblings filteredSetUsingPredicate:predicate];
58+
[itemsAfterSelf enumerateObjectsUsingBlock:^(Item* sibling, BOOL* stop)
59+
{
60+
sibling.order = @(sibling.order.integerValue - 1);
61+
}];
62+
}
63+
64+
@end

NestedTodoList.xcodeproj/project.pbxproj

Lines changed: 557 additions & 0 deletions
Large diffs are not rendered by default.

NestedTodoList/AppDelegate.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// AppDelegate.h
3+
// NestedTodoList
4+
//
5+
// Created by Chris Eidhof on 8/13/13.
6+
// Copyright (c) 2013 Chris Eidhof. All rights reserved.
7+
//
8+
9+
#import <UIKit/UIKit.h>
10+
11+
@class Store;
12+
@class PersistentStack;
13+
14+
@interface AppDelegate : UIResponder <UIApplicationDelegate>
15+
16+
@property (strong, nonatomic) UIWindow *window;
17+
18+
@end

NestedTodoList/AppDelegate.m

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//
2+
// AppDelegate.m
3+
// NestedTodoList
4+
//
5+
// Created by Chris Eidhof on 8/13/13.
6+
// Copyright (c) 2013 Chris Eidhof. All rights reserved.
7+
//
8+
9+
#import "AppDelegate.h"
10+
#import "ItemViewController.h"
11+
#import "Store.h"
12+
#import "PersistentStack.h"
13+
14+
@interface AppDelegate ()
15+
16+
@property (nonatomic, strong) Store* store;
17+
@property (nonatomic, strong) PersistentStack* persistentStack;
18+
@end
19+
20+
@implementation AppDelegate
21+
22+
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
23+
{
24+
UINavigationController* navigationController = (UINavigationController*) self.window.rootViewController;
25+
ItemViewController* rootViewController = (ItemViewController*)navigationController.topViewController;
26+
NSAssert([rootViewController isKindOfClass:[ItemViewController class]], @"Should have an item view controller");
27+
self.persistentStack = [[PersistentStack alloc] initWithStoreURL:self.storeURL modelURL:self.modelURL];
28+
self.store = [[Store alloc] init];
29+
self.store.managedObjectContext = self.persistentStack.managedObjectContext;
30+
rootViewController.parent = self.store.rootItem;
31+
application.applicationSupportsShakeToEdit = YES;
32+
return YES;
33+
}
34+
35+
- (NSURL*)storeURL
36+
{
37+
NSURL* documentsDirectory = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
38+
return [documentsDirectory URLByAppendingPathComponent:@"db.sqlite"];
39+
}
40+
41+
- (NSURL*)modelURL
42+
{
43+
return [[NSBundle mainBundle] URLForResource:@"NestedTodoList" withExtension:@"momd"];
44+
}
45+
46+
- (void)applicationDidEnterBackground:(UIApplication *)application
47+
{
48+
[self.store.managedObjectContext save:NULL];
49+
}
50+
51+
52+
@end

NestedTodoList/[email protected]

18.2 KB
Loading

NestedTodoList/Default.png

6.39 KB
Loading

NestedTodoList/[email protected]

15.7 KB
Loading
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// Created by Chris Eidhof
3+
//
4+
5+
6+
#import <Foundation/Foundation.h>
7+
#import <CoreData/CoreData.h>
8+
9+
@class NSFetchedResultsController;
10+
11+
@protocol FetchedResultsControllerDataSourceDelegate
12+
13+
- (void)configureCell:(id)cell withObject:(id)object;
14+
- (void)deleteObject:(id)object;
15+
16+
@end
17+
18+
19+
20+
@interface FetchedResultsControllerDataSource : NSObject <UITableViewDataSource, NSFetchedResultsControllerDelegate>
21+
22+
@property (nonatomic, strong) NSFetchedResultsController* fetchedResultsController;
23+
@property (nonatomic, weak) id<FetchedResultsControllerDataSourceDelegate> delegate;
24+
@property (nonatomic, copy) NSString* reuseIdentifier;
25+
@property (nonatomic) BOOL paused;
26+
27+
- (id)initWithTableView:(UITableView*)tableView;
28+
- (id)selectedItem;
29+
30+
@end
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//
2+
// Created by Chris Eidhof
3+
//
4+
5+
6+
#import <CoreData/CoreData.h>
7+
#import "FetchedResultsControllerDataSource.h"
8+
9+
10+
@interface FetchedResultsControllerDataSource ()
11+
12+
@property (nonatomic, strong) UITableView* tableView;
13+
14+
@end
15+
16+
@implementation FetchedResultsControllerDataSource
17+
18+
- (id)initWithTableView:(UITableView*)tableView
19+
{
20+
self = [super init];
21+
if (self) {
22+
self.tableView = tableView;
23+
self.tableView.dataSource = self;
24+
}
25+
return self;
26+
}
27+
28+
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
29+
{
30+
return self.fetchedResultsController.sections.count;
31+
}
32+
33+
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)sectionIndex
34+
{
35+
id<NSFetchedResultsSectionInfo> section = self.fetchedResultsController.sections[sectionIndex];
36+
return section.numberOfObjects;
37+
}
38+
39+
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
40+
{
41+
id object = [self.fetchedResultsController objectAtIndexPath:indexPath];
42+
id cell = [tableView dequeueReusableCellWithIdentifier:self.reuseIdentifier forIndexPath:indexPath];
43+
[self.delegate configureCell:cell withObject:object];
44+
return cell;
45+
}
46+
47+
- (BOOL)tableView:(UITableView*)tableView canEditRowAtIndexPath:(NSIndexPath*)indexPath
48+
{
49+
return YES;
50+
}
51+
52+
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
53+
if (editingStyle == UITableViewCellEditingStyleDelete) {
54+
[self.delegate deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
55+
}
56+
}
57+
58+
#pragma mark NSFetchedResultsControllerDelegate
59+
60+
- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller
61+
{
62+
[self.tableView beginUpdates];
63+
}
64+
65+
- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller
66+
{
67+
[self.tableView endUpdates];
68+
}
69+
70+
- (void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath
71+
{
72+
if (type == NSFetchedResultsChangeInsert) {
73+
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
74+
} else if (type == NSFetchedResultsChangeMove) {
75+
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
76+
} else if (type == NSFetchedResultsChangeDelete) {
77+
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
78+
} else {
79+
NSAssert(NO,@"");
80+
}
81+
}
82+
83+
- (void)setFetchedResultsController:(NSFetchedResultsController*)fetchedResultsController
84+
{
85+
NSAssert(_fetchedResultsController == nil, @"TODO: you can currently only assign this property once");
86+
_fetchedResultsController = fetchedResultsController;
87+
fetchedResultsController.delegate = self;
88+
[fetchedResultsController performFetch:NULL];
89+
}
90+
91+
92+
- (id)selectedItem
93+
{
94+
NSIndexPath* path = self.tableView.indexPathForSelectedRow;
95+
return path ? [self.fetchedResultsController objectAtIndexPath:path] : nil;
96+
}
97+
98+
99+
- (void)setPaused:(BOOL)paused
100+
{
101+
_paused = paused;
102+
if (paused) {
103+
self.fetchedResultsController.delegate = nil;
104+
} else {
105+
self.fetchedResultsController.delegate = self;
106+
[self.fetchedResultsController performFetch:NULL];
107+
[self.tableView reloadData];
108+
}
109+
}
110+
111+
112+
@end

NestedTodoList/ItemViewController.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// Created by Chris Eidhof
3+
//
4+
5+
6+
#import <Foundation/Foundation.h>
7+
8+
@class FetchedResultsControllerDataSource;
9+
@class Store;
10+
@class Item;
11+
12+
13+
@interface ItemViewController : UITableViewController
14+
15+
@property (nonatomic, strong) Item* parent;
16+
17+
@end

0 commit comments

Comments
 (0)