Skip to content

Instantly share code, notes, and snippets.

@michaeleisel
Last active August 10, 2022 06:49
// 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