Skip to content

Commit 9de9115

Browse files
authored
perf: pause CADisplayLink instead of re-creation (#980)
## 📜 Description Pause `DisplayLink` instead of re-creating it before any keyboard movement. ## 💡 Motivation and Context This is a known fact, that pausing `CADisplayLink` is faster operation rather than re-creating it and attaching to the thread. I decided to make some benchamrkes, and it seems like it takes `1ms` for `10` runs: <img width="516" alt="image" src="https://github.com/user-attachments/assets/b6bb5c28-bffa-46d0-b499-4855ebb3454f" /> I tried to re-run test 40 times, and the function wasn't in a stack trace - that means that the time was so insignificant. I also measure function execution: - pausing: 1.5-2e^-6 - re-creating: 7-10e-6 So roughly speaking this is 5x improvement, but we measure only creating instances of new object (most likely we don't track what happens underhood). Anyway, this is an optimization and I don't think it introduces any breaking changes, so let's keep it. ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### iOS - pause `DisplayLink` instead of re-creating it; ## 🤔 How Has This Been Tested? Tested via Profiler. Also tested functionality manually and via e2e tests. ## 📸 Screenshots (if appropriate): <img width="965" alt="image" src="https://github.com/user-attachments/assets/395b4511-4195-49e2-84fb-9beef91dfb4f" /> ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
1 parent fb95fc1 commit 9de9115

File tree

1 file changed

+17
-8
lines changed

1 file changed

+17
-8
lines changed

ios/observers/KeyboardMovementObserver.swift

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class KeyboardMovementObserver: NSObject {
3232

3333
private var _windowsCount: Int = 0
3434
private var prevKeyboardPosition = 0.0
35-
private var displayLink: CADisplayLink?
35+
private var displayLink: CADisplayLink!
3636
private var interactiveKeyboardObserver: NSKeyValueObservation?
3737
private var isMounted = false
3838
// state variables
@@ -57,6 +57,18 @@ public class KeyboardMovementObserver: NSObject {
5757
self.onNotify = onNotify
5858
self.onRequestAnimation = onRequestAnimation
5959
self.onCancelAnimation = onCancelAnimation
60+
61+
super.init()
62+
63+
displayLink = CADisplayLink(target: self, selector: #selector(updateKeyboardFrame))
64+
displayLink.preferredFramesPerSecond = 120 // will fallback to 60 fps for devices without Pro Motion display
65+
displayLink.add(to: .main, forMode: .common)
66+
displayLink.isPaused = true
67+
}
68+
69+
deinit {
70+
displayLink.invalidate()
71+
displayLink = nil
6072
}
6173

6274
@objc public func mount() {
@@ -109,7 +121,7 @@ public class KeyboardMovementObserver: NSObject {
109121

110122
private func keyboardDidMoveInteractively(changeValue: CGPoint) {
111123
// if we are currently animating keyboard -> we need to ignore values from KVO
112-
if displayLink != nil {
124+
if !displayLink.isPaused {
113125
return
114126
}
115127
// if keyboard height is not equal to its bounds - we can ignore
@@ -232,18 +244,15 @@ public class KeyboardMovementObserver: NSObject {
232244
// sometimes `will` events can be called multiple times.
233245
// To avoid double re-creation of listener we are adding this condition
234246
// (if active link is present, then no need to re-setup a listener)
235-
if displayLink != nil {
247+
if !displayLink.isPaused {
236248
return
237249
}
238250

239-
displayLink = CADisplayLink(target: self, selector: #selector(updateKeyboardFrame))
240-
displayLink?.preferredFramesPerSecond = 120 // will fallback to 60 fps for devices without Pro Motion display
241-
displayLink?.add(to: .main, forMode: .common)
251+
displayLink.isPaused = false
242252
}
243253

244254
@objc func removeKeyboardWatcher() {
245-
displayLink?.invalidate()
246-
displayLink = nil
255+
displayLink.isPaused = true
247256
}
248257

249258
func initializeAnimation(fromValue: Double, toValue: Double) {

0 commit comments

Comments
 (0)