Skip to content

Commit cfc18bc

Browse files
author
Giorgio Ruscigno
committed
Merge branch 'trunk' of https://github.com/wordpress-mobile/WordPress-iOS into task/jetpack-landing-screen-animation
2 parents 5afa068 + 438ae13 commit cfc18bc

File tree

85 files changed

+1614
-1361
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1614
-1361
lines changed

.buildkite/release-builds.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ common_params:
1414

1515
steps:
1616

17-
- label: ":wordpress::testflight: WordPress Release Build (App Store Connect)"
17+
- label: ":wordpress: :testflight: WordPress Release Build (App Store Connect)"
1818
command: ".buildkite/commands/release-build-wordpress.sh $BETA_RELEASE"
1919
env: *common_env
2020
plugins: *common_plugins
2121
notify:
2222
- slack: "#build-and-ship"
2323

2424
# There is no App Center emojiy
25-
- label: ":wordpress::hockeyapp: WordPress Release Build (App Center)"
25+
- label: ":wordpress: :appcenter: WordPress Release Build (App Center)"
2626
command: ".buildkite/commands/release-build-wordpress-internal.sh"
2727
env: *common_env
2828
plugins: *common_plugins
2929
notify:
3030
- slack: "#build-and-ship"
3131

32-
- label: ":jetpack::testflight: Jetpack Release Build (App Store Connect)"
32+
- label: ":jetpack: :testflight: Jetpack Release Build (App Store Connect)"
3333
command: ".buildkite/commands/release-build-jetpack.sh"
3434
env: *common_env
3535
plugins: *common_plugins

Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ abstract_target 'Apps' do
175175
## Gutenberg (React Native)
176176
## =====================
177177
##
178-
gutenberg tag: 'v1.81.0'
178+
gutenberg tag: 'v1.81.1'
179179

180180
## Third party libraries
181181
## =====================

Podfile.lock

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

WordPress/Classes/System/WordPress-Bridging-Header.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#import "EditCommentViewController.h"
2929

30+
#import "LegacyContextFactory.h"
3031
#import "LocalCoreDataService.h"
3132

3233
#import "Media.h"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import ObjectiveC
2+
3+
@objc
4+
class ContainerContextFactory: NSObject, ManagedObjectContextFactory {
5+
6+
private let container: NSPersistentContainer
7+
8+
let mainContext: NSManagedObjectContext
9+
10+
required init(persistentContainer container: NSPersistentContainer) {
11+
self.container = container
12+
self.mainContext = container.viewContext
13+
self.mainContext.automaticallyMergesChangesFromParent = true
14+
self.mainContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
15+
}
16+
17+
func newDerivedContext() -> NSManagedObjectContext {
18+
let context = container.newBackgroundContext()
19+
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
20+
return context
21+
}
22+
23+
func save(_ context: NSManagedObjectContext, andWait wait: Bool, withCompletionBlock completionBlock: (() -> Void)?) {
24+
let block: () -> Void = {
25+
self.internalSave(context)
26+
DispatchQueue.main.async {
27+
completionBlock?()
28+
}
29+
}
30+
if wait {
31+
context.performAndWait(block)
32+
} else {
33+
context.perform(block)
34+
}
35+
}
36+
37+
}

WordPress/Classes/Utility/ContextManager+ErrorHandling.swift

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,40 @@ private extension NSExceptionName {
5555
static let coreDataSaveDerivedException = NSExceptionName("Unresolved Core Data save error (Derived Context)")
5656
}
5757

