From 3927cc6cc59649156521bb48ab457bc8f5603617 Mon Sep 17 00:00:00 2001 From: Jim Roepcke Date: Tue, 24 Oct 2017 15:26:14 -0700 Subject: [PATCH 1/3] feat: allow the visibility behavior to be customized. --- LifetimeTracker.xcodeproj/project.pbxproj | 8 +++ Sources/LifetimeTracker+DashboardView.swift | 29 +++++++++- .../VisibilityTests.swift | 53 +++++++++++++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 Tests/LifetimeTrackerTests/VisibilityTests.swift diff --git a/LifetimeTracker.xcodeproj/project.pbxproj b/LifetimeTracker.xcodeproj/project.pbxproj index 65dc068..33286ef 100644 --- a/LifetimeTracker.xcodeproj/project.pbxproj +++ b/LifetimeTracker.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 383869131F9FEE7800B1A6AB /* VisibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383869121F9FEE7800B1A6AB /* VisibilityTests.swift */; }; + 383869141F9FEE7E00B1A6AB /* VisibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383869121F9FEE7800B1A6AB /* VisibilityTests.swift */; }; + 383869151F9FEE7F00B1A6AB /* VisibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383869121F9FEE7800B1A6AB /* VisibilityTests.swift */; }; 52D6D9871BEFF229002C0205 /* LifetimeTracker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* LifetimeTracker.framework */; }; 8933C7851EB5B820000D00A4 /* LifetimeTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7841EB5B820000D00A4 /* LifetimeTracker.swift */; }; 8933C7861EB5B820000D00A4 /* LifetimeTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8933C7841EB5B820000D00A4 /* LifetimeTracker.swift */; }; @@ -51,6 +54,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 383869121F9FEE7800B1A6AB /* VisibilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisibilityTests.swift; sourceTree = ""; }; 52D6D97C1BEFF229002C0205 /* LifetimeTracker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LifetimeTracker.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 52D6D9861BEFF229002C0205 /* LifetimeTracker-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "LifetimeTracker-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 52D6D9E21BEFFF6E002C0205 /* LifetimeTracker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LifetimeTracker.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -172,6 +176,7 @@ isa = PBXGroup; children = ( 8933C7891EB5B82A000D00A4 /* LifetimeTrackerTests.swift */, + 383869121F9FEE7800B1A6AB /* VisibilityTests.swift */, ); name = Tests; path = Tests/LifetimeTrackerTests; @@ -495,6 +500,7 @@ buildActionMask = 2147483647; files = ( 8933C7901EB5B82D000D00A4 /* LifetimeTrackerTests.swift in Sources */, + 383869131F9FEE7800B1A6AB /* VisibilityTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -530,6 +536,7 @@ buildActionMask = 2147483647; files = ( 8933C78F1EB5B82C000D00A4 /* LifetimeTrackerTests.swift in Sources */, + 383869141F9FEE7E00B1A6AB /* VisibilityTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -538,6 +545,7 @@ buildActionMask = 2147483647; files = ( 8933C78E1EB5B82C000D00A4 /* LifetimeTrackerTests.swift in Sources */, + 383869151F9FEE7F00B1A6AB /* VisibilityTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/LifetimeTracker+DashboardView.swift b/Sources/LifetimeTracker+DashboardView.swift index af30f58..0c7a156 100644 --- a/Sources/LifetimeTracker+DashboardView.swift +++ b/Sources/LifetimeTracker+DashboardView.swift @@ -45,11 +45,29 @@ public final class LifetimeTrackerDashboardIntegration { return window }() - public init() {} + public enum Visibility { + case alwaysHidden + case alwaysVisible + case visibleWithIssuesDetected + + func windowIsHidden(hasIssuesToDisplay: Bool) -> Bool { + switch self { + case .alwaysHidden: return true + case .alwaysVisible: return false + case .visibleWithIssuesDetected: return !hasIssuesToDisplay + } + } + } + + public var visibility: Visibility + + public init(visibility: Visibility = .alwaysVisible) { + self.visibility = visibility + } public func refreshUI(counts: [String: LifetimeTracker.Entry], fullEntries: [String: LifetimeTracker.Entry]) { DispatchQueue.main.async { - self.window.isHidden = false + self.window.isHidden = self.visibility.windowIsHidden(hasIssuesToDisplay: counts.hasIssuesToDisplay) let vm = DashboardViewModel(summary: self.summary(from: counts), entries: self.entries(from: fullEntries)) self.vc.update(with: vm) } @@ -84,3 +102,10 @@ public final class LifetimeTrackerDashboardIntegration { } } } + +extension Dictionary where Key == String, Value == LifetimeTracker.Entry { + var hasIssuesToDisplay: Bool { + let aDetectedIssue = keys.first { self[$0]?.shouldDisplay == true } + return aDetectedIssue != nil + } +} diff --git a/Tests/LifetimeTrackerTests/VisibilityTests.swift b/Tests/LifetimeTrackerTests/VisibilityTests.swift new file mode 100644 index 0000000..c53baf9 --- /dev/null +++ b/Tests/LifetimeTrackerTests/VisibilityTests.swift @@ -0,0 +1,53 @@ +// +// VisibilityTests.swift +// LifetimeTracker +// +// Created by Jim Roepcke on 2017-10-24. +// Copyright © 2017 LifetimeTracker. All rights reserved. +// + +import Foundation +import XCTest +@testable import LifetimeTracker + +private typealias Visibility = LifetimeTrackerDashboardIntegration.Visibility + +class VisibilityTests: XCTestCase { + + func testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreNoIssuesToDisplay() { + let behavior = Visibility.alwaysHidden + let hasIssuesToDisplay = false + XCTAssertTrue(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay)) + } + + func testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreIssuesToDisplay() { + let behavior = Visibility.alwaysHidden + let hasIssuesToDisplay = true + XCTAssertTrue(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay)) + } + + func testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreNoIssuesToDisplay() { + let behavior = Visibility.alwaysVisible + let hasIssuesToDisplay = false + XCTAssertFalse(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay)) + } + + func testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreIssuesToDisplay() { + let behavior = Visibility.alwaysVisible + let hasIssuesToDisplay = true + XCTAssertFalse(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay)) + } + + func testHidesWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreNoIssuesToDisplay() { + let behavior = Visibility.visibleWithIssuesDetected + let hasIssuesToDisplay = false + XCTAssertTrue(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay)) + } + + func testDoesNotHideWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreIssuesToDisplay() { + let behavior = Visibility.visibleWithIssuesDetected + let hasIssuesToDisplay = true + XCTAssertFalse(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay)) + } + +} From 1c0259c0fbd0f7d8b4f7afddcd6ff721a88fc668 Mon Sep 17 00:00:00 2001 From: Krzysztof Zablocki Date: Wed, 25 Oct 2017 10:42:03 +0200 Subject: [PATCH 2/3] chore: add allTests to visibility --- Tests/LifetimeTrackerTests/VisibilityTests.swift | 8 ++++++++ Tests/LinuxMain.swift | 1 + 2 files changed, 9 insertions(+) diff --git a/Tests/LifetimeTrackerTests/VisibilityTests.swift b/Tests/LifetimeTrackerTests/VisibilityTests.swift index c53baf9..7abd03e 100644 --- a/Tests/LifetimeTrackerTests/VisibilityTests.swift +++ b/Tests/LifetimeTrackerTests/VisibilityTests.swift @@ -50,4 +50,12 @@ class VisibilityTests: XCTestCase { XCTAssertFalse(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay)) } + static var allTests = [ + ("testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreNoIssuesToDisplay", testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreNoIssuesToDisplay), + ("testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreIssuesToDisplay", testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreIssuesToDisplay), + ("testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreNoIssuesToDisplay", testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreNoIssuesToDisplay), + ("testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreIssuesToDisplay", testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreIssuesToDisplay), + ("testHidesWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreNoIssuesToDisplay", testHidesWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreNoIssuesToDisplay), + ("testDoesNotHideWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreIssuesToDisplay", testDoesNotHideWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreIssuesToDisplay), + ] } diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 5dc98fc..9c7f005 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -3,4 +3,5 @@ import XCTest XCTMain([ testCase(LifetimeTrackerTests.allTests), + testCase(VisibilityTests.allTests), ]) From f6d8e6daf94640ff68f47b970269ad0b2569b67c Mon Sep 17 00:00:00 2001 From: Krzysztof Zablocki Date: Wed, 25 Oct 2017 10:44:56 +0200 Subject: [PATCH 3/3] docs: metadata update --- LifetimeTracker.podspec | 2 +- README.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/LifetimeTracker.podspec b/LifetimeTracker.podspec index 778d985..0a5bfc1 100644 --- a/LifetimeTracker.podspec +++ b/LifetimeTracker.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LifetimeTracker" - s.version = "1.0.9" + s.version = "1.1.0" s.summary = "Framework to visually warn you when retain cycle / leak happens." s.description = <<-DESC Mini framework that can surface retain cycle issues sooner. diff --git a/README.md b/README.md index e9107b3..a3f57ff 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,12 @@ To Integrate visual notifications simply add following line at the start of `App ```swift #if DEBUG - LifetimeTracker.setup(onUpdate: LifetimeTrackerDashboardIntegration().refreshUI) + LifetimeTracker.setup(onUpdate: LifetimeTrackerDashboardIntegration(visibility: .visibleWithIssuesDetected).refreshUI) #endif ``` +You can control when the dashboard is visible: `alwaysVisible`, `alwaysHidden`, or `visibleWithIssuesDetected`. + ## Tracking key actors Usually you want to use LifetimeTracker to track only key actors in your app, like ViewModels / Controllers etc.