托管同步会话 — Swift SDK
打开同步域会为该域启动 SyncSession 。 Realm Swift SDK提供了手动暂停和恢复同步会话的方法。
同步连接行为
版本 10.41.0 中的新增内容。
在 Realm Swift SDK 版本 10.41.0 及更高版本中,App Services 默认为所有打开的同步 Realm 共享与服务器的单个连接。 与早期版本相比,这是一项更改,在早期版本中,打开多个同步域会打开与服务器的额外连接。与服务器的连接独立于 SyncSession
,并且基于 App Services 用户。
您可以从应用程序客户端配置中更改此行为。
检查网络连接
提示
Realm 的离线优先设计意味着您通常不需要检查当前的网络连接状态。 也就是说,如果您的应用程序需要某些连接状态指示,则connectionState
属性可用。
要检查连接状态,可以直接读取同步 Realm 的 RLMSyncSession 实例的connectionState属性。
此属性 符合 KVO 标准 ,这样您就可以使用 KVO 观察更改。以下示例演示了如何实现观察者类:
@interface MySyncSessionObserver: NSObject @end @implementation MySyncSessionObserver - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (![object isKindOfClass:RLMSyncSession.class]) { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; return; } if (![keyPath isEqualToString:@"connectionState"]) { // Not interested in observing this keypath return; } RLMSyncSession *syncSession = (RLMSyncSession *)object; RLMSyncConnectionState connectionState = [syncSession connectionState]; switch (connectionState) { case RLMSyncConnectionStateConnecting: NSLog(@"Connecting..."); break; case RLMSyncConnectionStateConnected: NSLog(@"Connected"); break; case RLMSyncConnectionStateDisconnected: NSLog(@"Disconnected"); break; } } @end
然后,您可以将观察者实例附加到 RLMSyncSession对象。 请务必在完成后删除观察者。
// Observe connectionState for changes using KVO MySyncSessionObserver *observer = [[MySyncSessionObserver alloc] init]; [syncSession addObserver:observer forKeyPath:@"connectionState" options:NSKeyValueObservingOptionInitial context:nil]; // Later, when done... [syncSession removeObserver:observer forKeyPath:@"connectionState" context:nil];
要检查连接状态,可以直接读取同步 Realm 的 SyncSession 实例的connectionState属性。
此属性 符合 KVO 标准 ,因此您可以使用 KVO 甚至组合来观察更改。
// Observe connectionState for changes using KVO let observer = syncSession.observe(\.connectionState, options: [.initial]) { (syncSession, change) in switch syncSession.connectionState { case .connecting: print("Connecting...") case .connected: print("Connected") case .disconnected: print("Disconnected") default: break } } // Observe using Combine let cancellable = syncSession.publisher(for: \.connectionState) .sink { connectionState in switch connectionState { case .connecting: print("Connecting...") case .connected: print("Connected") case .disconnected: print("Disconnected") default: break } }
挂起或恢复同步会话
您可以暂停和恢复 Realm 上的同步会话。 暂停同步会话只会暂停该 Realm 的同步会话。 如果您有多个打开 Realm,则暂停不会影响其他 Realm 的同步会话。
您可以使用已同步域的RLMSyncSession实例暂停或恢复同步会话。
RLMRealm *syncedRealm = [RLMRealm realmWithConfiguration:configuration error:nil]; RLMSyncSession *syncSession = [syncedRealm syncSession]; // Suspend synchronization [syncSession suspend]; // Later, resume synchronization [syncSession resume];
您可以使用同步 Realm 的SyncSession实例暂停或恢复同步会话。
let syncSession = syncedRealm.syncSession! // Suspend synchronization syncSession.suspend() // Later, resume synchronization syncSession.resume()
何时暂停同步会话
对于大多数应用程序,无需手动暂停和恢复同步会话。 但是,在某些情况下,您可能希望暂停或暂停同步会话:
您只想在用户执行特定操作后进行同步
您只想在一天中的特定时间进行同步
您不想在网络连接较差时尝试同步
您想要显式强制同步会话连接
在网络连接较差的情况下,不断尝试建立网络连接可能会耗尽用户的设备电池。
显式强制同步会话连接的情况最常见与离线一段时间有关。同步客户端尝试连接,一旦失败,就会Go指数退避状态。长时间离线后,客户端可能无法立即重新连接。 暂停和恢复同步会话会显式强制连接。
当您暂停同步会话时,请记住以下事项:
暂停同步会话会使其在两个方向上暂停。您的应用在设备上所做的更改不会与后端同步,对后端或其他设备上的数据的更改也不会同步到设备。 无法仅暂停上传或仅暂停下载。
如果您希望客户端永久停止与后端同步,请勿暂停同步会话。 要永久停止同步,请将同步 Realm 的内容复制到非同步 Realm,并在客户端中使用该非同步 Realm。
请勿在不确定的时间段或以月和年为单位的时间范围内通过暂停同步来停止同步。 该功能不是针对这些使用案例而设计或测试的。 以这种方式使用时,您可能会遇到一系列问题。
等待上传或下载更改
版本 10.45.0 中的新增内容。
要等待从同步域上传或下载所有更改,请调用域.syncSession?.wait(for: )。
此方法采用ProgressDirection参数来指定是否追踪上传或下载进度。
您可以将这些方法与 Swift 的异步/等待语法或回调语法一起使用。 回调版本域.syncSession?.wait(for:queue: 区块:)可以采用一个队列来调度回调,以及一个在等待完成时调用的区块。
// Wait to download all pending changes from Atlas try await realm.syncSession?.wait(for: .download) // Add data locally try realm.write { realm.create(Task.self, value: [ "taskName": "Review proposal", "assignee": "Emma", "completed": false, "progressMinutes": 0, "dueDate": date ]) } // Wait for local changes to be uploaded to Atlas try await realm.syncSession?.wait(for: .upload)
// Wait to download all pending changes from Atlas realm.syncSession?.wait(for: .download, block: { _ in // You can provide a block to execute // after waiting for download to complete }) // Add data locally do { try realm.write { realm.create(Task.self, value: [ "taskName": "Review proposal", "assignee": "Emma", "completed": false, "progressMinutes": 0, "dueDate": date ]) } } catch { print("There was an error writing to realm: \(error.localizedDescription)") } // Wait for local changes to be uploaded to Atlas realm.syncSession?.wait(for: .upload, block: { _ in // You can provide a block to execute after // waiting for upload to complete })
检查同步会话的上传和下载进度
在版本10.50.0中进行了更改: 已弃用transferredBytes
和transferrableBytes
,改用progressEstimate
您可以通过注册令牌来检查上传和下载进度,该令牌为给定的上传或下载方向和工作范围提供progressEstimate
。 您可以设立ProgressMode
来确定工作范围:无限期观察或在当前工作项完成后取消注册区块。
令牌提供的 progressEstimate
值是double精度值,其值范围从 0.0
到 1.0
。 在1.0
处,上传或下载已完成。 您可以使用此progressEstimate
来显示进度指示器或估计的数据传输百分比。
在版本10.50.0中进行了更改: 已弃用addProgressNotificationForDirection
,取而代之的是addSyncProgressNotificationForDirection
您可以使用同步 Realm 的 RLMSyncSession 实例的[--addSyncProgressNotificationForDirection:mode:block:]方法添加进度通知。
此方法会返回一个令牌,您应保留该令牌,直到您希望停止观察上传或下载进度。 请注意,如果将令牌保留在局部变量中,则当局部变量Go作用域时,观察将停止。
RLMSyncSession *syncSession = [syncedRealm syncSession]; RLMProgressNotificationToken *token = [syncSession addSyncProgressNotificationForDirection:RLMSyncProgressDirectionUpload mode:RLMSyncProgressModeForCurrentlyOutstandingWork block:^(RLMSyncProgress syncProgress) { NSLog(@"Uploaded %fB", (double)syncProgress.progressEstimate); }]; // Upload something [syncedRealm transactionWithBlock:^{ [syncedRealm addObject:[[Task alloc] init]]; }];
您可以使用同步 Realm 的 SyncSession 实例的addProgressNotification(for:mode:block:)方法添加进度通知。
此方法会返回一个令牌,您应保留该令牌,直到您希望停止观察上传或下载进度。 请注意,如果将令牌保留在局部变量中,则当局部变量Go作用域时,观察将停止。
let syncSession = realm.syncSession! let token = syncSession.addProgressNotification( for: .upload, mode: .forCurrentlyOutstandingWork) { (progress) in let progressEstimate = progress.progressEstimate let transferPercent = progressEstimate * 100 print("Uploaded (\(transferPercent)%)") }
手动重新连接所有同步会话
版本 10.44.0 中的新增内容。
Realm 会自动检测设备何时在离线后重新获得连接,并尝试使用增量退避策略重新连接。 例如,在 Apple 平台上,Realm 会侦听网络变更通知,并在收到通知后立即自动Atlas Triggers重新连接。
在 Swift SDK 版本 10.44.0 及更高版本中,您可以选择使用SyncSession.reconnect()
手动trigger重新连接尝试,而不是等待增量退避持续时间。如果您对网络状况有更准确的了解并且不想依赖 Realm 的自动重新连接检测,这非常有用。
let syncSession = realm.syncSession! // Work with the realm. When you need to force the sync session to reconnect... syncSession.reconnect()
调用此方法时,SDK 会强制所有同步会话立即尝试重新连接。 这会重置用于增量退避的所有计时器。
调用此方法并不能保证设备可以重新连接。 如果 SDK 出现致命错误,或者设备已连接或正在尝试连接,则调用此方法无效。
重要
无法在套接字读取超时时间内重新连接
Realm 的内部默认套接字读取超时为 2 分钟,如果读取操作在 2 分钟窗口内未收到任何数据,Realm 将超时。 如果您在该窗口内调用SyncSession.reconnect()
,Swift SDK不会尝试重新连接。