macOS: trailing closures for FlutterRunLoop.perform* (#168415)

Support trailing closure syntax in FlutterRunLoop perform methods. This
allows us to write Swift code like:

```
FlutterRunLoop.mainLoop.perform(withDelay: delay) {
  // code.
}
```

This also matches the ordering used in NSRunLoop/RunLoop:
*
https://developer.apple.com/documentation/foundation/runloop/perform(inmodes:block:)?language=objc
*
https://developer.apple.com/documentation/foundation/runloop/perform(inmodes:block:)

Follow-up to flutter/flutter#168174.

No tests since this is just a method rename.

Issue: https://github.com/flutter/flutter/issues/144791

## Pre-launch Checklist

- [X] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [X] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [X] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [X] I signed the [CLA].
- [X] I listed at least one issue that this PR fixes in the description
above.
- [X] I updated/added relevant documentation (doc comments with `///`).
- [X] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [X] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [X] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
Chris Bracken 2025-05-06 21:27:30 -07:00 committed by GitHub
parent 1d9bec83d7
commit 4af869e8d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 36 additions and 39 deletions

View File

@ -1565,16 +1565,16 @@ static void SetThreadPriority(FlutterThreadPriority priority) {
const auto engine_time = _embedderAPI.GetCurrentTime();
[FlutterRunLoop.mainRunLoop
performBlock:^{
FlutterEngine* self = weakSelf;
if (self != nil && self->_engine != nil) {
auto result = _embedderAPI.RunTask(self->_engine, &task);
if (result != kSuccess) {
NSLog(@"Could not post a task to the Flutter engine.");
}
}
}
afterDelay:(targetTime - (double)engine_time) / NSEC_PER_SEC];
performAfterDelay:(targetTime - (double)engine_time) / NSEC_PER_SEC
block:^{
FlutterEngine* self = weakSelf;
if (self != nil && self->_engine != nil) {
auto result = _embedderAPI.RunTask(self->_engine, &task);
if (result != kSuccess) {
NSLog(@"Could not post a task to the Flutter engine.");
}
}
}];
}
// Getter used by test harness, only exposed through the FlutterEngine(Test) category

View File

@ -45,13 +45,12 @@
if (_inResize) {
delay = 0;
}
[FlutterRunLoop.mainRunLoop
performBlock:^{
_didReceiveFrame = YES;
_contentSize = size;
notify();
}
afterDelay:delay];
[FlutterRunLoop.mainRunLoop performAfterDelay:delay
block:^{
_didReceiveFrame = YES;
_contentSize = size;
notify();
}];
}
- (void)shutDown {

View File

@ -107,8 +107,7 @@ import Foundation
}
// Schedules a block to be executed on the main thread.
@objc(performBlock:afterDelay:)
public func perform(block: @escaping () -> Void, afterDelay delay: TimeInterval) {
@objc public func perform(afterDelay delay: TimeInterval, block: @escaping () -> Void) {
tasksLock.lock()
defer { tasksLock.unlock() }
@ -123,8 +122,8 @@ import Foundation
// Schedules a block to be executed on the main thread after a delay.
@objc(performBlock:)
public func perform(block: @escaping () -> Void) {
perform(block: block, afterDelay: 0)
public func perform(_ block: @escaping () -> Void) {
perform(afterDelay: 0, block: block)
}
private func performExpiredTasks() {

View File

@ -78,17 +78,17 @@ static const CFTimeInterval kTimerLatencyCompensation = 0.001;
TRACE_VSYNC("DisplayLinkCallback-Original", _pendingBaton.value_or(0));
[FlutterRunLoop.mainRunLoop
performBlock:^{
if (!_pendingBaton.has_value()) {
TRACE_VSYNC("DisplayLinkPaused", size_t(0));
_displayLink.paused = YES;
return;
}
TRACE_VSYNC("DisplayLinkCallback-Delayed", _pendingBaton.value_or(0));
_block(minStart, targetTimestamp, *_pendingBaton);
_pendingBaton = std::nullopt;
}
afterDelay:remaining];
performAfterDelay:remaining
block:^{
if (!_pendingBaton.has_value()) {
TRACE_VSYNC("DisplayLinkPaused", size_t(0));
_displayLink.paused = YES;
return;
}
TRACE_VSYNC("DisplayLinkCallback-Delayed", _pendingBaton.value_or(0));
_block(minStart, targetTimestamp, *_pendingBaton);
_pendingBaton = std::nullopt;
}];
}
}
@ -138,13 +138,12 @@ static const CFTimeInterval kTimerLatencyCompensation = 0.001;
delay = std::max(start - now - kTimerLatencyCompensation, 0.0);
}
[FlutterRunLoop.mainRunLoop
performBlock:^{
CFTimeInterval targetTimestamp = start + tick_interval;
TRACE_VSYNC("SynthesizedInitialVSync", baton);
_block(start, targetTimestamp, baton);
}
afterDelay:delay];
[FlutterRunLoop.mainRunLoop performAfterDelay:delay
block:^{
CFTimeInterval targetTime = start + tick_interval;
TRACE_VSYNC("SynthesizedInitialVSync", baton);
_block(start, targetTime, baton);
}];
_displayLink.paused = NO;
} else {
_pendingBaton = baton;