Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Fix `raw_description` in `runtime` context on Mac Catalyst (#7082)
- Deprecates `configureDarkTheme` for user feedback (#7114)
- Fix incorrect variable assignment for 'sampled' key (#7120)
- Resolve crash in caused by calling `SentryFramesTracker.removeListener(_:)` (#7155)

## 9.1.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ public protocol SentryFramesTrackerListener: NSObjectProtocol {

@_spi(Private) @objc
public class SentryFramesTracker: NSObject {

var isStarted: Bool = false
private var isStarted: Bool = false
@objc public private(set) var isRunning: Bool = false

// MARK: Private properties
private var lock = NSLock()
private var previousFrameTimestamp: CFTimeInterval = SentryFramesTracker.previousFrameInitialValue
private var previousFrameSystemTimestamp: UInt64 = 0
private var currentFrameRate: UInt64 = 60
Expand Down Expand Up @@ -68,11 +67,24 @@ public class SentryFramesTracker: NSObject {
resetFrames()
SentrySDKLog.debug("Initialized frame tracker")
}

deinit {
// Avoid async dispatch with self capture on deinit.
dispatchQueueWrapper.dispatchSyncOnMainQueue {
self.stopInternal()
}
}

// MARK: - Public Methods

@objc
public func start() {
dispatchQueueWrapper.dispatchAsyncOnMainQueueIfNotMainThread {
self.startInternal()
}
}

private func startInternal() {
guard !isStarted else { return }

isStarted = true
Expand All @@ -96,6 +108,12 @@ public class SentryFramesTracker: NSObject {

@objc
public func stop() {
dispatchQueueWrapper.dispatchAsyncOnMainQueueIfNotMainThread {
self.stopInternal()
}
}

private func stopInternal() {
guard isStarted else { return }

isStarted = false
Expand All @@ -114,9 +132,7 @@ public class SentryFramesTracker: NSObject {
object: nil
)

lock.synchronized {
listeners.removeAllObjects()
}
listeners.removeAllObjects()
}

@objc
Expand Down Expand Up @@ -170,10 +186,6 @@ public class SentryFramesTracker: NSObject {
self.listeners.remove(listener)
}
}

deinit {
stop()
}

#if os(iOS)
@objc public func resetProfilingTimestamps() {
Expand Down Expand Up @@ -222,7 +234,7 @@ public class SentryFramesTracker: NSObject {
private func willResignActive() {
pause()
}

private func unpause() {
guard !isRunning else { return }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import XCTest
// This test class also includes tests for delayed frames calculation which is quite complex.

#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst)
class SentryFramesTrackerTests: XCTestCase {
final class SentryFramesTrackerTests: XCTestCase {

private class Fixture {

Expand Down Expand Up @@ -775,6 +775,21 @@ class SentryFramesTrackerTests: XCTestCase {
XCTAssertEqual(dispatchQueueWrapper.blockOnMainInvocations.count, 1)
}

func testListenersAreRemovedInMainThread() {
let dispatchQueueWrapper = TestSentryDispatchQueueWrapper()
let sut = SentryFramesTracker(displayLinkWrapper: fixture.displayLinkWrapper, dateProvider: fixture.dateProvider, dispatchQueueWrapper: dispatchQueueWrapper, notificationCenter: fixture.notificationCenter, delayedFramesTracker: TestDelayedWrapper(keepDelayedFramesDuration: fixture.keepDelayedFramesDuration, dateProvider: fixture.dateProvider))
let listener = FrameTrackerListener()

sut.addListener(listener)
sut.start()

XCTAssertEqual(dispatchQueueWrapper.blockOnMainInvocations.count, 2)

sut.stop()

XCTAssertEqual(dispatchQueueWrapper.blockOnMainInvocations.count, 3)
}

func testRemoveListener() {
let sut = fixture.sut
let listener = FrameTrackerListener()
Expand Down
Loading