From 3a9586b62042a4e010f3d3439b67a4779017fe07 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Mon, 22 Apr 2024 17:42:51 +0300 Subject: [PATCH] RCOCOA-2334: Move initial subscription logic into Core (#8549) * Clean up API docs, add changelog (+1 squashed commit) Squashed commits: [04969a5aa] Move initial subscription logic into Core * Address CR comments * Remove spaces after colons --- CHANGELOG.md | 2 +- Package.swift | 1 + Realm.podspec | 1 + Realm.xcodeproj/project.pbxproj | 10 +++ Realm/ObjectServerTests/AsyncSyncTests.swift | 10 +++ Realm/RLMInitialSubscriptionsConfiguration.h | 71 +++++++++++++++++++ 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 | 14 ++-- Realm/Realm.h | 1 + Realm/Realm.modulemap | 1 + RealmSwift/RealmConfiguration.swift | 16 ----- RealmSwift/Sync.swift | 15 ++++ .../RLMInitialSubscriptionsConfiguration.h | 1 + 19 files changed, 206 insertions(+), 56 deletions(-) create mode 100644 Realm/RLMInitialSubscriptionsConfiguration.h create mode 100644 Realm/RLMInitialSubscriptionsConfiguration.m create mode 120000 include/Realm/RLMInitialSubscriptionsConfiguration.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dc967bbff..1d9217de23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ x.y.z Release notes (yyyy-MM-dd) ============================================================= ### Enhancements -* None. +* Added `SyncConfiguration.initialSubscriptions` which describes the initial subscription configuration that was passed when constructing the `SyncConfiguration`. ([#8548](https://github.com/realm/realm-swift/issues/8548)) ### Fixed * ([#????](https://github.com/realm/realm-swift/issues/????), since v?.?.?) diff --git a/Package.swift b/Package.swift index 630ecb4aa0..accb03a8dc 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/ObjectServerTests/AsyncSyncTests.swift b/Realm/ObjectServerTests/AsyncSyncTests.swift index 74bf5fece5..4cecbe9912 100644 --- a/Realm/ObjectServerTests/AsyncSyncTests.swift +++ b/Realm/ObjectServerTests/AsyncSyncTests.swift @@ -611,6 +611,11 @@ class AsyncFlexibleSyncTests: SwiftSyncTestCase { }) }) config.objectTypes = [SwiftPerson.self] + + XCTAssertNotNil(config.syncConfiguration?.initialSubscriptions) + XCTAssertNotNil(config.syncConfiguration?.initialSubscriptions?.callback) + XCTAssertEqual(config.syncConfiguration?.initialSubscriptions?.rerunOnOpen, false) + let realm = try await Realm(configuration: config, downloadBeforeOpen: .once) XCTAssertEqual(realm.subscriptions.count, 1) checkCount(expected: 10, realm, SwiftPerson.self) @@ -644,6 +649,11 @@ class AsyncFlexibleSyncTests: SwiftSyncTestCase { } }, rerunOnOpen: true) config.objectTypes = [SwiftPerson.self] + + XCTAssertNotNil(config.syncConfiguration?.initialSubscriptions) + XCTAssertNotNil(config.syncConfiguration?.initialSubscriptions?.callback) + XCTAssertEqual(config.syncConfiguration?.initialSubscriptions?.rerunOnOpen, false) + try await Task { let realm = try await Realm(configuration: config, downloadBeforeOpen: .once) XCTAssertEqual(realm.subscriptions.count, 1) diff --git a/Realm/RLMInitialSubscriptionsConfiguration.h b/Realm/RLMInitialSubscriptionsConfiguration.h new file mode 100644 index 0000000000..15d9ab64bf --- /dev/null +++ b/Realm/RLMInitialSubscriptionsConfiguration.h @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////// +// +// 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); + +/** + A configuration controlling how the initial subscriptions are populated when a Realm file is first opened. + + @see `RLMSubscriptionSet` + */ +RLM_SWIFT_SENDABLE RLM_FINAL // immutable final class +@interface RLMInitialSubscriptionsConfiguration : NSObject + +/** + A callback that's executed in an update block to populate the initial subscriptions for that Realm. + + This callback will only be executed when the Realm is first created, unless `rerunOnOpen` is `true`, in which case it will be executed every time + the Realm is opened. + */ +@property (nonatomic, readonly) RLMFlexibleSyncInitialSubscriptionsBlock callback; + +/** + Controls whether to re-run the `callback` every time the Realm is opened. + */ +@property (nonatomic, readonly) BOOL rerunOnOpen; + +/** + Create a new initial subscriptions configuration. + + @param callback Callback that will be invoked to update the subscriptions for this Realm file when it's first created or every time it's opened if `rerunOnOpen` is `true`. + @param rerunOnOpen A flag controlling whether to run the subscription callback every time the Realm is opened or only the first time. + */ +- (instancetype)initWithCallback:(RLMFlexibleSyncInitialSubscriptionsBlock)callback rerunOnOpen:(BOOL)rerunOnOpen; + + +/** + Create a new initial subscriptions configuration. + + @param callback Callback that will be invoked to update the subscriptions for this Realm file when it's first created. + */ +- (instancetype)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..51a3a3e566 --- /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..7cdf5b55b4 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..2459c479ff 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; } @@ -279,8 +277,8 @@ - (NSString *)identifier { NSMutableArray *buffer = [NSMutableArray array]; auto identities = _user->identities(); for (auto& identity : identities) { - [buffer addObject: [[RLMUserIdentity alloc] initUserIdentityWithProviderType:@(identity.provider_type.c_str()) - identifier:@(identity.id.c_str())]]; + [buffer addObject:[[RLMUserIdentity alloc] initUserIdentityWithProviderType:@(identity.provider_type.c_str()) + identifier:@(identity.id.c_str())]]; } return [buffer copy]; 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..20dc1ebfce 100644 --- a/RealmSwift/Sync.swift +++ b/RealmSwift/Sync.swift @@ -515,6 +515,14 @@ public typealias Provider = RLMIdentityProvider case manual(errorHandler: ErrorReportingBlock? = nil) } + +/** + A configuration controlling how the initial subscriptions are populated when a Realm file is first opened. + + - see: `RLMInitialSubscriptionsConfiguration` + */ +public typealias InitialSubscriptionsConfiguration = RLMInitialSubscriptionsConfiguration + /** A `SyncConfiguration` represents configuration parameters for Realms intended to sync with Atlas App Services. @@ -569,6 +577,13 @@ public typealias Provider = RLMIdentityProvider config.cancelAsyncOpenOnNonFatalErrors } + /** + A configuration that controls how initial subscriptions are populated when the Realm is opened. + */ + public var initialSubscriptions: InitialSubscriptionsConfiguration? { + config.initialSubscriptions + } + @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