Skip to content

feat(performance): detect UIViewController lifecycle methods not calling super - #436

Merged
maatheusgois-dd merged 2 commits into
mainfrom
feat/super-call-detector-376
Aug 11, 2026
Merged

maatheusgois-dd merged 2 commits into
mainfrom
feat/super-call-detector-376

Conversation

@maatheusgois-dd

Copy link
Copy Markdown
Contributor

Summary

Implements #376 — detects UIViewController lifecycle methods that fail to call their super implementation.

Approach

Swizzling: Uses IMP-replacement (method_setImplementation) — not method_exchangeImplementations — to avoid the NewRelic crash pattern documented in #434. The 5 swizzled lifecycle methods: viewDidLoad, viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear.

Detection logic: Per-instance lifecycle state is tracked via associated objects. When a later lifecycle method fires for a VC instance but an earlier one was never recorded (meaning its swizzled base IMP never ran), the earlier method is flagged as missing its super call.

Public API

DebugSwift.Performance.SuperCallChecker:

  • onDetect(_:) — register a callback for new violations
  • violations — current list of SuperCallViolation
  • ignoreClass(_:) / setIgnoredClasses(_:) — ignore specific classes
  • clearViolations() — clear stored violations

UI

Dedicated "Super Call Checker" section in the Performance tab with a ResourcesGenericController listing violations. Guarded by .superCallDetector in DebugSwiftSwizzleFeature — disabled by default, opt-in like the leak detector.

Tests

18 tests in ExampleTests covering:

  • Violation recording and deduplication
  • Ignore list behavior (single + set replacement)
  • Callback dispatch (fires for new, deduped for duplicates, suppressed for ignored)
  • Public API mirroring (SuperCallCheckerSuperCallDetector)
  • LifecycleEvent ordering and count
  • End-to-end detection with good/bad view controllers

All tests pass:

Test Suite 'SuperCallDetectorTests' passed (18 tests)
** TEST SUCCEEDED **

Files Changed

  • Performance.SuperCallDetector.swift (new) — core detection logic
  • SuperCallViolationsViewModel.swift (new) — violations list ViewModel
  • SuperCallDetectorTests.swift (new) — 18 tests
  • FeatureBase.swift.superCallDetector case
  • FeatureHandling.swiftenableSuperCallDetector() wiring
  • DebugSwift.Performance.swiftSuperCallChecker public API
  • Performance.Controller.swift — UI section, cell, navigation

Closes #376

…ing super (#376)

Add SuperCallDetector — swizzles viewDidLoad, viewWillAppear,
viewDidAppear, viewWillDisappear, and viewDidDisappear on UIViewController
using IMP-replacement (method_setImplementation, not method_exchangeImplementations)
to avoid NewRelic-style crashes. Per-instance lifecycle state is tracked via
associated objects; when a later lifecycle method fires for a VC instance but
an earlier one was never recorded, the earlier method is flagged as missing
its super call.

Public API: DebugSwift.Performance.SuperCallChecker with onDetect(_:),
violations, ignoreClass(_:), setIgnoredClasses(_:), clearViolations().

UI: dedicated "Super Call Checker" section in Performance tab with a
ResourcesGenericController listing violations.

Tests: 18 tests covering violation recording, dedup, ignore list, callback
dispatch, public API mirroring, and end-to-end detection with good/bad VCs.

Co-authored-by: oh-my-pi <https://omp.sh>
…ation

The new swizzle feature case was added to DebugSwiftSwizzleFeature but
the test's expected array was not updated, causing
testDebugSwiftSwizzleFeature_allCases to fail on CI.

Co-authored-by: oh-my-pi <https://omp.sh>
@github-actions

Copy link
Copy Markdown
Warnings
⚠️ Please assign yourself to the PR.
Messages
📖 Project coverage: 25.43%
📖 The PR added 717 and removed 1 lines. 8 file(s) changed.

DebugSwift: Coverage: 15.2

File Coverage
Performance.Controller.swift 18.32% ⚠️
DebugSwift.Performance.swift 10.53% ⚠️
Performance.SuperCallDetector.swift 98.08%
SuperCallViolationsViewModel.swift 0.0% ⚠️
FeatureHandling.swift 86.59%

ExampleTests.xctest: Coverage: 97.04

File Coverage
SuperCallDetectorTests.swift 97.63%
FeatureBaseTests.swift 92.31%

Generated by 🚫 Danger Swift against b71a7ee

@maatheusgois-dd
maatheusgois-dd merged commit 19f483c into main Aug 11, 2026
5 checks passed
@maatheusgois-dd
maatheusgois-dd deleted the feat/super-call-detector-376 branch August 11, 2026 22:43
@Janneman84

Copy link
Copy Markdown
Contributor

Did you cover viewIsAppearing() too? It's a newer and lesser known lifecycle method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: detect lifecycle methods not calling super

2 participants