Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

*Major* rebase #5

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
38 changes: 19 additions & 19 deletions MKiCloudSync.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
//
// MKiCloudSync.h
// iCloud1
//
// Created by Mugunth Kumar (@mugunthkumar) on 20/11/11.
// Created by Mugunth Kumar on 11/20//11.
// Modified by Alexsander Akers on 1/4/12.
//
// Copyright (C) 2011-2020 by Steinlogic

//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Expand All @@ -23,23 +24,22 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// As a side note, you might also consider
// 1) tweeting about this mentioning @mugunthkumar
// 2) A paypal donation to [email protected]
#import <Foundation/Foundation.h>

#ifdef DEBUG
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
# define DLog(...)
#endif
// Change to 1 to enable logging
#define MKiCloudSyncDebug 0

// ALog always displays output regardless of the DEBUG setting
#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);

#import <Foundation/Foundation.h>
#define kMKiCloudSyncNotification @"MKiCloudSyncDidUpdateToLatest"
// Posted
extern NSString *const MKiCloudSyncDidUpdateNotification;

@interface MKiCloudSync : NSObject

+(void) start;
+ (BOOL) isSyncing;
+ (BOOL) start;

+ (NSMutableSet *) ignoredKeys;

+ (void) cleanUbiquitousStore;
+ (void) stop;

@end
239 changes: 165 additions & 74 deletions MKiCloudSync.m
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
//
// MKiCloudSync.m
// iCloud1
//
// Created by Mugunth Kumar (@mugunthkumar) on 20/11/11.
// Created by Mugunth Kumar on 11/20//11.
// Modified by Alexsander Akers on 1/4/12.
//
// Copyright (C) 2011-2020 by Steinlogic

//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Expand All @@ -23,86 +24,176 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// As a side note, you might also consider
// 1) tweeting about this mentioning @mugunthkumar
// 2) A paypal donation to [email protected]
#import "MKiCloudSync.h"

NSString *const MKiCloudSyncDidUpdateNotification = @"MKiCloudSyncDidUpdateNotification";

#import "MKiCloudSync.h"
static BOOL _isSyncing;
static dispatch_queue_t _queue;

@interface MKiCloudSync ()

+ (BOOL) tryToStartSync;

+ (void) pullFromICloud: (NSNotification *) note;
+ (void) pushToICloud;

@end

@implementation MKiCloudSync

+(void) updateToiCloud:(NSNotification*) notificationObject {

NSDictionary *dict = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];

[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {

[[NSUbiquitousKeyValueStore defaultStore] setObject:obj forKey:key];
}];

[[NSUbiquitousKeyValueStore defaultStore] synchronize];
+ (BOOL) isSyncing
{
__block BOOL isSyncing = NO;

dispatch_sync(_queue, ^{
isSyncing = _isSyncing;
});

return isSyncing;
}
+ (BOOL) start
{
if ([NSUbiquitousKeyValueStore class] && [NSUbiquitousKeyValueStore defaultStore] && [self tryToStartSync])
{
#if MKiCloudSyncDebug
NSLog(@"MKiCloudSync: Will start sync");
#endif

// Force push
[MKiCloudSync pushToICloud];

// Force pull
NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
NSDictionary *dict = [store dictionaryRepresentation];

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[dict enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
[userDefaults setObject: obj forKey: key];
}];
[userDefaults synchronize];

NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];

// Post notification
[dnc postNotificationName: MKiCloudSyncDidUpdateNotification object: self];

+(void) updateFromiCloud:(NSNotification*) notificationObject {

NSUbiquitousKeyValueStore *iCloudStore = [NSUbiquitousKeyValueStore defaultStore];
NSDictionary *dict = [iCloudStore dictionaryRepresentation];

// prevent NSUserDefaultsDidChangeNotification from being posted while we update from iCloud

[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSUserDefaultsDidChangeNotification
object:nil];

[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {

[[NSUserDefaults standardUserDefaults] setObject:obj forKey:key];
}];

[[NSUserDefaults standardUserDefaults] synchronize];

// enable NSUserDefaultsDidChangeNotification notifications again

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateToiCloud:)
name:NSUserDefaultsDidChangeNotification
object:nil];

[[NSNotificationCenter defaultCenter] postNotificationName:kMKiCloudSyncNotification object:nil];
// Add self as observer
[dnc addObserver: self selector: @selector(pullFromICloud:) name: NSUbiquitousKeyValueStoreDidChangeExternallyNotification object: store];
[dnc addObserver: self selector: @selector(pushToICloud) name: NSUserDefaultsDidChangeNotification object: nil];

