1
1
#import " ContextManager.h"
2
+ #import " LegacyContextFactory.h"
2
3
#import " WordPress-Swift.h"
3
4
@import WordPressShared.WPAnalytics;
4
5
@import Foundation;
@@ -18,13 +19,11 @@ @interface ContextManager ()
18
19
19
20
@property (nonatomic , strong ) NSPersistentStoreDescription *storeDescription;
20
21
@property (nonatomic , strong ) NSPersistentContainer *persistentContainer;
21
- @property (nonatomic , strong ) NSPersistentStoreCoordinator *persistentStoreCoordinator;
22
22
@property (nonatomic , strong ) NSManagedObjectModel *managedObjectModel;
23
- @property (nonatomic , strong ) NSManagedObjectContext *mainContext;
24
- @property (nonatomic , strong ) NSManagedObjectContext *writerContext;
25
23
@property (nonatomic , assign ) BOOL migrationFailed;
26
24
@property (nonatomic , strong ) NSString *modelName;
27
25
@property (nonatomic , strong ) NSURL *storeURL;
26
+ @property (nonatomic , strong ) id <ManagedObjectContextFactory> contextFactory;
28
27
29
28
@end
30
29
@@ -43,25 +42,27 @@ - (instancetype)init
43
42
storeURL = [self localDatabasePath ];
44
43
}
45
44
46
- return [self initWithModelName: ContextManagerModelNameCurrent storeURL: storeURL];
45
+ return [self initWithModelName: ContextManagerModelNameCurrent storeURL: storeURL contextFactory: nil ];
47
46
}
48
47
49
- - (instancetype )initWithModelName : (NSString *)modelName storeURL : (NSURL *)storeURL
48
+ - (instancetype )initWithModelName : (NSString *)modelName storeURL : (NSURL *)storeURL contextFactory : ( Class ) factory
50
49
{
51
50
self = [super init ];
52
51
if (self) {
52
+ if (factory == nil ) {
53
+ factory = [ContainerContextFactory class ];
54
+ }
55
+
53
56
NSParameterAssert ([modelName isEqualToString: ContextManagerModelNameCurrent] || [modelName hasPrefix: @" WordPress " ]);
54
57
NSParameterAssert ([storeURL isFileURL ]);
58
+ NSParameterAssert ([factory conformsToProtocol: @protocol (ManagedObjectContextFactory)]);
55
59
56
60
self.modelName = modelName;
57
61
self.storeURL = storeURL;
58
62
59
63
[NSValueTransformer registerCustomTransformers ];
60
- // Create `mainContext` and `writerContext` during initialisation to
61
- // ensure they are only created once.
62
- [self createWriterContext ];
63
- [self createMainContext ];
64
- [self startListeningToMainContextNotifications ];
64
+ self.contextFactory = (id <ManagedObjectContextFactory>)[[factory alloc ] initWithPersistentContainer: self .persistentContainer];
65
+ [[[NullBlogPropertySanitizer alloc ] initWithContext: self .contextFactory.mainContext] sanitize ];
65
66
}
66
67
67
68
return self;
@@ -84,118 +85,31 @@ + (NSURL *)inMemoryStoreURL
84
85
85
86
#pragma mark - Contexts
86
87
87
- - (NSManagedObjectContext *const )newDerivedContext
88
- {
89
- return [self newChildContextWithConcurrencyType: NSPrivateQueueConcurrencyType];
90
- }
91
-
92
- - (void )createWriterContext
88
+ - (NSManagedObjectContext *)mainContext
93
89
{
94
- NSAssert (self.writerContext == nil , @" %s should only be called once" , __PRETTY_FUNCTION__);
95
-
96
- NSManagedObjectContext *context = [[NSManagedObjectContext alloc ] initWithConcurrencyType: NSPrivateQueueConcurrencyType];
97
- context.persistentStoreCoordinator = self.persistentStoreCoordinator ;
98
- self.writerContext = context;
90
+ return self.contextFactory .mainContext ;
99
91
}
100
92
101
- - (void )createMainContext
102
- {
103
- NSAssert (self.mainContext == nil , @" %s should only be called once" , __PRETTY_FUNCTION__);
104
-
105
- NSManagedObjectContext *context = [[NSManagedObjectContext alloc ] initWithConcurrencyType: NSMainQueueConcurrencyType];
106
- context.parentContext = self.writerContext ;
107
- self.mainContext = context;
108
- [[[NullBlogPropertySanitizer alloc ] initWithContext: context] sanitize ];
109
- }
110
-
111
- - (NSManagedObjectContext *const )newChildContextWithConcurrencyType : (NSManagedObjectContextConcurrencyType )concurrencyType
93
+ - (NSManagedObjectContext *const )newDerivedContext
112
94
{
113
- NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc ]
114
- initWithConcurrencyType: concurrencyType];
115
- childContext.parentContext = self.mainContext ;
116
- childContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy ;
117
-
118
- return childContext;
95
+ return [self .contextFactory newDerivedContext ];
119
96
}
120
97
121
-
122
98
#pragma mark - Context Saving and Merging
123
99
124
100
- (void )saveContextAndWait : (NSManagedObjectContext *)context
125
101
{
126
- [self saveContext: context andWait: YES withCompletionBlock: nil ];
102
+ [self .contextFactory saveContext: context andWait: YES withCompletionBlock: nil ];
127
103
}
128
104
129
105
- (void )saveContext : (NSManagedObjectContext *)context
130
106
{
131
- [self saveContext: context andWait: NO withCompletionBlock: nil ];
107
+ [self .contextFactory saveContext: context andWait: NO withCompletionBlock: nil ];
132
108
}
133
109
134
110
- (void )saveContext : (NSManagedObjectContext *)context withCompletionBlock : (void (^)(void ))completionBlock
135
111
{
136
- [self saveContext: context andWait: NO withCompletionBlock: completionBlock];
137
- }
138
-
139
-
140
- - (void )saveContext : (NSManagedObjectContext *)context andWait : (BOOL )wait withCompletionBlock : (void (^)(void ))completionBlock
141
- {
142
- // Save derived contexts a little differently
143
- if (context.parentContext == self.mainContext ) {
144
- [self saveDerivedContext: context andWait: wait withCompletionBlock: completionBlock];
145
- return ;
146
- }
147
-
148
- if (wait) {
149
- [context performBlockAndWait: ^{
150
- [self internalSaveContext: context withCompletionBlock: completionBlock];
151
- }];
152
- } else {
153
- [context performBlock: ^{
154
- [self internalSaveContext: context withCompletionBlock: completionBlock];
155
- }];
156
- }
157
- }
158
-
159
- - (void )saveDerivedContext : (NSManagedObjectContext *)context andWait : (BOOL )wait withCompletionBlock : (void (^)(void ))completionBlock
160
- {
161
- if (wait) {
162
- [context performBlockAndWait: ^{
163
- [self internalSaveContext: context];
164
- [self saveContext: self .mainContext andWait: wait withCompletionBlock: completionBlock];
165
- }];
166
- } else {
167
- [context performBlock: ^{
168
- [self internalSaveContext: context];
169
- [self saveContext: self .mainContext andWait: wait withCompletionBlock: completionBlock];
170
- }];
171
- }
172
- }
173
-
174
- - (void )internalSaveContext : (NSManagedObjectContext *)context withCompletionBlock : (void (^)(void ))completionBlock
175
- {
176
- [self internalSaveContext: context];
177
-
178
- if (completionBlock) {
179
- dispatch_async (dispatch_get_main_queue (), completionBlock);
180
- }
181
- }
182
-
183
- - (void )mergeChanges : (NSManagedObjectContext *)context fromContextDidSaveNotification : (NSNotification *)notification
184
- {
185
- [context performBlock: ^{
186
- // Fault-in updated objects before a merge to avoid any internal inconsistency errors later.
187
- // Based on old solution referenced here: http://www.mlsite.net/blog/?p=518
188
- NSSet * updates = [notification.userInfo objectForKey: NSUpdatedObjectsKey ];
189
- for (NSManagedObject *object in updates) {
190
- NSManagedObject *objectInContext = [context existingObjectWithID: object.objectID error: nil ];
191
- if ([objectInContext isFault ]) {
192
- // Force a fault-in of the object's key-values
193
- [objectInContext willAccessValueForKey: nil ];
194
- }
195
- }
196
- // Continue with the merge
197
- [context mergeChangesFromContextDidSaveNotification: notification];
198
- }];
112
+ [self .contextFactory saveContext: context andWait: NO withCompletionBlock: completionBlock];
199
113
}
200
114
201
115
- (void )performAndSaveUsingBlock : (void (^)(NSManagedObjectContext *context))aBlock
@@ -214,7 +128,7 @@ - (void)performAndSaveUsingBlock:(void (^)(NSManagedObjectContext *context))aBlo
214
128
[context performBlock: ^{
215
129
aBlock (context);
216
130
217
- [self saveContext: context andWait: NO withCompletionBlock: completion];
131
+ [self .contextFactory saveContext: context andWait: NO withCompletionBlock: completion];
218
132
}];
219
133
}
220
134
@@ -297,46 +211,9 @@ - (NSManagedObjectModel *)managedObjectModel
297
211
return _managedObjectModel;
298
212
}
299
213
300
- - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
301
- {
302
- return self.persistentContainer .persistentStoreCoordinator ;
303
- }
304
-
305
-
306
- #pragma mark - Notification Helpers
307
-
308
- - (void )startListeningToMainContextNotifications
309
- {
310
- NSNotificationCenter *nc = [NSNotificationCenter defaultCenter ];
311
- [nc addObserver: self selector: @selector (mainContextDidSave: ) name: NSManagedObjectContextDidSaveNotification object: self .mainContext];
312
- }
313
-
314
- - (void )mainContextDidSave : (NSNotification *)notification
315
- {
316
- // Defer I/O to a BG Writer Context. Simperium 4ever!
317
- //
318
- [self .writerContext performBlock: ^{
319
- [self internalSaveContext: self .writerContext];
320
- }];
321
- }
322
-
323
214
324
215
#pragma mark - Private Helpers
325
216
326
- - (void )internalSaveContext : (NSManagedObjectContext *)context
327
- {
328
- NSParameterAssert (context);
329
-
330
- NSError *error;
331
- if (![context obtainPermanentIDsForObjects: context.insertedObjects.allObjects error: &error]) {
332
- DDLogError (@" Error obtaining permanent object IDs for %@ , %@ " , context.insertedObjects .allObjects , error);
333
- }
334
-
335
- if ([context hasChanges ] && ![context save: &error]) {
336
- [self handleSaveError: error inContext: context];
337
- }
338
- }
339
-
340
217
- (void )migrateDataModelsIfNecessary : (SentryStartupEvent *)sentryEvent
341
218
{
342
219
if (![[NSFileManager defaultManager ] fileExistsAtPath: [[self storeURL ] path ]]) {
0 commit comments