Skip to content

Commit

Permalink
Change how progress notifications are dispatched
Browse files Browse the repository at this point in the history
Progress notifications are now dispatched to a dedicated queue. From there, the user is free to dispatch them onto whatever queue they need, including the main queue if they need to work with Cocoa UI APIs.
  • Loading branch information
austinzheng authored Feb 15, 2017
1 parent 6360d8f commit 3688715
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 14 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ x.x.x Release notes (yyyy-MM-dd)
non-nil value when passed in an invalid URL.
* `SyncSession.Progress.fractionTransferred` now returns 1 if there are no
transferrable bytes.
* Fix sync progress notifications registered on background threads by always
dispatching on a dedicated background queue.
* Fix compilation issues with Xcode 8.3 beta 2.
* Fix incorrect sync progress notification values for Realms originally created
using a version of Realm prior to 2.3.0.
Expand Down
11 changes: 6 additions & 5 deletions Realm/RLMSyncSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ NS_ASSUME_NONNULL_BEGIN
Register a progress notification block.
Multiple blocks can be registered with the same session at once. Each block
will be invoked from the runloop of the thread on which it was registered,
creating a new runloop if none exists. If the session has already received
progress information from the synchronization subsystem, the block will be
called immediately. Otherwise, it will be called as soon as progress
information becomes available.
will be invoked on a side queue devoted to progress notifications.
If the session has already received progress information from the
synchronization subsystem, the block will be called immediately. Otherwise, it
will be called as soon as progress information becomes available.
The token returned by this method must be retained as long as progress
notifications are desired, and the `-stop` method should be called on it
Expand All @@ -152,6 +152,7 @@ NS_ASSUME_NONNULL_BEGIN
mode:(RLMSyncProgress)mode
block:(RLMProgressNotificationBlock)block
NS_REFINED_FOR_SWIFT;

@end

NS_ASSUME_NONNULL_END
19 changes: 15 additions & 4 deletions Realm/RLMSyncSession.mm
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,21 @@ - (nullable instancetype)initWithTokenValue:(uint64_t)token

@end

@interface RLMSyncSession ()
@property (class, nonatomic, readonly) dispatch_queue_t notificationsQueue;
@end

@implementation RLMSyncSession

+ (dispatch_queue_t)notificationsQueue {
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = dispatch_queue_create("io.realm.sync.sessionsNotificationQueue", DISPATCH_QUEUE_SERIAL);
});
return queue;
}

- (instancetype)initWithSyncSession:(std::shared_ptr<SyncSession>)session {
if (self = [super init]) {
_session = session;
Expand Down Expand Up @@ -153,17 +166,15 @@ - (RLMProgressNotificationToken *)addProgressNotificationForDirection:(RLMSyncPr
if (session->state() == SyncSession::PublicState::Error) {
return nil;
}
// Get the current runloop, or create one if necessary.
CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
dispatch_queue_t queue = RLMSyncSession.notificationsQueue;
auto notifier_direction = (direction == RLMSyncProgressDirectionUpload
? SyncSession::NotifierType::upload
: SyncSession::NotifierType::download);
bool is_streaming = (mode == RLMSyncProgressReportIndefinitely);
uint64_t token = session->register_progress_notifier([=](uint64_t transferred, uint64_t transferrable) {
CFRunLoopPerformBlock(currentRunLoop, kCFRunLoopCommonModes, ^{
dispatch_async(queue, ^{
block((NSUInteger)transferred, (NSUInteger)transferrable);
});
CFRunLoopWakeUp(currentRunLoop);
}, notifier_direction, is_streaming);
return [[RLMProgressNotificationToken alloc] initWithTokenValue:token session:std::move(session)];
}
Expand Down
10 changes: 5 additions & 5 deletions RealmSwift/Sync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -582,12 +582,12 @@ public extension SyncSession {
/**
Register a progress notification block.

If the session has already received progress information from the
synchronization subsystem, the block will be called immediately. Otherwise, it
will be called as soon as progress information becomes available.

Multiple blocks can be registered with the same session at once. Each block
will be invoked from the runloop of the thread on which it was registered,
creating a new runloop if none exists. If the session has already received
progress information from the synchronization subsystem, the block will be
called immediately. Otherwise, it will be called as soon as progress
information becomes available.
will be invoked on a side queue devoted to progress notifications.

The token returned by this method must be retained as long as progress
notifications are desired, and the `stop()` method should be called on it
Expand Down

0 comments on commit 3688715

Please sign in to comment.