#if MKiCloudSyncDebug
NSLog(@"MKiCloudSync: Did start sync");
#endif
return YES;
}

return NO;
}
+ (BOOL) tryToStartSync
{
__block BOOL didSucceed = NO;

dispatch_sync(_queue, ^{
if (!_isSyncing)
{
_isSyncing = YES;
didSucceed = YES;
}
});

+(void) start {

if(NSClassFromString(@"NSUbiquitousKeyValueStore")) { // is iOS 5?

if([NSUbiquitousKeyValueStore defaultStore]) { // is iCloud enabled

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateFromiCloud:)
name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification
object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateToiCloud:)
name:NSUserDefaultsDidChangeNotification object:nil];
} else {
DLog(@"iCloud not enabled");
}
}
else {
DLog(@"Not an iOS 5 device");
}
return didSucceed;
}

+ (void) dealloc {

[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification
object:nil];
+ (NSMutableSet *) ignoredKeys
{
static NSMutableSet *ignoredKeys;
static dispatch_once_t token;
dispatch_once(&token, ^{
ignoredKeys = [NSMutableSet new];
});

return ignoredKeys;
}

[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSUserDefaultsDidChangeNotification
object:nil];
+ (void) cleanUbiquitousStore
{
[self stop];

NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
NSDictionary *dict = [store dictionaryRepresentation];

NSMutableSet *keys = [NSMutableSet setWithArray: [dict allKeys]];
[keys minusSet: [self ignoredKeys]];

[keys enumerateObjectsUsingBlock: ^(NSString *key, BOOL *stop) {
[store removeObjectForKey: key];
}];
[store synchronize];

#if MKiCloudSyncDebug
NSLog(@"MKiCloudSync: Cleaned ubiquitous store");
#endif
}
+ (void) initialize
{
if (self == [MKiCloudSync class])
{
_isSyncing = NO;
_queue = dispatch_queue_create("com.mugunthkumar.MKiCloudSync", DISPATCH_QUEUE_SERIAL);
}
}
+ (void) pullFromICloud: (NSNotification *) note
{
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc removeObserver: self name: NSUserDefaultsDidChangeNotification object: nil];

NSUbiquitousKeyValueStore *store = note.object;
NSArray *changedKeys = [note.userInfo objectForKey: NSUbiquitousKeyValueStoreChangedKeysKey];

#if MKiCloudSyncDebug
NSLog(@"MKiCloudSync: Pulled from iCloud");
#endif

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[changedKeys enumerateObjectsUsingBlock: ^(NSString *key, NSUInteger idx, BOOL *stop) {
id obj = [store objectForKey: key];
[userDefaults setObject: obj forKey: key];
}];
[userDefaults synchronize];

[dnc addObserver: self selector: @selector(pushToICloud) name: NSUserDefaultsDidChangeNotification object: nil];
[dnc postNotificationName: MKiCloudSyncDidUpdateNotification object: nil];
}
+ (void) pushToICloud
{
NSString *identifier = [[NSBundle mainBundle] bundleIdentifier];

NSMutableDictionary *persistentDomain = [[[NSUserDefaults standardUserDefaults] persistentDomainForName: identifier] mutableCopy];

NSArray *ignoredKeys = [[self ignoredKeys] allObjects];
[persistentDomain removeObjectsForKeys: ignoredKeys];

NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
[persistentDomain enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
[store setObject: obj forKey: key];
}];
[store synchronize];

#if MKiCloudSyncDebug
NSLog(@"MKiCloudSync: Pushed to iCloud");
#endif
}
+ (void) stop
{
dispatch_sync(_queue, ^{
_isSyncing = NO;
[[NSNotificationCenter defaultCenter] removeObserver: self];

#if MKiCloudSyncDebug
NSLog(@"MKiCloudSync: Stopped syncing with iCloud");
#endif
});
}

@end
13 changes: 13 additions & 0 deletions MKiCloudSync.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Pod::Spec.new do |s|
s.name = 'MKiCloudSync'
s.version = '1.0.2'
s.license = 'MIT'
s.summary = 'Sync your NSUserDefaults to iCloud automatically.'
s.homepage = 'https://github.com/pandamonia/MKiCloudSync'
s.author = { 'Alexsander Akers' => '[email protected]',
'Mugunth Kumar' => '[email protected]' }
s.source = { :git => 'https://github.com/pandamonia/MKiCloudSync.git', :tag => 'v1.0.2' }
s.platform = :ios
s.source_files = 'MKiCloudSync.{h,m}'
s.requires_arc = true
end
Loading