From 04969a5aa22a5a86a917d58e13bbe2d82a17c71d Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Mon, 15 Apr 2024 18:36:12 +0200 Subject: [PATCH] Move initial subscription logic into Core --- Package.swift | 1 + Realm.podspec | 1 + Realm.xcodeproj/project.pbxproj | 10 ++++ .../xcschemes/Object Server Tests.xcscheme | 10 ++++ Realm/ObjectServerTests/AsyncSyncTests.swift | 58 +++++++++++++++++++ Realm/RLMInitialSubscriptionsConfiguration.h | 45 ++++++++++++++ Realm/RLMInitialSubscriptionsConfiguration.m | 36 ++++++++++++ Realm/RLMRealm.mm | 19 +----- Realm/RLMRealmConfiguration.h | 7 --- Realm/RLMRealmConfiguration.mm | 2 - Realm/RLMRealmConfiguration_Private.h | 4 -- Realm/RLMSyncConfiguration.h | 7 +++ Realm/RLMSyncConfiguration.mm | 44 ++++++++++++++ Realm/RLMUser.mm | 10 ++-- Realm/Realm.h | 1 + Realm/Realm.modulemap | 1 + RealmSwift/RealmConfiguration.swift | 16 ----- RealmSwift/Sync.swift | 27 +++++++++ .../RLMInitialSubscriptionsConfiguration.h | 1 + 19 files changed, 247 insertions(+), 53 deletions(-) create mode 100644 Realm/RLMInitialSubscriptionsConfiguration.h create mode 100644 Realm/RLMInitialSubscriptionsConfiguration.m create mode 120000 include/Realm/RLMInitialSubscriptionsConfiguration.h diff --git a/Package.swift b/Package.swift index 28c3c2e1c8..6cc8ca6f1e 100644 --- a/Package.swift +++ b/Package.swift @@ -244,6 +244,7 @@ let package = Package( "Realm/RLMEmailPasswordAuth.mm", "Realm/RLMFindOneAndModifyOptions.mm", "Realm/RLMFindOptions.mm", + "Realm/RLMInitialSubscriptionsConfiguration.m", "Realm/RLMMongoClient.mm", "Realm/RLMMongoCollection.mm", "Realm/RLMNetworkTransport.mm", diff --git a/Realm.podspec b/Realm.podspec index 97de5736ca..c93224dc08 100644 --- a/Realm.podspec +++ b/Realm.podspec @@ -55,6 +55,7 @@ Pod::Spec.new do |s| 'include/RLMApp.h', 'include/RLMAppCredentials.h', 'include/RLMBSON.h', + 'include/RLMInitialSubscriptionsConfiguration.h', 'include/RLMNetworkTransport.h', 'include/RLMPushClient.h', 'include/RLMProviderClient.h', diff --git a/Realm.xcodeproj/project.pbxproj b/Realm.xcodeproj/project.pbxproj index 8a37306e83..5d9f090e83 100644 --- a/Realm.xcodeproj/project.pbxproj +++ b/Realm.xcodeproj/project.pbxproj @@ -53,9 +53,12 @@ 0C3BD4B325C1BDF1007CFDD3 /* RLMDictionary.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BD4B125C1BDF1007CFDD3 /* RLMDictionary.mm */; }; 0C3BD4D325C1C5AB007CFDD3 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BD4D225C1C5AB007CFDD3 /* Map.swift */; }; 0C5796A225643D7500744CAE /* RLMUUID.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0C57969F25643D7500744CAE /* RLMUUID.mm */; }; + 0C63BB902BCD787300E25C3A /* RLMInitialSubscriptionsConfiguration.h in Sources */ = {isa = PBXBuildFile; fileRef = 0CC270AB2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h */; }; 0C86B33925E15B6000775FED /* PrimitiveDictionaryPropertyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C86B33825E15B6000775FED /* PrimitiveDictionaryPropertyTests.m */; }; 0C9758BF264974660097B48D /* SwiftRLMDictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C9758BE264974660097B48D /* SwiftRLMDictionaryTests.swift */; }; 0CBF2DB927286FFD00635902 /* ProjectedCollectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBF2DB827286FFD00635902 /* ProjectedCollectTests.swift */; }; + 0CC270AA2BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CC270A92BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m */; }; + 0CC270AC2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC270AB2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0CD1632826D3DF1D0027C49B /* ProjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD1632726D3DF1C0027C49B /* ProjectionTests.swift */; }; 0CED6DB82655087200B80277 /* RLMDictionary_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C3BD50125C1DE6F007CFDD3 /* RLMDictionary_Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1A0512771D8746CD00806AEC /* RLMSyncConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A3623651D8384BA00945A54 /* RLMSyncConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -628,6 +631,8 @@ 0C86B33825E15B6000775FED /* PrimitiveDictionaryPropertyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrimitiveDictionaryPropertyTests.m; sourceTree = ""; }; 0C9758BE264974660097B48D /* SwiftRLMDictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftRLMDictionaryTests.swift; sourceTree = ""; }; 0CBF2DB827286FFD00635902 /* ProjectedCollectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectedCollectTests.swift; sourceTree = ""; }; + 0CC270A92BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RLMInitialSubscriptionsConfiguration.m; sourceTree = ""; }; + 0CC270AB2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RLMInitialSubscriptionsConfiguration.h; sourceTree = ""; }; 0CD1632526D3DD7B0027C49B /* Projection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Projection.swift; sourceTree = ""; }; 0CD1632726D3DF1C0027C49B /* ProjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProjectionTests.swift; sourceTree = ""; }; 1A0512731D87413000806AEC /* RLMSyncUtil_Private.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RLMSyncUtil_Private.hpp; sourceTree = ""; }; @@ -1200,6 +1205,8 @@ 4993220324129DCD00A0EC8E /* RLMCredentials.h */, 4993220424129DCD00A0EC8E /* RLMCredentials.mm */, 4993220224129DCD00A0EC8E /* RLMCredentials_Private.hpp */, + 0CC270AB2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h */, + 0CC270A92BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m */, 4993221524129E6600A0EC8E /* RLMNetworkTransport.h */, 4993221424129E6500A0EC8E /* RLMNetworkTransport.mm */, CF330BBB24E56E3A00F07EE2 /* RLMNetworkTransport_Private.hpp */, @@ -1906,6 +1913,7 @@ 6807E64F2487F9210096066F /* RLMPushClient_Private.hpp in Headers */, 1AD397CF1F72FFC7002AA897 /* RLMRealm+Sync.h in Headers */, 5D659EBF1BE04556006515A0 /* RLMRealm.h in Headers */, + 0CC270AC2BCD665800788EE1 /* RLMInitialSubscriptionsConfiguration.h in Headers */, 5D659EC01BE04556006515A0 /* RLMRealm_Dynamic.h in Headers */, 5D659EC11BE04556006515A0 /* RLMRealm_Private.h in Headers */, 5D659EC21BE04556006515A0 /* RLMRealmConfiguration.h in Headers */, @@ -2454,6 +2462,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0C63BB902BCD787300E25C3A /* RLMInitialSubscriptionsConfiguration.h in Sources */, 3F73BC961E3A878500FE80B6 /* NSError+RLMSync.m in Sources */, 5D659E851BE04556006515A0 /* RLMAccessor.mm in Sources */, 5D659E861BE04556006515A0 /* RLMAnalytics.mm in Sources */, @@ -2513,6 +2522,7 @@ 531F956C27906F7600E497F1 /* RLMSyncSubscription.mm in Sources */, 1A84132F1D4BCCE600C5326F /* RLMSyncUtil.mm in Sources */, 3F67DB3E1E26D69C0024533D /* RLMThreadSafeReference.mm in Sources */, + 0CC270AA2BCD664200788EE1 /* RLMInitialSubscriptionsConfiguration.m in Sources */, 5D659E9A1BE04556006515A0 /* RLMUpdateChecker.mm in Sources */, CF76F7DD24816AAB00890DD2 /* RLMUpdateResult.mm in Sources */, 1ABDCDB01D793008003489E3 /* RLMUser.mm in Sources */, diff --git a/Realm.xcodeproj/xcshareddata/xcschemes/Object Server Tests.xcscheme b/Realm.xcodeproj/xcshareddata/xcschemes/Object Server Tests.xcscheme index 3933ee1c8e..cf0fe212ea 100644 --- a/Realm.xcodeproj/xcshareddata/xcschemes/Object Server Tests.xcscheme +++ b/Realm.xcodeproj/xcshareddata/xcschemes/Object Server Tests.xcscheme @@ -109,6 +109,16 @@ value = "1" isEnabled = "YES"> + + + + () { + $0.age > 10 && $0.firstName == "\(self.name)" + }) + }) + config.objectTypes = [SwiftPerson.self] + let realm = try await Realm(configuration: config, downloadBeforeOpen: .once) + XCTAssertEqual(realm.subscriptions.count, 1) + + let realm2 = try await Realm(configuration: config, downloadBeforeOpen: .once) + XCTAssertNotNil(realm2) + XCTAssertEqual(realm.subscriptions.count, 1) + } + + @MainActor + func testFlexibleSyncInitialSubscriptionsConfiguredViaPropertyRerunOnOpen() async throws { + let user = try await createUser() + var config = user.flexibleSyncConfiguration() + let invocations = Locked(0) + config.syncConfiguration!.initialSubscriptions = InitialSubscriptionsConfiguration(callback: { subscriptions in + invocations.withLock { invocations in + invocations += 1 + } + subscriptions.append(QuerySubscription() { + $0.age > invocations.wrappedValue + }) + }, rerunOnOpen: true) + config.objectTypes = [SwiftPerson.self] + + let c = config + try await Task { + let realm = try await Realm(configuration: c, downloadBeforeOpen: .once) + XCTAssertEqual(realm.subscriptions.count, 1) + }.value + + try await Task { + let realm = try await Realm(configuration: c, downloadBeforeOpen: .once) + XCTAssertEqual(realm.subscriptions.count, 2) + }.value + + XCTAssertEqual(invocations.wrappedValue, 2) + } + + // MARK: Subscribe @MainActor diff --git a/Realm/RLMInitialSubscriptionsConfiguration.h b/Realm/RLMInitialSubscriptionsConfiguration.h new file mode 100644 index 0000000000..0ce01b124b --- /dev/null +++ b/Realm/RLMInitialSubscriptionsConfiguration.h @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2024 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + + +#import +#import + +RLM_HEADER_AUDIT_BEGIN(nullability, sendability) + +/** + A block which receives a subscription set instance, that can be used to add an initial set of subscriptions which will be executed + when the Realm is first opened. + */ +RLM_SWIFT_SENDABLE +typedef void(^RLMFlexibleSyncInitialSubscriptionsBlock)(RLMSyncSubscriptionSet * _Nonnull subscriptions); + +@interface RLMInitialSubscriptionsConfiguration : NSObject + +/** + A callback that's executed when a Realm is first created or every time it's opened if `rerunOnOpen` is true. + */ +@property (nonatomic, readonly) RLMFlexibleSyncInitialSubscriptionsBlock callback; +@property (nonatomic, readonly) BOOL rerunOnOpen; + +-(id)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback rerunOnOpen: (BOOL)rerunOnOpen; +-(id)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback; + +@end + +RLM_HEADER_AUDIT_END(nullability, sendability) diff --git a/Realm/RLMInitialSubscriptionsConfiguration.m b/Realm/RLMInitialSubscriptionsConfiguration.m new file mode 100644 index 0000000000..ebb6800a54 --- /dev/null +++ b/Realm/RLMInitialSubscriptionsConfiguration.m @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2024 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + + +#import "RLMInitialSubscriptionsConfiguration.h" + +@implementation RLMInitialSubscriptionsConfiguration + +-(id)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback +{ + return [self initWithCallback: callback rerunOnOpen: false]; +} + +-(id)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback rerunOnOpen: (BOOL)rerunOnOpen +{ + _callback = callback; + _rerunOnOpen = rerunOnOpen; + return self; +} + +@end diff --git a/Realm/RLMRealm.mm b/Realm/RLMRealm.mm index 9a84a67b80..c5e177eb2c 100644 --- a/Realm/RLMRealm.mm +++ b/Realm/RLMRealm.mm @@ -447,7 +447,6 @@ + (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration } } - bool isFirstOpen = false; if (realm->_schema) { } else if (dynamic) { realm->_schema = [RLMSchema dynamicSchemaFromObjectStoreSchema:realm->_realm->schema()]; @@ -482,16 +481,9 @@ + (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration }; } - DataInitializationFunction initializationFunction; - if (!configuration.rerunOnOpen && configuration.initialSubscriptions) { - initializationFunction = [&isFirstOpen](SharedRealm) { - isFirstOpen = true; - }; - } - try { realm->_realm->update_schema(schema.objectStoreCopy, config.schema_version, - std::move(migrationFunction), std::move(initializationFunction)); + std::move(migrationFunction)); } catch (...) { RLMRealmTranslateException(error); @@ -522,15 +514,6 @@ + (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration realm->_realm->m_binding_context->realm = realm->_realm; } -#if REALM_ENABLE_SYNC - if (isFirstOpen || (configuration.rerunOnOpen && !realmIsCached)) { - RLMSyncSubscriptionSet *subscriptions = realm.subscriptions; - [subscriptions update:^{ - configuration.initialSubscriptions(subscriptions); - }]; - } -#endif - // Run Analytics and Update checker, this will be run only the first any realm open [self runFirstCheckForConfiguration:configuration schema:realm.schema]; diff --git a/Realm/RLMRealmConfiguration.h b/Realm/RLMRealmConfiguration.h index 4cfbbf3445..55b4689a7c 100644 --- a/Realm/RLMRealmConfiguration.h +++ b/Realm/RLMRealmConfiguration.h @@ -34,13 +34,6 @@ RLM_HEADER_AUDIT_BEGIN(nullability, sendability) RLM_SWIFT_SENDABLE typedef BOOL (^RLMShouldCompactOnLaunchBlock)(NSUInteger totalBytes, NSUInteger bytesUsed); -/** - A block which receives a subscription set instance, that can be used to add an initial set of subscriptions which will be executed - when the Realm is first opened. - */ -RLM_SWIFT_SENDABLE -typedef void(^RLMFlexibleSyncInitialSubscriptionsBlock)(RLMSyncSubscriptionSet * _Nonnull subscriptions); - /** An `RLMRealmConfiguration` instance describes the different options used to create an instance of a Realm. diff --git a/Realm/RLMRealmConfiguration.mm b/Realm/RLMRealmConfiguration.mm index bfeeadace7..c60372aaba 100644 --- a/Realm/RLMRealmConfiguration.mm +++ b/Realm/RLMRealmConfiguration.mm @@ -130,8 +130,6 @@ - (instancetype)copyWithZone:(NSZone *)zone { configuration->_customSchema = _customSchema; configuration->_eventConfiguration = _eventConfiguration; configuration->_migrationObjectClass = _migrationObjectClass; - configuration->_initialSubscriptions = _initialSubscriptions; - configuration->_rerunOnOpen = _rerunOnOpen; return configuration; } diff --git a/Realm/RLMRealmConfiguration_Private.h b/Realm/RLMRealmConfiguration_Private.h index 12b09676d0..b4a22cd7b4 100644 --- a/Realm/RLMRealmConfiguration_Private.h +++ b/Realm/RLMRealmConfiguration_Private.h @@ -33,10 +33,6 @@ RLM_HEADER_AUDIT_BEGIN(nullability) @property (nonatomic, nullable) Class migrationObjectClass; @property (nonatomic) bool disableAutomaticChangeNotifications; -// Flexible Sync -@property (nonatomic, readwrite, nullable) RLMFlexibleSyncInitialSubscriptionsBlock initialSubscriptions; -@property (nonatomic, readwrite) BOOL rerunOnOpen; - // Get the default configuration without copying it + (RLMRealmConfiguration *)rawDefaultConfiguration; diff --git a/Realm/RLMSyncConfiguration.h b/Realm/RLMSyncConfiguration.h index 54ea2ecfce..47e3f7f198 100644 --- a/Realm/RLMSyncConfiguration.h +++ b/Realm/RLMSyncConfiguration.h @@ -19,11 +19,13 @@ #import #import +#import @class RLMApp; @class RLMRealm; @class RLMRealmConfiguration; @class RLMUser; +@class RLMInitialSubscriptionsConfiguration; @protocol RLMBSON; RLM_HEADER_AUDIT_BEGIN(nullability, sendability) @@ -175,6 +177,11 @@ typedef void(^RLMClientResetAfterBlock)(RLMRealm * _Nonnull beforeFrozen, RLMRea */ @property (nonatomic, nullable) RLMSyncErrorReportingBlock manualClientResetHandler; +/** + A configuration that controls how initial subscriptions are populated when the Realm is opened. + @see `RLMInitialSubscriptionsConfiguration` + */ +@property (nonatomic, readwrite, nullable) RLMInitialSubscriptionsConfiguration *initialSubscriptions; /** Whether nonfatal connection errors should cancel async opens. diff --git a/Realm/RLMSyncConfiguration.mm b/Realm/RLMSyncConfiguration.mm index 10188dffc3..109a7527c0 100644 --- a/Realm/RLMSyncConfiguration.mm +++ b/Realm/RLMSyncConfiguration.mm @@ -21,6 +21,7 @@ #import "RLMApp_Private.hpp" #import "RLMBSON_Private.hpp" #import "RLMError_Private.hpp" +#import "RLMInitialSubscriptionsConfiguration.h" #import "RLMRealm_Private.hpp" #import "RLMRealmConfiguration_Private.h" #import "RLMRealmConfiguration_Private.hpp" @@ -28,6 +29,7 @@ #import "RLMSchema_Private.hpp" #import "RLMSyncManager_Private.hpp" #import "RLMSyncSession_Private.hpp" +#import "RLMSyncSubscription.h" #import "RLMSyncUtil_Private.hpp" #import "RLMUser_Private.hpp" #import "RLMUtil.hpp" @@ -80,6 +82,23 @@ void operator()(std::shared_ptr local, ThreadSafeReference remote, bool) } } }; + +struct InitialSubscriptionsWrapper : CallbackSchema { + RLMFlexibleSyncInitialSubscriptionsBlock block; + void operator()(std::shared_ptr local) { + @autoreleasepool { + RLMRealm *realm = [RLMRealm realmWithSharedRealm:local + schema:customSchema + dynamic:dynamic + freeze:false]; + + RLMSyncSubscriptionSet* subscriptions = realm.subscriptions; + [subscriptions update:^{ + block(subscriptions); + }]; + } + } +}; } // anonymous namespace @interface RLMSyncConfiguration () { @@ -190,6 +209,26 @@ - (void)setManualClientResetHandler:(RLMSyncErrorReportingBlock)manualClientRese [self assignConfigErrorHandler:self.user]; } +- (RLMInitialSubscriptionsConfiguration *)initialSubscriptions { + if (_config->subscription_initializer) { + auto wrapper = _config->subscription_initializer.target(); + + return [[RLMInitialSubscriptionsConfiguration alloc] initWithCallback: wrapper->block + rerunOnOpen: _config->rerun_init_subscription_on_open]; + } + + return nil; +} + +- (void)setInitialSubscriptions:(RLMInitialSubscriptionsConfiguration *)initialSubscriptions { + if (initialSubscriptions) { + _config->subscription_initializer = InitialSubscriptionsWrapper{.block = initialSubscriptions.callback}; + _config->rerun_init_subscription_on_open = initialSubscriptions.rerunOnOpen; + } else { + _config->subscription_initializer = nil; + } +} + void RLMSetConfigInfoForClientResetCallbacks(realm::SyncConfig& syncConfig, RLMRealmConfiguration *config) { if (syncConfig.notify_before_client_reset) { auto before = syncConfig.notify_before_client_reset.target(); @@ -201,6 +240,11 @@ void RLMSetConfigInfoForClientResetCallbacks(realm::SyncConfig& syncConfig, RLMR after->dynamic = config.dynamic; after->customSchema = config.customSchema; } + if (syncConfig.subscription_initializer) { + auto initializer = syncConfig.subscription_initializer.target(); + initializer->dynamic = config.dynamic; + initializer->customSchema = config.customSchema; + } } - (id)partitionValue { diff --git a/Realm/RLMUser.mm b/Realm/RLMUser.mm index 4a94ecd8e3..a59d8fb45a 100644 --- a/Realm/RLMUser.mm +++ b/Realm/RLMUser.mm @@ -151,9 +151,8 @@ - (RLMRealmConfiguration *)flexibleSyncConfigurationWithClientResetMode:(RLMClie - (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions rerunOnOpen:(BOOL)rerunOnOpen { auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; + syncConfig.initialSubscriptions = [[RLMInitialSubscriptionsConfiguration alloc] initWithCallback:initialSubscriptions rerunOnOpen:rerunOnOpen]; RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; - config.initialSubscriptions = initialSubscriptions; - config.rerunOnOpen = rerunOnOpen; config.syncConfiguration = syncConfig; return config; } @@ -168,8 +167,8 @@ - (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RL syncConfig.clientResetMode = clientResetMode; syncConfig.beforeClientReset = beforeResetBlock; syncConfig.afterClientReset = afterResetBlock; - config.initialSubscriptions = initialSubscriptions; - config.rerunOnOpen = rerunOnOpen; + syncConfig.initialSubscriptions = [[RLMInitialSubscriptionsConfiguration alloc] initWithCallback:initialSubscriptions rerunOnOpen:rerunOnOpen]; + config.syncConfiguration = syncConfig; return config; } @@ -182,8 +181,7 @@ - (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RL RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; syncConfig.clientResetMode = clientResetMode; syncConfig.manualClientResetHandler = manualClientResetHandler; - config.initialSubscriptions = initialSubscriptions; - config.rerunOnOpen = rerunOnOpen; + syncConfig.initialSubscriptions = [[RLMInitialSubscriptionsConfiguration alloc] initWithCallback:initialSubscriptions rerunOnOpen:rerunOnOpen]; config.syncConfiguration = syncConfig; return config; } diff --git a/Realm/Realm.h b/Realm/Realm.h index 71408b498c..34f1679bc8 100644 --- a/Realm/Realm.h +++ b/Realm/Realm.h @@ -48,6 +48,7 @@ #import #import #import +#import #import #import #import diff --git a/Realm/Realm.modulemap b/Realm/Realm.modulemap index a1538d1088..e7cbca362f 100644 --- a/Realm/Realm.modulemap +++ b/Realm/Realm.modulemap @@ -27,6 +27,7 @@ framework module Realm { header "RLMApp.h" header "RLMCredentials.h" + header "RLMInitialSubscriptionsConfiguration.h" header "RLMNetworkTransport.h" header "RLMPushClient.h" header "RLMRealm+Sync.h" diff --git a/RealmSwift/RealmConfiguration.swift b/RealmSwift/RealmConfiguration.swift index 226d82193f..c25c996688 100644 --- a/RealmSwift/RealmConfiguration.swift +++ b/RealmSwift/RealmConfiguration.swift @@ -268,14 +268,6 @@ extension Realm { /// If `true`, disables automatic format upgrades when accessing the Realm. internal var disableFormatUpgrade: Bool = false - // MARK: Flexible Sync - - /// Callback for adding subscriptions to the initialization of the Realm - internal var initialSubscriptions: (@Sendable (SyncSubscriptionSet) -> Void)? - - /// If `true` Indicates that the `initialSubscriptions` will run on every app startup. - internal var rerunOnOpen: Bool = false - // MARK: Private Methods internal var rlmConfiguration: RLMRealmConfiguration { @@ -311,11 +303,6 @@ extension Realm { configuration.eventConfiguration = rlmConfig } - if let initialSubscriptions = initialSubscriptions { - configuration.initialSubscriptions = ObjectiveCSupport.convert(block: initialSubscriptions) - configuration.rerunOnOpen = rerunOnOpen - } - return configuration } @@ -340,9 +327,6 @@ extension Realm { errorHandler: eventConfiguration.errorHandler) } - configuration.initialSubscriptions = rlmConfiguration.initialSubscriptions.map(ObjectiveCSupport.convert(block:)) - configuration.rerunOnOpen = rlmConfiguration.rerunOnOpen - return configuration } } diff --git a/RealmSwift/Sync.swift b/RealmSwift/Sync.swift index b3a5162d64..dd7fe30c4d 100644 --- a/RealmSwift/Sync.swift +++ b/RealmSwift/Sync.swift @@ -515,6 +515,24 @@ public typealias Provider = RLMIdentityProvider case manual(errorHandler: ErrorReportingBlock? = nil) } +@frozen public struct InitialSubscriptionsConfiguration: Sendable { + public var rerunOnOpen: Bool { + config.rerunOnOpen + } + + public var callback: @Sendable (SyncSubscriptionSet) -> Void { + ObjectiveCSupport.convert(block: config.callback) + } + + public init(callback: @escaping @Sendable (SyncSubscriptionSet) -> Void, rerunOnOpen: Bool = false) { + self.init(config: RLMInitialSubscriptionsConfiguration.init(callback: ObjectiveCSupport.convert(block: callback), rerunOnOpen: rerunOnOpen)) + } + + @Unchecked internal var config: RLMInitialSubscriptionsConfiguration + internal init(config: RLMInitialSubscriptionsConfiguration) { + self.config = config + }} + /** A `SyncConfiguration` represents configuration parameters for Realms intended to sync with Atlas App Services. @@ -569,6 +587,15 @@ public typealias Provider = RLMIdentityProvider config.cancelAsyncOpenOnNonFatalErrors } + public var initialSubscriptions: InitialSubscriptionsConfiguration? { + get { + config.initialSubscriptions == nil ? nil : InitialSubscriptionsConfiguration(config: config.initialSubscriptions!) + } + set { + config.initialSubscriptions = newValue?.config + } + } + @Unchecked internal var config: RLMSyncConfiguration internal init(config: RLMSyncConfiguration) { self.config = config diff --git a/include/Realm/RLMInitialSubscriptionsConfiguration.h b/include/Realm/RLMInitialSubscriptionsConfiguration.h new file mode 120000 index 0000000000..72d5364d8c --- /dev/null +++ b/include/Realm/RLMInitialSubscriptionsConfiguration.h @@ -0,0 +1 @@ +../../Realm/RLMInitialSubscriptionsConfiguration.h \ No newline at end of file