Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data with iCloud Notifications in iOS 7

I have added iCloud support to my app. when the user update his data I got a notification NSPersistentStoreDidImportUbiquitousContentChangesNotification

That's great

However, I have these problems

  1. I can't find a will version of this notification that I can use to show loader for example that the database will be updated
  2. Since I can't find a will version, then I used the same notification to display a loader to tell the user that the database is being updated ... The problem in this notification is that it can be called several time if the content changed in iCloud is relatively large which lead me to display several loading indicator !
  3. Is there a way that I can use to trigger the update through iCloud manually?

.


I added iCloud support to Core data by doing this:

in NSManagedObjectContext

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;

in NSPersistentStoreCoordinator

[_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:@{NSPersistentStoreUbiquitousContentNameKey:@"iCloudStore"} error:nil];

and In NSPersistentStoreDidImportUbiquitousContentChangesNotification notification method

- (void)persistentStoreDidImportUbiquitousContentChanges:(NSNotification *)notification
{
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    [managedObjectContext performBlock:^{
        [managedObjectContext mergeChangesFromContextDidSaveNotification:notification];

        dispatch_async(dispatch_get_main_queue(), ^{
            UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
            MBProgressHUD *hud = [MBProgressHUD HUDForView:mainWindow];
            if (hud == nil) {
                hud = [[MBProgressHUD alloc] initWithWindow:mainWindow];
            }
            [mainWindow addSubview:hud];
            hud.labelText = NSLocalizedString(@"Progress updated", nil);
            [hud show:YES];
            [hud hide:YES afterDelay:1];

            // Post Notification
            [[NSNotificationCenter defaultCenter] postNotificationName:RESET_APPLICATION_NOTIFICATION object:nil];
        });
    }];
}
like image 779
Hani Ibrahim Avatar asked Dec 07 '13 01:12

Hani Ibrahim


People also ask

Should I use Core Data iOS?

The next time you need to store data, you should have a better idea of your options. Core Data is unnecessary for random pieces of unrelated data, but it's a perfect fit for a large, relational data set. The defaults system is ideal for small, random pieces of unrelated data, such as settings or the user's preferences.

What is iOS Core Data?

Core Data is an object graph and persistence framework provided by Apple in the macOS and iOS operating systems. It was introduced in Mac OS X 10.4 Tiger and iOS with iPhone SDK 3.0. It allows data organized by the relational entity–attribute model to be serialized into XML, binary, or SQLite stores.

Is Core Data still used?

Yes. It's a pretty old framework and its Objective-C roots are not very well hidden. Regardless, Apple's clearly still interested in having people use and adopt Core Data given the fact that they've added new features for Core Data + SwiftUI in iOS 15, and previous iOS versions received various Core Data updates too.

Do CloudKit apps sync with iCloud users?

Sync user data between multiple apps from the same developer If you have a suite of apps, they can all share the same CloudKit container so users can have access to their data for all of your apps on every device they have associated with their iCloud account.


1 Answers

I can't find a will version of this notification that I can use to show loader for example that the database will be updated

Yeah, that's because there isn't one. When new changes come in, the iCloud daemon saves them and then tells you what it has done.

Since I can't find a will version, then I used the same notification to display a loader to tell the user that the database is being updated ... The problem in this notification is that it can be called several time if the content changed in iCloud is relatively large which lead me to display several loading indicator !

Yes! I had this same issue. These notifications can be very frequent, so you don't want to notify the user every time one comes in. What I did was arrange to delay the notification until iCloud had quieted down for at least 1 second. You can do this using an NSTimer. First declare it as a property:

@property (readwrite, retain) NSTimer *iCloudUpdateTimer;

Then when you get the "did import" notification, do something like this:

if (self.iCloudUpdateTimer == nil) {
    self.iCloudUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
        target:self
        selector:@selector(notifyUser:)
        userInfo:nil
        repeats:NO];
} else {
    [self.iCloudUpdateTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:1.0];
}

// Now actually handle the notification....

What this does: Creates the timer if it doesn't exist. If it does exist, it delays the fire date for one second. When iCloud sends a lot of notifications, the timer keeps getting pushed out into the future. The timer will finally fire one second after iCloud calms down.

Then when the timer fires, do something like:

- (void)notifyUser:(NSNotification *)notification
{
    [self.iCloudUpdateTimer invalidate];
    self.iCloudUpdateTimer = nil;

    // Then notify the user
}

You may need to use dispatch_async to make sure that all timer access happens on the same queue.

(As an aside, even if there were a "will import" notification, it would probably be posted just as often as the current "did import" notification, so it wouldn't help you very much.)

Is there a way that I can use to trigger the update through iCloud manually?

No, you have absolutely no control over that.

like image 94
Tom Harrington Avatar answered Oct 14 '22 00:10

Tom Harrington