Skip to content

Instantly share code, notes, and snippets.

@michaeleisel
Last active August 10, 2022 06:49
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save michaeleisel/77b8efc9bedab1444dbb71a5915dbd15 to your computer and use it in GitHub Desktop.
Save michaeleisel/77b8efc9bedab1444dbb71a5915dbd15 to your computer and use it in GitHub Desktop.
// Note that this checker is always running, even when the app is in the background (where it doesn't matter if the main thread is blocked)
// You'll have to add more code if you don't want the checker to run while the app is in the background
final class ANRChecker {
private let ANRThreshold: CFTimeInterval = 5
// This variable may be accessed from multiple threads at the same time. It won't cause issues, but if you want prevent the thread sanitizer from complaining, you can add locking around it or w/e
private lazy var lastResponseTime: CFTimeInterval = CACurrentMediaTime()
func beginChecking() {
updateLastResponseTime()
checkLastResponseTime()
}
private func updateLastResponseTime() {
lastResponseTime = CACurrentMediaTime()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.updateLastResponseTime()
}
}
private func checkLastResponseTime() {
crashIfDelayTooLarge()
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + 1) {
self.checkLastResponseTime()
}
}
private func crashIfDelayTooLarge() {
let delay = CACurrentMediaTime() - self.lastResponseTime
if delay > self.ANRThreshold {
fatalError()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment