Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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,22 @@ public class SentryFramesTracker: NSObject {
resetFrames()
SentrySDKLog.debug("Initialized frame tracker")
}

deinit {
// Need to invalidate so DisplayLink is releasing this object. Calling this is thread-safe.
displayLinkWrapper.invalidate()
}

// MARK: - Public Methods

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

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

isStarted = true
Expand All @@ -96,6 +106,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 +130,7 @@ public class SentryFramesTracker: NSObject {
object: nil
)

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

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

deinit {
stop()
}

#if os(iOS)
@objc public func resetProfilingTimestamps() {
Expand Down Expand Up @@ -222,7 +232,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