From d02bea34097e566d09f297bb16092eef74c2c5d4 Mon Sep 17 00:00:00 2001 From: Peter Easdown Date: Wed, 17 Feb 2016 13:10:43 +1100 Subject: [PATCH 1/2] Added functionality to simplify the initialisation of the wrapper. These changes were primarily to facilitate Shared iPad support. --- SDCloudUserDefaults/SDCloudUserDefaults.h | 14 +++ SDCloudUserDefaults/SDCloudUserDefaults.m | 131 +++++++++++++++------- 2 files changed, 106 insertions(+), 39 deletions(-) diff --git a/SDCloudUserDefaults/SDCloudUserDefaults.h b/SDCloudUserDefaults/SDCloudUserDefaults.h index b33b6e4..86d498f 100644 --- a/SDCloudUserDefaults/SDCloudUserDefaults.h +++ b/SDCloudUserDefaults/SDCloudUserDefaults.h @@ -134,6 +134,20 @@ */ +(void)removeNotifications; +#define ICLOUD_DATA_ENABLED_KEY @"iCloudDataEnabled" + +/** + * Enables or disables the storage of player information and other settings in iCloud. For Shared iPad usage + * this needs to be enabled so that the users data is preserved in iCloud when the iPad is swapped to another + * user. + */ ++ (void) setiCloudEnabled:(BOOL)iCloudEnabled; + +/** + * Returns YES if iCloud is enabled. + */ ++ (BOOL) isiCloudEnabled; + /** * Notification with the following name will be fired for every updated value that came from iCloud */ diff --git a/SDCloudUserDefaults/SDCloudUserDefaults.m b/SDCloudUserDefaults/SDCloudUserDefaults.m index bef4fdc..36d031a 100644 --- a/SDCloudUserDefaults/SDCloudUserDefaults.m +++ b/SDCloudUserDefaults/SDCloudUserDefaults.m @@ -15,6 +15,37 @@ @implementation SDCloudUserDefaults static NSString *suiteName; static NSUserDefaults *userDefaults; ++ (void) setiCloudEnabled:(BOOL)iCloudEnabled { + [[NSUserDefaults standardUserDefaults] setBool:iCloudEnabled forKey:ICLOUD_DATA_ENABLED_KEY]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + if (iCloudEnabled == YES) { + [SDCloudUserDefaults registerForNotifications]; + } else { + [SDCloudUserDefaults removeNotifications]; + } +} + ++ (BOOL) isiCloudEnabled { + return [[NSUserDefaults standardUserDefaults] boolForKey:ICLOUD_DATA_ENABLED_KEY]; +} + ++ (void) initialize { + [super initialize]; + + id keyValue = [SDCloudUserDefaults objectForKey:ICLOUD_DATA_ENABLED_KEY]; + + if (keyValue != nil) { + BOOL iCloudEnabled = [SDCloudUserDefaults boolForKey:ICLOUD_DATA_ENABLED_KEY]; + + if (iCloudEnabled == YES) { + [SDCloudUserDefaults registerForNotifications]; + } else { + [SDCloudUserDefaults removeNotifications]; + } + } +} + +(NSUserDefaults *) _standardUserDefaults { if (userDefaults == nil) { userDefaults = [NSUserDefaults standardUserDefaults]; @@ -62,13 +93,19 @@ +(BOOL)boolForKey:(NSString*)aKey { } +(id)objectForKey:(NSString*)aKey { - NSUbiquitousKeyValueStore* cloud = [NSUbiquitousKeyValueStore defaultStore]; - id retv = [cloud objectForKey:aKey]; - if (!retv) { - retv = [[self _standardUserDefaults] objectForKey:aKey]; - [cloud setObject:retv forKey:aKey]; + if ([SDCloudUserDefaults isiCloudEnabled] == YES) { + NSUbiquitousKeyValueStore* cloud = [NSUbiquitousKeyValueStore defaultStore]; + id retv = [cloud objectForKey:aKey]; + + if (!retv) { + retv = [[self _standardUserDefaults] objectForKey:aKey]; + [cloud setObject:retv forKey:aKey]; + } + + return retv; + } else { + return [[self _standardUserDefaults] objectForKey:aKey]; } - return retv; } +(NSInteger)integerForKey:(NSString*)aKey { @@ -88,8 +125,13 @@ +(void)setBool:(BOOL)aBool forKey:(NSString*)aKey { } +(void)setObject:(id)anObject forKey:(NSString*)aKey { - [[NSUbiquitousKeyValueStore defaultStore] setObject:anObject forKey:aKey]; + if ([SDCloudUserDefaults isiCloudEnabled] == YES) { + [[NSUbiquitousKeyValueStore defaultStore] setObject:anObject forKey:aKey]; + } + [[self _standardUserDefaults] setObject:anObject forKey:aKey]; + + [SDCloudUserDefaults synchronize]; } +(void)setInteger:(NSInteger)anInteger forKey:(NSString*)aKey { @@ -103,12 +145,20 @@ +(void)setFloat:(float)aFloat forKey:(NSString *)aKey { } +(void)removeObjectForKey:(NSString*)aKey { - [[NSUbiquitousKeyValueStore defaultStore] removeObjectForKey:aKey]; + if ([SDCloudUserDefaults isiCloudEnabled] == YES) { + [[NSUbiquitousKeyValueStore defaultStore] removeObjectForKey:aKey]; + } + [[self _standardUserDefaults] removeObjectForKey:aKey]; + + [SDCloudUserDefaults synchronize]; } +(void)synchronize { - [[NSUbiquitousKeyValueStore defaultStore] synchronize]; + if ([SDCloudUserDefaults isiCloudEnabled] == YES) { + [[NSUbiquitousKeyValueStore defaultStore] synchronize]; + } + [[self _standardUserDefaults] synchronize]; } @@ -118,36 +168,39 @@ +(void)registerForNotifications { return; } - notificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:@"NSUbiquitousKeyValueStoreDidChangeExternallyNotification" - object:[NSUbiquitousKeyValueStore defaultStore] - queue:nil - usingBlock:^(NSNotification* notification) { - - NSDictionary* userInfo = [notification userInfo]; - NSNumber* reasonForChange = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangeReasonKey]; - - // If a reason could not be determined, do not update anything. - if (!reasonForChange) - return; - - // Update only for changes from the server. - NSInteger reason = [reasonForChange integerValue]; - if ((reason == NSUbiquitousKeyValueStoreServerChange) || - (reason == NSUbiquitousKeyValueStoreInitialSyncChange)) { - NSUserDefaults* defaults = [self _standardUserDefaults]; - NSUbiquitousKeyValueStore* cloud = [NSUbiquitousKeyValueStore defaultStore]; - NSArray* changedKeys = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey]; - for (NSString* key in changedKeys) { - [defaults setObject:[cloud objectForKey:key] forKey:key]; - - [[NSNotificationCenter defaultCenter] postNotificationName:SDCloudValueUpdatedNotification - object:self - userInfo:@{key:[cloud objectForKey:key]}]; - } - - - } - }]; + notificationObserver = [[NSNotificationCenter defaultCenter] + addObserverForName:NSUbiquitousKeyValueStoreDidChangeExternallyNotification + object:[NSUbiquitousKeyValueStore defaultStore] + queue:nil + usingBlock:^(NSNotification* notification) { + + NSDictionary* userInfo = [notification userInfo]; + NSNumber* reasonForChange = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangeReasonKey]; + + // If a reason could not be determined, do not update anything. + if (!reasonForChange) + return; + + // Update only for changes from the server. + NSInteger reason = [reasonForChange integerValue]; + if ((reason == NSUbiquitousKeyValueStoreServerChange) || + (reason == NSUbiquitousKeyValueStoreInitialSyncChange)) { + + NSUserDefaults* defaults = [self _standardUserDefaults]; + NSUbiquitousKeyValueStore* cloud = [NSUbiquitousKeyValueStore defaultStore]; + NSArray* changedKeys = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey]; + + for (NSString* key in changedKeys) { + [defaults setObject:[cloud objectForKey:key] forKey:key]; + + [[NSNotificationCenter defaultCenter] postNotificationName:SDCloudValueUpdatedNotification + object:self + userInfo:@{key:[cloud objectForKey:key]}]; + } + + + } + }]; } } From cbc3c88f91ec23813cf49edfe62fddbd9a8a1337 Mon Sep 17 00:00:00 2001 From: Peter Easdown Date: Sun, 11 Oct 2020 09:13:58 +1100 Subject: [PATCH 2/2] Added Swift version of the class and a test for it. --- SDCloudUserDefaults.xcodeproj/project.pbxproj | 235 +++++++++++++++++- .../SDCloudUserDefaults OSX.xcscheme | 10 +- SDCloudUserDefaults/SDCloudUserDefaults.m | 18 +- SDCloudUserDefaults_Swift/AppDelegate.swift | 42 ++++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 98 ++++++++ .../Assets.xcassets/Contents.json | 6 + .../Base.lproj/LaunchScreen.storyboard | 25 ++ .../Base.lproj/Main.storyboard | 72 ++++++ SDCloudUserDefaults_Swift/Info.plist | 64 +++++ .../SDCloudUserDefaults.swift | 228 +++++++++++++++++ .../SDCloudUserDefaults_Swift.entitlements | 10 + SDCloudUserDefaults_Swift/SceneDelegate.swift | 53 ++++ .../ViewController.swift | 51 ++++ 14 files changed, 909 insertions(+), 14 deletions(-) create mode 100644 SDCloudUserDefaults_Swift/AppDelegate.swift create mode 100644 SDCloudUserDefaults_Swift/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 SDCloudUserDefaults_Swift/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 SDCloudUserDefaults_Swift/Assets.xcassets/Contents.json create mode 100644 SDCloudUserDefaults_Swift/Base.lproj/LaunchScreen.storyboard create mode 100644 SDCloudUserDefaults_Swift/Base.lproj/Main.storyboard create mode 100644 SDCloudUserDefaults_Swift/Info.plist create mode 100644 SDCloudUserDefaults_Swift/SDCloudUserDefaults.swift create mode 100644 SDCloudUserDefaults_Swift/SDCloudUserDefaults_Swift.entitlements create mode 100644 SDCloudUserDefaults_Swift/SceneDelegate.swift create mode 100644 SDCloudUserDefaults_Swift/ViewController.swift diff --git a/SDCloudUserDefaults.xcodeproj/project.pbxproj b/SDCloudUserDefaults.xcodeproj/project.pbxproj index 98cf858..bfa0ece 100644 --- a/SDCloudUserDefaults.xcodeproj/project.pbxproj +++ b/SDCloudUserDefaults.xcodeproj/project.pbxproj @@ -26,6 +26,13 @@ C480299416909FFF0061EFF8 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C480299216909FFF0061EFF8 /* MainStoryboard.storyboard */; }; C480299716909FFF0061EFF8 /* WSLViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C480299616909FFF0061EFF8 /* WSLViewController.m */; }; C480299E1690A0100061EFF8 /* libSDCloudUserDefaults.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C4802949169093EF0061EFF8 /* libSDCloudUserDefaults.a */; }; + D06343262531DD0B004AB667 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06343252531DD0B004AB667 /* AppDelegate.swift */; }; + D06343282531DD0B004AB667 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06343272531DD0B004AB667 /* SceneDelegate.swift */; }; + D063432A2531DD0B004AB667 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06343292531DD0B004AB667 /* ViewController.swift */; }; + D063432D2531DD0B004AB667 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D063432B2531DD0B004AB667 /* Main.storyboard */; }; + D063432F2531DD0D004AB667 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D063432E2531DD0D004AB667 /* Assets.xcassets */; }; + D06343322531DD0D004AB667 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D06343302531DD0D004AB667 /* LaunchScreen.storyboard */; }; + D063435B2531DD64004AB667 /* SDCloudUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D063435A2531DD64004AB667 /* SDCloudUserDefaults.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -77,6 +84,16 @@ C4C65C791B25F20700288498 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; C4C65C7A1B25F20700288498 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; C4C65C7B1B25F20700288498 /* SDCloudUserDefaults.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SDCloudUserDefaults.podspec; sourceTree = ""; }; + D06343232531DD0B004AB667 /* SDCloudUserDefaults_Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SDCloudUserDefaults_Swift.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D06343252531DD0B004AB667 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + D06343272531DD0B004AB667 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + D06343292531DD0B004AB667 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + D063432C2531DD0B004AB667 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + D063432E2531DD0D004AB667 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + D06343312531DD0D004AB667 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + D06343332531DD0D004AB667 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D063435A2531DD64004AB667 /* SDCloudUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SDCloudUserDefaults.swift; sourceTree = ""; }; + D0D08AE62531E46A00DE5072 /* SDCloudUserDefaults_Swift.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SDCloudUserDefaults_Swift.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -113,6 +130,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D06343202531DD0B004AB667 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -124,6 +148,7 @@ C4C65C7B1B25F20700288498 /* SDCloudUserDefaults.podspec */, C480294E169093EF0061EFF8 /* SDCloudUserDefaults */, C480298016909FFF0061EFF8 /* TestSDCloudUserDefaults */, + D06343242531DD0B004AB667 /* SDCloudUserDefaults_Swift */, C480294B169093EF0061EFF8 /* Frameworks */, C480294A169093EF0061EFF8 /* Products */, ); @@ -136,6 +161,7 @@ C480297916909FFF0061EFF8 /* TestSDCloudUserDefaults.app */, 23BB07851BCA5E8A004DD41D /* SDCloudUserDefaults.framework */, 23BB07921BCA5EA2004DD41D /* SDCloudUserDefaults.framework */, + D06343232531DD0B004AB667 /* SDCloudUserDefaults_Swift.app */, ); name = Products; sourceTree = ""; @@ -195,6 +221,22 @@ name = "Supporting Files"; sourceTree = ""; }; + D06343242531DD0B004AB667 /* SDCloudUserDefaults_Swift */ = { + isa = PBXGroup; + children = ( + D0D08AE62531E46A00DE5072 /* SDCloudUserDefaults_Swift.entitlements */, + D063435A2531DD64004AB667 /* SDCloudUserDefaults.swift */, + D06343252531DD0B004AB667 /* AppDelegate.swift */, + D06343272531DD0B004AB667 /* SceneDelegate.swift */, + D06343292531DD0B004AB667 /* ViewController.swift */, + D063432B2531DD0B004AB667 /* Main.storyboard */, + D063432E2531DD0D004AB667 /* Assets.xcassets */, + D06343302531DD0D004AB667 /* LaunchScreen.storyboard */, + D06343332531DD0D004AB667 /* Info.plist */, + ); + path = SDCloudUserDefaults_Swift; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -288,12 +330,30 @@ productReference = C480297916909FFF0061EFF8 /* TestSDCloudUserDefaults.app */; productType = "com.apple.product-type.application"; }; + D06343222531DD0B004AB667 /* SDCloudUserDefaults_Swift */ = { + isa = PBXNativeTarget; + buildConfigurationList = D06343502531DD0D004AB667 /* Build configuration list for PBXNativeTarget "SDCloudUserDefaults_Swift" */; + buildPhases = ( + D063431F2531DD0B004AB667 /* Sources */, + D06343202531DD0B004AB667 /* Frameworks */, + D06343212531DD0B004AB667 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SDCloudUserDefaults_Swift; + productName = SDCloudUserDefaults_Swift; + productReference = D06343232531DD0B004AB667 /* SDCloudUserDefaults_Swift.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ C4802940169093EF0061EFF8 /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 1200; LastUpgradeCheck = 0450; ORGANIZATIONNAME = "Wandle Software Limited"; TargetAttributes = { @@ -303,6 +363,10 @@ 23BB07911BCA5EA2004DD41D = { CreatedOnToolsVersion = 7.0.1; }; + D06343222531DD0B004AB667 = { + CreatedOnToolsVersion = 12.0.1; + ProvisioningStyle = Automatic; + }; }; }; buildConfigurationList = C4802943169093EF0061EFF8 /* Build configuration list for PBXProject "SDCloudUserDefaults" */; @@ -310,7 +374,9 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, + Base, ); mainGroup = C480293E169093EF0061EFF8; productRefGroup = C480294A169093EF0061EFF8 /* Products */; @@ -321,6 +387,7 @@ C480297816909FFF0061EFF8 /* TestSDCloudUserDefaults */, 23BB07841BCA5E8A004DD41D /* SDCloudUserDefaults iOS */, 23BB07911BCA5EA2004DD41D /* SDCloudUserDefaults OSX */, + D06343222531DD0B004AB667 /* SDCloudUserDefaults_Swift */, ); }; /* End PBXProject section */ @@ -352,6 +419,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D06343212531DD0B004AB667 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D06343322531DD0D004AB667 /* LaunchScreen.storyboard in Resources */, + D063432F2531DD0D004AB667 /* Assets.xcassets in Resources */, + D063432D2531DD0B004AB667 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -389,6 +466,17 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D063431F2531DD0B004AB667 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D063432A2531DD0B004AB667 /* ViewController.swift in Sources */, + D063435B2531DD64004AB667 /* SDCloudUserDefaults.swift in Sources */, + D06343262531DD0B004AB667 /* AppDelegate.swift in Sources */, + D06343282531DD0B004AB667 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -416,6 +504,22 @@ name = MainStoryboard.storyboard; sourceTree = ""; }; + D063432B2531DD0B004AB667 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + D063432C2531DD0B004AB667 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + D06343302531DD0D004AB667 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + D06343312531DD0D004AB667 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -604,7 +708,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; @@ -624,7 +728,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; @@ -679,6 +783,122 @@ }; name = Release; }; + D063434A2531DD0D004AB667 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = SDCloudUserDefaults_Swift/SDCloudUserDefaults_Swift.entitlements; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = ""; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = SDCloudUserDefaults_Swift/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.pkclsoft.SDCloudUserDefaults-Swift"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TVOS_DEPLOYMENT_TARGET = 13.4; + }; + name = Debug; + }; + D063434B2531DD0D004AB667 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = SDCloudUserDefaults_Swift/SDCloudUserDefaults_Swift.entitlements; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ""; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = SDCloudUserDefaults_Swift/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.pkclsoft.SDCloudUserDefaults-Swift"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TVOS_DEPLOYMENT_TARGET = 13.4; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -689,6 +909,7 @@ 23BB078B1BCA5E8A004DD41D /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 23BB07971BCA5EA2004DD41D /* Build configuration list for PBXNativeTarget "SDCloudUserDefaults OSX" */ = { isa = XCConfigurationList; @@ -697,6 +918,7 @@ 23BB07991BCA5EA2004DD41D /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; C4802943169093EF0061EFF8 /* Build configuration list for PBXProject "SDCloudUserDefaults" */ = { isa = XCConfigurationList; @@ -725,6 +947,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D06343502531DD0D004AB667 /* Build configuration list for PBXNativeTarget "SDCloudUserDefaults_Swift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D063434A2531DD0D004AB667 /* Debug */, + D063434B2531DD0D004AB667 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = C4802940169093EF0061EFF8 /* Project object */; diff --git a/SDCloudUserDefaults.xcodeproj/xcshareddata/xcschemes/SDCloudUserDefaults OSX.xcscheme b/SDCloudUserDefaults.xcodeproj/xcshareddata/xcschemes/SDCloudUserDefaults OSX.xcscheme index bfa6b26..360be58 100644 --- a/SDCloudUserDefaults.xcodeproj/xcshareddata/xcschemes/SDCloudUserDefaults OSX.xcscheme +++ b/SDCloudUserDefaults.xcodeproj/xcshareddata/xcschemes/SDCloudUserDefaults OSX.xcscheme @@ -15,7 +15,7 @@ @@ -29,8 +29,6 @@ shouldUseLaunchSchemeArgsEnv = "YES"> - - - - diff --git a/SDCloudUserDefaults/SDCloudUserDefaults.m b/SDCloudUserDefaults/SDCloudUserDefaults.m index 36d031a..16f2c88 100644 --- a/SDCloudUserDefaults/SDCloudUserDefaults.m +++ b/SDCloudUserDefaults/SDCloudUserDefaults.m @@ -191,11 +191,19 @@ +(void)registerForNotifications { NSArray* changedKeys = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey]; for (NSString* key in changedKeys) { - [defaults setObject:[cloud objectForKey:key] forKey:key]; - - [[NSNotificationCenter defaultCenter] postNotificationName:SDCloudValueUpdatedNotification - object:self - userInfo:@{key:[cloud objectForKey:key]}]; + id obj = [cloud objectForKey:key]; + + [defaults setObject:obj forKey:key]; + + if (obj != nil) { + [[NSNotificationCenter defaultCenter] postNotificationName:SDCloudValueUpdatedNotification + object:self + userInfo:@{key:[cloud objectForKey:key]}]; + } else { + [[NSNotificationCenter defaultCenter] postNotificationName:SDCloudValueUpdatedNotification + object:self + userInfo:nil]; + } } diff --git a/SDCloudUserDefaults_Swift/AppDelegate.swift b/SDCloudUserDefaults_Swift/AppDelegate.swift new file mode 100644 index 0000000..f82cd42 --- /dev/null +++ b/SDCloudUserDefaults_Swift/AppDelegate.swift @@ -0,0 +1,42 @@ +// +// AppDelegate.swift +// SDCloudUserDefaults_Swift +// +// Created by Peter Easdown on 10/10/20. +// Copyright © 2020 Wandle Software Limited. All rights reserved. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + + SDCloudUserDefaults.shared.registerForNotifications() + + application.registerForRemoteNotifications() + + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/SDCloudUserDefaults_Swift/Assets.xcassets/AccentColor.colorset/Contents.json b/SDCloudUserDefaults_Swift/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/SDCloudUserDefaults_Swift/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SDCloudUserDefaults_Swift/Assets.xcassets/AppIcon.appiconset/Contents.json b/SDCloudUserDefaults_Swift/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/SDCloudUserDefaults_Swift/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SDCloudUserDefaults_Swift/Assets.xcassets/Contents.json b/SDCloudUserDefaults_Swift/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/SDCloudUserDefaults_Swift/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/SDCloudUserDefaults_Swift/Base.lproj/LaunchScreen.storyboard b/SDCloudUserDefaults_Swift/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/SDCloudUserDefaults_Swift/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SDCloudUserDefaults_Swift/Base.lproj/Main.storyboard b/SDCloudUserDefaults_Swift/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d8c6c0e --- /dev/null +++ b/SDCloudUserDefaults_Swift/Base.lproj/Main.storyboard @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SDCloudUserDefaults_Swift/Info.plist b/SDCloudUserDefaults_Swift/Info.plist new file mode 100644 index 0000000..2b43ebc --- /dev/null +++ b/SDCloudUserDefaults_Swift/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/SDCloudUserDefaults_Swift/SDCloudUserDefaults.swift b/SDCloudUserDefaults_Swift/SDCloudUserDefaults.swift new file mode 100644 index 0000000..e2b4db8 --- /dev/null +++ b/SDCloudUserDefaults_Swift/SDCloudUserDefaults.swift @@ -0,0 +1,228 @@ +// +// SDCloudUserDefaults.swift +// Tap Times Tables Swift +// +// Created by Peter Easdown on 9/10/20. +// + +import Foundation + +extension Notification.Name { + + static let SDCloudValueUpdatedNotification = Notification.Name(rawValue: "com.wandlesoftware.SDCloudUserDefaults.KeyValueUpdated") + +} + +class SDCloudUserDefaults { + + static let ICLOUD_DATA_ENABLED_KEY = "iCloudDataEnabled" + + static let shared = SDCloudUserDefaults() + + private var userDefaults : UserDefaults? = nil + + func setiCloud(enabled: Bool) { + UserDefaults.standard.set(enabled, forKey: SDCloudUserDefaults.ICLOUD_DATA_ENABLED_KEY) + + if enabled { + self.registerForNotifications() + } else { + self.removeNotifications() + } + } + + func hasiCloudBeenInitialized() -> Bool { + return UserDefaults.standard.object(forKey: SDCloudUserDefaults.ICLOUD_DATA_ENABLED_KEY) != nil + } + + func isiCloudEnabled() -> Bool { + return UserDefaults.standard.bool(forKey: SDCloudUserDefaults.ICLOUD_DATA_ENABLED_KEY) + } + + init() { + if self.hasiCloudBeenInitialized() { + if self.isiCloudEnabled() { + self.registerForNotifications() + } else { + self.removeNotifications() + } + } + } + + func standardUserDefaults() -> UserDefaults { + if self.userDefaults == nil { + self.userDefaults = UserDefaults.standard + } + + return self.userDefaults! + } + + func string(forKey aKey: String) -> String? { + if let obj = self.object(forKey: aKey) { + if obj is String { + return obj as? String + } + } + + return nil + } + + func bool(forKey aKey: String) -> Bool { + if let obj = self.object(forKey: aKey) { + if obj is Bool { + return obj as! Bool + } + } + + return false + } + + func object(forKey aKey: String) -> Any? { + if self.isiCloudEnabled() { + if let obj = NSUbiquitousKeyValueStore.default.object(forKey: aKey) { + return obj + } else { + if let obj = self.standardUserDefaults().object(forKey: aKey) { + NSUbiquitousKeyValueStore.default.set(obj, forKey: aKey) + + return obj + } else { + return nil + } + } + } else { + return self.standardUserDefaults().object(forKey: aKey) + } + } + + func array(forKey aKey: String) -> Array? { + if let obj = self.object(forKey: aKey) { + if obj is Array { + return obj as? Array + } + } + + return nil + } + + func data(forKey aKey: String) -> Data? { + if let obj = self.object(forKey: aKey) { + if obj is Data { + return obj as? Data + } + } + + return nil + } + + func integer(forKey aKey: String) -> Int { + if let obj = self.object(forKey: aKey) { + if obj is Int { + return obj as! Int + } + } + + return 0 + } + + func float(forKey aKey: String) -> Float { + if let obj = self.object(forKey: aKey) { + if obj is Float { + return obj as! Float + } + } + + return 0.0 + } + + func double(forKey aKey: String) -> Double { + if let obj = self.object(forKey: aKey) { + if obj is Double { + return obj as! Double + } + } + + return 0.0 + } + + func set(string aString: String, forKey aKey: String) { + self.set(aString, forKey:aKey) + } + + func set(_ aBool: Bool, forKey aKey: String) { + self.set(NSNumber(booleanLiteral: aBool), forKey: aKey) + } + + func set(_ object: Any, forKey aKey: String) { + if self.isiCloudEnabled() { + NSUbiquitousKeyValueStore.default.set(object, forKey: aKey) + } + + self.userDefaults?.set(object, forKey: aKey) + } + + func set(_ integer: Int, forKey aKey: String) { + self.set(NSNumber(integerLiteral: integer), forKey: aKey) + } + + func set(_ float: Float, forKey aKey: String) { + self.set(NSNumber(floatLiteral: Double(float)), forKey: aKey) + } + + func set(_ double: Double, forKey aKey: String) { + self.set(NSNumber(floatLiteral: double), forKey: aKey) + } + + func removeObject(forKey aKey: String) { + if self.isiCloudEnabled() { + NSUbiquitousKeyValueStore.default.removeObject(forKey: aKey) + } + + self.userDefaults?.removeObject(forKey: aKey) + } + + func synchronize() { + if self.isiCloudEnabled() { + NSUbiquitousKeyValueStore.default.synchronize() + } + + self.userDefaults?.synchronize() + } + + var notificationObserver : NSObjectProtocol? = nil + + func registerForNotifications() { + if self.notificationObserver != nil { + return + } + + self.notificationObserver = NotificationCenter.default.addObserver(forName: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: NSUbiquitousKeyValueStore.default, queue: nil, using: { (notification) in + if let userInfo = notification.userInfo { + if let reasonForChange = userInfo[NSUbiquitousKeyValueStoreChangeReasonKey] { + let reason = (reasonForChange as! NSNumber).intValue + + // Update only for changes from the server. + if ((reason == NSUbiquitousKeyValueStoreServerChange) || + (reason == NSUbiquitousKeyValueStoreInitialSyncChange)) { + + let changedKeys = userInfo[NSUbiquitousKeyValueStoreChangedKeysKey] as! Array + let cloud = NSUbiquitousKeyValueStore.default + let defaults = self.userDefaults + + changedKeys.forEach { (key) in + if let obj = cloud.object(forKey: key) { + defaults?.setValue(obj, forKey: key) + NotificationCenter.default.post(name: .SDCloudValueUpdatedNotification, object: self, userInfo: [key: obj]) + } + } + } + } + } + }) + } + + func removeNotifications() { + NotificationCenter.default.removeObserver(self.notificationObserver!) + self.notificationObserver = nil + } +} diff --git a/SDCloudUserDefaults_Swift/SDCloudUserDefaults_Swift.entitlements b/SDCloudUserDefaults_Swift/SDCloudUserDefaults_Swift.entitlements new file mode 100644 index 0000000..c280ba7 --- /dev/null +++ b/SDCloudUserDefaults_Swift/SDCloudUserDefaults_Swift.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.icloud-container-identifiers + + com.apple.developer.ubiquity-kvstore-identifier + $(TeamIdentifierPrefix)$(CFBundleIdentifier) + + diff --git a/SDCloudUserDefaults_Swift/SceneDelegate.swift b/SDCloudUserDefaults_Swift/SceneDelegate.swift new file mode 100644 index 0000000..d550599 --- /dev/null +++ b/SDCloudUserDefaults_Swift/SceneDelegate.swift @@ -0,0 +1,53 @@ +// +// SceneDelegate.swift +// SDCloudUserDefaults_Swift +// +// Created by Peter Easdown on 10/10/20. +// Copyright © 2020 Wandle Software Limited. All rights reserved. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/SDCloudUserDefaults_Swift/ViewController.swift b/SDCloudUserDefaults_Swift/ViewController.swift new file mode 100644 index 0000000..31e3bcb --- /dev/null +++ b/SDCloudUserDefaults_Swift/ViewController.swift @@ -0,0 +1,51 @@ +// +// ViewController.swift +// SDCloudUserDefaults_Swift +// +// Created by Peter Easdown on 10/10/20. +// Copyright © 2020 Wandle Software Limited. All rights reserved. +// + +import UIKit + +class ViewController: UIViewController, UITextFieldDelegate { + + @IBOutlet weak var keyNameTextField: UITextField! + @IBOutlet weak var valueTextField: UITextField! + @IBOutlet weak var enabledSwitch: UISwitch! + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + + NotificationCenter.default.addObserver(forName: Notification.Name.SDCloudValueUpdatedNotification, object: nil, queue: nil) { (notification) in + notification.userInfo?.keys.forEach({ (key) in + if (key as! String) == self.keyNameTextField.text { + self.valueTextField.text = (notification.userInfo![key as! String] as! String) + } + }) + } + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + if string == "\n" { + textField.resignFirstResponder() + return false + } else { + return true + } + } + + func textFieldDidEndEditing(_ textField: UITextField) { + if textField == self.keyNameTextField { + self.valueTextField.text = SDCloudUserDefaults.shared.string(forKey: textField.text!) + } else if (textField == self.valueTextField) { + SDCloudUserDefaults.shared.set(textField.text!, forKey: self.keyNameTextField.text!) + } + } + + @IBAction func switchChanged(_ sender: Any) { + SDCloudUserDefaults.shared.setiCloud(enabled: self.enabledSwitch.isOn) + } +} +