58-
extension ContextManager {
59-
@objc(handleSaveError:inContext:)
58+
extension LegacyContextFactory {
59+
60+
/// A wrapper of `internalSave(_:)` to expose it as an Objective-C API for `LegacyContextFactory` to call.
61+
@objc func internalSaveContext(_ context: NSManagedObjectContext) {
62+
internalSave(context)
63+
}
64+
65+
}
66+
67+
extension ManagedObjectContextFactory {
68+
69+
func internalSave(_ context: NSManagedObjectContext) {
70+
guard context.hasChanges else {
71+
return
72+
}
73+
74+
let inserted = Array(context.insertedObjects)
75+
do {
76+
try context.obtainPermanentIDs(for: inserted)
77+
} catch {
78+
DDLogError("Error obtaining permanent object IDs for \(inserted), \(error)")
79+
}
80+
81+
do {
82+
try context.save()
83+
} catch {
84+
handleSaveError(error as NSError, in: context)
85+
}
86+
}
87+
88+
}
89+
90+
private extension ManagedObjectContextFactory {
91+
6092
func handleSaveError(_ error: NSError, in context: NSManagedObjectContext) {
6193
let isMainContext = context == mainContext
6294
let exceptionName: NSExceptionName = isMainContext ? .coreDataSaveMainException : .coreDataSaveDerivedException
@@ -68,9 +100,7 @@ extension ContextManager {
68100
let exception = NSException(name: exceptionName, reason: reason, userInfo: nil)
69101
exception.raise()
70102
}
71-
}
72103

73-
private extension ContextManager {
74104
func reasonForError(_ error: NSError) -> String {
75105
if error.code == NSValidationMultipleErrorsError {
76106
guard let errors = error.userInfo[NSDetailedErrorsKey] as? [NSError] else {

WordPress/Classes/Utility/ContextManager.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#import <Foundation/Foundation.h>
22
#import <CoreData/CoreData.h>
33

4+
#import "ManagedObjectContextFactory.h"
5+
46
NS_ASSUME_NONNULL_BEGIN
57

68
/**
@@ -59,8 +61,9 @@ FOUNDATION_EXTERN NSString * const ContextManagerModelNameCurrent;
5961
Use ContextManagerModelNameCurrent for current version, or
6062
"WordPress <version>" for specific version.
6163
@param storeURL Database location. Use +[ContextManager inMemoryStoreURL] to create an in-memory database.
64+
@param contextFactory A type that conforms to `ManagedObjectContextFactory`.
6265
*/
63-
- (instancetype)initWithModelName:(NSString *)modelName storeURL:(NSURL *)storeURL NS_DESIGNATED_INITIALIZER;
66+
- (instancetype)initWithModelName:(NSString *)modelName storeURL:(NSURL *)storeURL contextFactory:(Class<ManagedObjectContextFactory> _Nullable)factory NS_DESIGNATED_INITIALIZER;
6467

6568

6669
///--------------------------

WordPress/Classes/Utility/ContextManager.m

Lines changed: 19 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#import "ContextManager.h"
2+
#import "LegacyContextFactory.h"
23
#import "WordPress-Swift.h"
34
@import WordPressShared.WPAnalytics;
45
@import Foundation;
@@ -18,13 +19,11 @@ @interface ContextManager ()
1819

1920
@property (nonatomic, strong) NSPersistentStoreDescription *storeDescription;
2021
@property (nonatomic, strong) NSPersistentContainer *persistentContainer;
21-
@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
2222
@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
23-
@property (nonatomic, strong) NSManagedObjectContext *mainContext;
24-
@property (nonatomic, strong) NSManagedObjectContext *writerContext;
2523
@property (nonatomic, assign) BOOL migrationFailed;
2624
@property (nonatomic, strong) NSString *modelName;
2725
@property (nonatomic, strong) NSURL *storeURL;
26+
@property (nonatomic, strong) id<ManagedObjectContextFactory> contextFactory;
2827

2928
@end
3029

@@ -43,25 +42,27 @@ - (instancetype)init
4342
storeURL = [self localDatabasePath];
4443
}
4544

46-
return [self initWithModelName:ContextManagerModelNameCurrent storeURL:storeURL];
45+
return [self initWithModelName:ContextManagerModelNameCurrent storeURL:storeURL contextFactory:nil];
4746
}
4847

49-
- (instancetype)initWithModelName:(NSString *)modelName storeURL:(NSURL *)storeURL
48+
- (instancetype)initWithModelName:(NSString *)modelName storeURL:(NSURL *)storeURL contextFactory:(Class)factory
5049
{
5150
self = [super init];
5251
if (self) {
52+
if (factory == nil) {
53+
factory = [ContainerContextFactory class];
54+
}
55+
5356
NSParameterAssert([modelName isEqualToString:ContextManagerModelNameCurrent] || [modelName hasPrefix:@"WordPress "]);
5457
NSParameterAssert([storeURL isFileURL]);
58+
NSParameterAssert([factory conformsToProtocol:@protocol(ManagedObjectContextFactory)]);
5559

5660
self.modelName = modelName;
5761
self.storeURL = storeURL;
5862

5963
[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];
6566
}
6667

6768
return self;
@@ -84,118 +85,31 @@ + (NSURL *)inMemoryStoreURL
8485

8586
#pragma mark - Contexts
8687

87-
- (NSManagedObjectContext *const)newDerivedContext
88-
{
89-
return [self newChildContextWithConcurrencyType:NSPrivateQueueConcurrencyType];
90-
}
91-
92-
- (void)createWriterContext
88+
- (NSManagedObjectContext *)mainContext
9389
{
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;
9991
}
10092

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
11294
{
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];
11996
}
12097

121-
12298
#pragma mark - Context Saving and Merging
12399

124100
- (void)saveContextAndWait:(NSManagedObjectContext *)context
125101
{
126-
[self saveContext:context andWait:YES withCompletionBlock:nil];
102+
[self.contextFactory saveContext:context andWait:YES withCompletionBlock:nil];
127103
}
128104

129105
- (void)saveContext:(NSManagedObjectContext *)context
130106
{
131-
[self saveContext:context andWait:NO withCompletionBlock:nil];
107+
[self.contextFactory saveContext:context andWait:NO withCompletionBlock:nil];
132108
}
133109

134110
- (void)saveContext:(NSManagedObjectContext *)context withCompletionBlock:(void (^)(void))completionBlock
135111
{
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];
199113
}
200114

201115
- (void)performAndSaveUsingBlock:(void (^)(NSManagedObjectContext *context))aBlock
@@ -214,7 +128,7 @@ - (void)performAndSaveUsingBlock:(void (^)(NSManagedObjectContext *context))aBlo
214128
[context performBlock:^{
215129
aBlock(context);
216130

217-
[self saveContext:context andWait:NO withCompletionBlock:completion];
131+
[self.contextFactory saveContext:context andWait:NO withCompletionBlock:completion];
218132
}];
219133
}
220134

@@ -297,46 +211,9 @@ - (NSManagedObjectModel *)managedObjectModel
297211
return _managedObjectModel;
298212
}
299213

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-
323214

324215
#pragma mark - Private Helpers
325216

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-
340217
- (void)migrateDataModelsIfNecessary:(SentryStartupEvent *)sentryEvent
341218
{
342219
if (![[NSFileManager defaultManager] fileExistsAtPath:[[self storeURL] path]]) {

0 commit comments

Comments
 (0)