diff --git a/CHANGELOG.md b/CHANGELOG.md index 95257d7178c..adc393f9716 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ - Support uint64 in crash reports (#2631) +### Fixes + +- Always fetch view hierarchy on the main thread (#2629) + ## 8.0.0 ### Features diff --git a/Sources/Sentry/SentryViewHierarchy.m b/Sources/Sentry/SentryViewHierarchy.m index b846c7b6a54..b55155be5bc 100644 --- a/Sources/Sentry/SentryViewHierarchy.m +++ b/Sources/Sentry/SentryViewHierarchy.m @@ -48,11 +48,12 @@ - (BOOL)saveViewHierarchy:(NSString *)filePath - (NSData *)fetchViewHierarchy { - NSArray *windows = [SentryDependencyContainer.sharedInstance.application windows]; - __block NSMutableData *result = [[NSMutableData alloc] init]; void (^save)(void) = ^{ + NSArray *windows = + [SentryDependencyContainer.sharedInstance.application windows]; + if (![self processViewHierarchy:windows addFunction:writeJSONDataToMemory userData:(__bridge void *)(result)]) { diff --git a/Tests/SentryTests/SentryViewHierarchyTests.swift b/Tests/SentryTests/SentryViewHierarchyTests.swift index 797b5de7e33..318d1f6ce3b 100644 --- a/Tests/SentryTests/SentryViewHierarchyTests.swift +++ b/Tests/SentryTests/SentryViewHierarchyTests.swift @@ -172,14 +172,37 @@ class SentryViewHierarchyTests: XCTestCase { wait(for: [ex], timeout: 1) } + func test_fetch_usesMainThread() { + let sut = TestSentryViewHierarchy() + let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 10, height: 10)) + fixture.uiApplication.windows = [window] + + let ex = expectation(description: "Running on background Thread") + let dispatch = DispatchQueue(label: "background") + dispatch.async { + let _ = sut.fetch() + ex.fulfill() + } + + wait(for: [ex], timeout: 1) + XCTAssertTrue(fixture.uiApplication.calledOnMainThread, "fetchViewHierarchy is not using the main thread to get UI windows") + } + class TestSentryUIApplication: SentryUIApplication { private var _windows: [UIWindow]? + private var _calledOnMainThread = true + + var calledOnMainThread: Bool { + return _calledOnMainThread + } override var windows: [UIWindow]? { get { + _calledOnMainThread = Thread.isMainThread return _windows } set { + _calledOnMainThread = Thread.isMainThread _windows = newValue } }