5

I am using the Ensembles framework to sync data with iCloud. Everything was working fine until I migrated to Swift 3.

The framework is in Objective-C and my appDelegate functions I have migrated to Swift 3; I have had issues since. I call the appDelegate.syncWithCompletion throughout the app when saving changes to NSManagedObjects.

Here's the appDelegate Functions

// MARK: Ensembles

var cloudFileSystem: CDECloudFileSystem!
var ensemble: CDEPersistentStoreEnsemble!

func syncWithCompletion(completion:@escaping (_ completed:Bool) -> Void) {

    if !ensemble.isLeeched {
        ensemble.leechPersistentStore { error in
            if error != nil {
                print("cannot leech \(error!.localizedDescription)")
                completion(false)
            }
            else {
                print("leached!!")
                completion(true)
            }
        }
    }
    else {
        ensemble.merge{ error in
            if error != nil {
                print("cannot merge \(error!.localizedDescription)")
                completion(false)
            }
            else {
                print("merged!!")
                completion(true)
                //NSNotificationCenter.defaultCenter().postNotificationName("Updated-DB", object: nil)
            }
        }
    }
}

func persistentStoreEnsemble(_ ensemble: CDEPersistentStoreEnsemble, didSaveMergeChangesWith notification: Notification) {
    managedObjectContext.performAndWait {
        print("Database was updated from iCloud")
        self.managedObjectContext.mergeChanges(fromContextDidSave: notification as Notification)
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "Updated-DB"), object: nil)
    }
}

private func persistentStoreEnsemble(ensemble: CDEPersistentStoreEnsemble!, globalIdentifiersForManagedObjects objects: [AnyObject]!) -> [AnyObject]! {
    return (objects as NSArray).value(forKeyPath: "uniqueIdentifier") as! [AnyObject]
}

I turned iCloud drive off and I get the following error when running the app; the CPU is over 100%, Memory and Energy are also high.

Message from debugger: Terminated due to memory issue

When iCloud drive is on for syncing and merging data I get the following

Could not load any Objective-C class information. This will significantly reduce the quality of type information available.

When investigating further instruments takes me to the following function in the Ensembles framework; the dispatch_async(queue,^{ line more specifically.

#pragma mark Merging Store Modification Events

- (void)mergeEventsWithCompletion:(CDECompletionBlock)completion
{
    NSAssert([NSThread isMainThread], @"mergeEvents... called off main thread");

    newEventUniqueId = nil;

    // Setup a context for accessing the main store
    NSError *error = nil;
    NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel];
    NSPersistentStore *persistentStore = [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:self.persistentStoreOptions error:&error];
    if (!persistentStore) {
        [self failWithCompletion:completion error:error];
        return;
    }

    self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [self.managedObjectContext performBlockAndWait:^{
        self.managedObjectContext.persistentStoreCoordinator = coordinator;
        self.managedObjectContext.undoManager = nil;
    }];

    NSManagedObjectContext *eventStoreContext = self.eventStore.managedObjectContext;

    // Integrate on background queue
    dispatch_async(queue,^{
        @try {
            __block NSError *error;

            // Apply changes
            BOOL integrationSucceeded = [self integrate:&error];
            if (!integrationSucceeded) {
                [self failWithCompletion:completion error:error];
                return;
            }

            // If no changes, complete
            __block BOOL hasChanges;
            [managedObjectContext performBlockAndWait:^{
                hasChanges = managedObjectContext.hasChanges;
            }];
            if (!hasChanges) {
                [self completeSuccessfullyWithCompletion:completion];
                return;
            }

            // Create id of new event
            // Register event in case of crashes
            newEventUniqueId = [[NSProcessInfo processInfo] globallyUniqueString];
            [self.eventStore registerIncompleteEventIdentifier:newEventUniqueId isMandatory:NO];

            // Create a merge event
            CDEEventBuilder *eventBuilder = [[CDEEventBuilder alloc] initWithEventStore:self.eventStore];
            eventBuilder.ensemble = self.ensemble;
            CDERevision *revision = [eventBuilder makeNewEventOfType:CDEStoreModificationEventTypeMerge uniqueIdentifier:newEventUniqueId];

            // Repair inconsistencies caused by integration
            BOOL repairSucceeded = [self repairWithMergeEventBuilder:eventBuilder error:&error];
            if (!repairSucceeded) {
                [self failWithCompletion:completion error:error];
                return;
            }

            // Commit (save) the changes
            BOOL commitSucceeded = [self commitWithMergeEventBuilder:eventBuilder error:&error];
            if (!commitSucceeded) {
                [self failWithCompletion:completion error:error];
                return;
            }

            // Save changes event context
            __block BOOL eventSaveSucceeded = NO;
            [eventStoreContext performBlockAndWait:^{
                BOOL isUnique = [self checkUniquenessOfEventWithRevision:revision];
                if (isUnique) {
                    [eventBuilder finalizeNewEvent];
                    eventSaveSucceeded = [eventStoreContext save:&error];
                }
                else {
                    error = [NSError errorWithDomain:CDEErrorDomain code:CDEErrorCodeSaveOccurredDuringMerge userInfo:nil];
                }
                [eventStoreContext reset];
            }];
            if (!eventSaveSucceeded) {
                [self failWithCompletion:completion error:error];
                return;
            }

            // Notify of save
            [self.managedObjectContext performBlockAndWait:^{
                if (didSaveBlock) didSaveBlock(managedObjectContext, saveInfoDictionary);
            }];
            saveInfoDictionary = nil;

            // Complete
            [self completeSuccessfullyWithCompletion:completion];
        }
        @catch (NSException *exception) {
            NSDictionary *info = @{NSLocalizedFailureReasonErrorKey:exception.reason};
            NSError *error = [NSError errorWithDomain:CDEErrorDomain code:CDEErrorCodeUnknown userInfo:info];
            [self failWithCompletion:completion error:error];
        }
    });
} 

Does anyone know what is causing the errors and and how I can resolve them? It seems to keep looping over the code, also NSManagedObjects keep getting duplicated.

PS: The project worked fine in swift 2.2.

A.Roe
  • 973
  • 3
  • 15
  • 34
  • There were a couple of bugs fixed in the last two to three weeks which might be related. Make sure you have the latest code. (Use your download link, or update from GitHub if you have access.) – Drew McCormack Sep 13 '16 at 06:35
  • Has it been fixed also for open source version? Thanks. – Lubos Sep 23 '16 at 21:16

0 Answers0