forked from soffes/ssdatakit
/
SSManagedObject.m
292 lines (209 loc) · 8.34 KB
/
SSManagedObject.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
//
// SSManagedObject.m
// SSDataKit
//
// Created by Sam Soffes on 10/23/11.
// Copyright (c) 2011 Sam Soffes. All rights reserved.
//
#import "SSManagedObject.h"
static NSManagedObjectContext *__managedObjectContext = nil;
static NSManagedObjectModel *__managedObjectModel = nil;
static NSURL *__persistentStoreURL = nil;
static NSDictionary *__persistentStoreOptions = nil;
static BOOL __automaticallyResetsPersistentStore = NO;
static NSString *const kURIRepresentationKey = @"URIRepresentation";
@implementation SSManagedObject
#pragma mark - Managing Main Context
+ (NSManagedObjectContext *)mainContext {
if (!__managedObjectContext) {
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
__managedObjectContext.persistentStoreCoordinator = [self persistentStoreCoordinator];
}
return __managedObjectContext;
}
+ (BOOL)hasMainContext {
return __managedObjectContext != nil;
}
+ (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
static NSPersistentStoreCoordinator *persistentStoreCoordinator = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSManagedObjectModel *model = [self managedObjectModel];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSURL *url = [self persistentStoreURL];
NSError *error = nil;
NSDictionary *storeOptions = [self persistentStoreOptions];
[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:storeOptions error:&error];
if (error) {
// Reset the persistent store
if (__automaticallyResetsPersistentStore && error.code == 134130) {
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:storeOptions error:&error];
} else {
NSLog(@"[SSDataKit] Failed to add persistent store: %@ %@", error, error.userInfo);
}
}
});
return persistentStoreCoordinator;
}
+ (NSDictionary *)persistentStoreOptions {
if (!__persistentStoreOptions) {
[self setPersistentStoreOptions:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil]];
}
return __persistentStoreOptions;
}
+ (void)setPersistentStoreOptions:(NSDictionary *)options {
__persistentStoreOptions = options;
}
+ (NSManagedObjectModel *)managedObjectModel {
if (!__managedObjectModel) {
// Default model
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
// Ensure a model is loaded
if (!model) {
[[NSException exceptionWithName:@"SSManagedObjectMissingModel" reason:@"You need to provide a managed model." userInfo:nil] raise];
return nil;
}
[self setManagedObjectModel:model];
}
return __managedObjectModel;
}
+ (void)setManagedObjectModel:(NSManagedObjectModel *)model {
__managedObjectModel = model;
}
+ (NSURL *)persistentStoreURL {
if (!__persistentStoreURL) {
NSDictionary *applicationInfo = [[NSBundle mainBundle] infoDictionary];
#if TARGET_OS_IPHONE
NSString *applicationName = [applicationInfo objectForKey:@"CFBundleDisplayName"];
NSURL *documentsURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *url = [documentsURL URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite", applicationName]];
#else
NSString *applicationName = [applicationInfo objectForKey:@"CFBundleName"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *applicationSupportURL = [[fileManager URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject];
applicationSupportURL = [applicationSupportURL URLByAppendingPathComponent:applicationName];
NSDictionary *properties = [applicationSupportURL resourceValuesForKeys:[NSArray arrayWithObject:NSURLIsDirectoryKey] error:nil];
if (!properties) {
[fileManager createDirectoryAtPath:[applicationSupportURL path] withIntermediateDirectories:YES attributes:nil error:nil];
}
NSURL *url = [applicationSupportURL URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite", applicationName]];
#endif
[self setPersistentStoreURL:url];
}
return __persistentStoreURL;
}
+ (void)setPersistentStoreURL:(NSURL *)url {
__persistentStoreURL = url;
}
#pragma mark - Resetting the Presistent Store
+ (void)resetPersistentStore {
__managedObjectContext = nil;
NSURL *url = [self persistentStoreURL];
NSPersistentStoreCoordinator *psc = [SSManagedObject persistentStoreCoordinator];
if ([psc removePersistentStore:psc.persistentStores.lastObject error:nil]) {
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:[SSManagedObject persistentStoreOptions] error:nil];
}
}
+ (void)setAutomaticallyResetsPersistentStore:(BOOL)automaticallyReset {
__automaticallyResetsPersistentStore = automaticallyReset;
}
+ (BOOL)automaticallyResetsPersistentStore {
return __automaticallyResetsPersistentStore;
}
#pragma mark - Getting Entity Information
+ (NSString *)entityName {
return NSStringFromClass(self);
}
+ (NSEntityDescription *)entity {
return [self entityWithContext:nil];
}
+ (NSEntityDescription *)entityWithContext:(NSManagedObjectContext *)context {
if (!context) {
context = [self mainContext];
}
return [NSEntityDescription entityForName:[self entityName] inManagedObjectContext:context];
}
+ (NSArray *)defaultSortDescriptors {
// Subclasses should override this
return nil;
}
#pragma mark - NSObject
- (id)init {
return [self initWithContext:nil];
}
#pragma mark - Initializing
- (id)initWithContext:(NSManagedObjectContext *)context {
if (!context) {
context = [[self class] mainContext];
}
NSEntityDescription *entity = [[self class] entityWithContext:context];
return (self = [self initWithEntity:entity insertIntoManagedObjectContext:context]);
}
#pragma mark - Reflection
- (NSArray *)attributeKeys {
return [[[[self class] entityWithContext:[self managedObjectContext]] attributesByName] allKeys];
}
- (NSArray *)persistedAttributeKeys {
NSDictionary *attributes = [[[self class] entityWithContext:[self managedObjectContext]] attributesByName];
NSMutableArray *keys = [[NSMutableArray alloc] init];
for (NSString *key in attributes) {
if ([[attributes objectForKey:key] isTransient] == NO) {
[keys addObject:key];
}
}
return keys;
}
- (NSArray *)transientAttributeKeys {
NSDictionary *attributes = [[[self class] entityWithContext:[self managedObjectContext]] attributesByName];
NSMutableArray *keys = [[NSMutableArray alloc] init];
for (NSString *key in attributes) {
if ([[attributes objectForKey:key] isTransient] == YES) {
[keys addObject:key];
}
}
return keys;
}
- (NSArray *)relationshipKeys {
return [[[[self class] entityWithContext:[self managedObjectContext]] relationshipsByName] allKeys];
}
- (NSRelationshipDescription *)relationshipForKeyPath:(NSString *)keyPath {
// Find releationship
NSArray *keys = [keyPath componentsSeparatedByString:@"."];
// We need keys to find the relationship
if ([keys count] == 0) {
return nil;
}
NSEntityDescription *rootEntity = [[self class] entityWithContext:[self managedObjectContext]];
NSRelationshipDescription *relationship = nil;
// Loop through keys and find the relationship
for (NSString *key in keys) {
if (relationship) {
rootEntity = [relationship destinationEntity];
}
relationship = [[rootEntity relationshipsByName] objectForKey:key];
}
return relationship;
}
#pragma mark - Manipulation
- (void)save {
[self.managedObjectContext save:nil];
}
- (void)delete {
[self.managedObjectContext deleteObject:self];
}
#pragma mark - NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
NSManagedObjectContext *context = [[self class] mainContext];
NSPersistentStoreCoordinator *psc = [[self class] persistentStoreCoordinator];
self = (SSManagedObject *)[context objectWithID:[psc managedObjectIDForURIRepresentation:(NSURL *)[decoder decodeObjectForKey:kURIRepresentationKey]]];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:[[self objectID] URIRepresentation] forKey:kURIRepresentationKey];
}
@end