From 1511a0ed264d7987f754a262e9d9fa50c9facfc1 Mon Sep 17 00:00:00 2001 From: Francesco <100066266+cranci1@users.noreply.github.com> Date: Thu, 24 Apr 2025 21:32:30 +0200 Subject: [PATCH] icloud safe checking --- .../iCloudSyncManager/iCloudSyncManager.swift | 143 ++++++++++-------- Sora/Views/LibraryView/LibraryManager.swift | 2 +- 2 files changed, 82 insertions(+), 63 deletions(-) diff --git a/Sora/Utils/iCloudSyncManager/iCloudSyncManager.swift b/Sora/Utils/iCloudSyncManager/iCloudSyncManager.swift index 595bee5..1a9fcae 100644 --- a/Sora/Utils/iCloudSyncManager/iCloudSyncManager.swift +++ b/Sora/Utils/iCloudSyncManager/iCloudSyncManager.swift @@ -10,6 +10,7 @@ import UIKit class iCloudSyncManager { static let shared = iCloudSyncManager() + private let syncQueue = DispatchQueue(label: "me.cranci.sora.icloud-sync", qos: .utility) private let defaultsToSync: [String] = [ "externalPlayer", "alwaysLandscape", @@ -43,20 +44,92 @@ class iCloudSyncManager { private init() { setupSync() - NotificationCenter.default.addObserver(self, selector: #selector(willEnterBackground), name: UIApplication.willResignActiveNotification, object: nil) + NotificationCenter.default.addObserver(self, + selector: #selector(willEnterBackground), + name: UIApplication.willResignActiveNotification, + object: nil) } private func setupSync() { - NSUbiquitousKeyValueStore.default.synchronize() - syncFromiCloud() - syncModulesFromiCloud() - NotificationCenter.default.addObserver(self, selector: #selector(iCloudDidChangeExternally), name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: NSUbiquitousKeyValueStore.default) - NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange), name: UserDefaults.didChangeNotification, object: nil) + syncQueue.async { [weak self] in + guard let self = self else { return } + + NSUbiquitousKeyValueStore.default.synchronize() + self.syncFromiCloud() + self.syncModulesFromiCloud() + + DispatchQueue.main.async { + NotificationCenter.default.addObserver(self, + selector: #selector(self.iCloudDidChangeExternally), + name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, + object: NSUbiquitousKeyValueStore.default) + + NotificationCenter.default.addObserver(self, + selector: #selector(self.userDefaultsDidChange), + name: UserDefaults.didChangeNotification, + object: nil) + } + } + } + + @objc private func userDefaultsDidChange(_ notification: Notification) { + syncQueue.async { [weak self] in + self?.syncToiCloud() + } + } + + private func syncToiCloud() { + let iCloud = NSUbiquitousKeyValueStore.default + let defaults = UserDefaults.standard + + do { + for key in allKeysToSync() { + if let value = defaults.object(forKey: key) { + if isValidValueType(value) { + iCloud.set(value, forKey: key) + } + } + } + + iCloud.synchronize() + } catch { + Logger.shared.log("Failed to sync to iCloud: \(error)", type: "Error") + } + } + + private func syncFromiCloud() { + let iCloud = NSUbiquitousKeyValueStore.default + let defaults = UserDefaults.standard + + for key in allKeysToSync() { + if let value = iCloud.object(forKey: key) { + if isValidValueType(value) { + defaults.set(value, forKey: key) + } + } + } + + defaults.synchronize() + NotificationCenter.default.post(name: .iCloudSyncDidComplete, object: nil) + } + + private func isValidValueType(_ value: Any) -> Bool { + return value is String || + value is Bool || + value is Int || + value is Float || + value is Double || + value is Data || + value is Date || + value is [Any] || + value is [String: Any] } @objc private func willEnterBackground() { - syncToiCloud() - syncModulesToiCloud() + syncQueue.async { [weak self] in + self?.syncToiCloud() + self?.syncModulesToiCloud() + } } private func allProgressKeys() -> [String] { @@ -80,60 +153,6 @@ class iCloudSyncManager { return Array(keys) } - private func syncFromiCloud() { - let iCloud = NSUbiquitousKeyValueStore.default - let defaults = UserDefaults.standard - - for key in allKeysToSync() { - if let value = iCloud.object(forKey: key) { - if (value is String) || (value is Bool) || (value is Int) || (value is Float) || (value is Double) || (value is Data) || (value is Date) || (value is Array) || (value is Dictionary) { - defaults.set(value, forKey: key) - } else { - Logger.shared.log("Skipped syncing invalid value type for key: \(key)", type: "Error") - } - } - } - - defaults.synchronize() - NotificationCenter.default.post(name: .iCloudSyncDidComplete, object: nil) - } - - private func syncToiCloud() { - let iCloud = NSUbiquitousKeyValueStore.default - let defaults = UserDefaults.standard - - for key in allKeysToSync() { - if let value = defaults.object(forKey: key) { - iCloud.set(value, forKey: key) - } - } - - iCloud.synchronize() - } - - @objc private func iCloudDidChangeExternally(_ notification: Notification) { - do { - guard let userInfo = notification.userInfo, - let reason = userInfo[NSUbiquitousKeyValueStoreChangeReasonKey] as? Int else { - return - } - - if reason == NSUbiquitousKeyValueStoreServerChange || - reason == NSUbiquitousKeyValueStoreInitialSyncChange { - DispatchQueue.main.async { [weak self] in - self?.syncFromiCloud() - self?.syncModulesFromiCloud() - } - } - } catch { - Logger.shared.log("Error handling iCloud sync: \(error.localizedDescription)", type: "Error") - } - } - - @objc private func userDefaultsDidChange(_ notification: Notification) { - syncToiCloud() - } - func syncModulesToiCloud() { DispatchQueue.global(qos: .background).async { [weak self] in guard let self = self, let iCloudURL = self.ubiquityContainerURL else { return } diff --git a/Sora/Views/LibraryView/LibraryManager.swift b/Sora/Views/LibraryView/LibraryManager.swift index 6e8e3d3..4f18ef2 100644 --- a/Sora/Views/LibraryView/LibraryManager.swift +++ b/Sora/Views/LibraryView/LibraryManager.swift @@ -69,7 +69,7 @@ class LibraryManager: ObservableObject { let encoded = try JSONEncoder().encode(bookmarks) UserDefaults.standard.set(encoded, forKey: bookmarksKey) } catch { - Logger.shared.log("Failed to encode bookmarks: \(error.localizedDescription)", type: "Error") + Logger.shared.log("Failed to save bookmarks: \(error)", type: "Error") } }