From 7ab07a8eef9f4f8f78bee8e35a811a0f4411c670 Mon Sep 17 00:00:00 2001 From: An Tran Date: Fri, 16 Jul 2021 10:39:15 +0800 Subject: [PATCH] Add macOS support --- .github/workflows/test.yml | 12 +- .../LeakDetectorTests_Info.plist | 25 + .../LeakDetector_Info.plist | 25 + LeakDetector.xcodeproj/project.pbxproj | 631 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcschemes/LeakDetector-Package.xcscheme | 33 + Package.swift | 3 +- .../LeakDetector+NSViewController.swift | 54 ++ .../LeakDetector+UIViewController.swift | 54 ++ Sources/LeakDetector/LeakDetector.swift | 42 +- .../LeakDetectorTests/LeakDetectorTests.swift | 6 +- 13 files changed, 860 insertions(+), 48 deletions(-) create mode 100644 LeakDetector.xcodeproj/LeakDetectorTests_Info.plist create mode 100644 LeakDetector.xcodeproj/LeakDetector_Info.plist create mode 100644 LeakDetector.xcodeproj/project.pbxproj create mode 100644 LeakDetector.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 LeakDetector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 LeakDetector.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 LeakDetector.xcodeproj/xcshareddata/xcschemes/LeakDetector-Package.xcscheme create mode 100644 Sources/LeakDetector/LeakDetector+NSViewController.swift create mode 100644 Sources/LeakDetector/LeakDetector+UIViewController.swift diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e556b0b..61ec9f3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,8 +10,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@master - - name: Build and test - run: | - xcodebuild clean test -workspace LeakDetectorDemo.xcworkspace -scheme LeakDetectorDemo -destination "${destination}" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO + + - name: Test (iOS) + run: xcodebuild test -project LeakDetector.xcodeproj -scheme LeakDetector-Package -destination "platform=iOS Simulator,name=iPhone 12" + + - name: Test (macOS) + run: xcodebuild test -project LeakDetector.xcodeproj -scheme LeakDetector-Package -destination "platform=macOS" + + - name: Build and test demo app + run: xcodebuild clean test -workspace LeakDetectorDemo.xcworkspace -scheme LeakDetectorDemo -destination "${destination}" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO env: destination: ${{ matrix.destination }} \ No newline at end of file diff --git a/LeakDetector.xcodeproj/LeakDetectorTests_Info.plist b/LeakDetector.xcodeproj/LeakDetectorTests_Info.plist new file mode 100644 index 0000000..7c23420 --- /dev/null +++ b/LeakDetector.xcodeproj/LeakDetectorTests_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/LeakDetector.xcodeproj/LeakDetector_Info.plist b/LeakDetector.xcodeproj/LeakDetector_Info.plist new file mode 100644 index 0000000..57ada9f --- /dev/null +++ b/LeakDetector.xcodeproj/LeakDetector_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/LeakDetector.xcodeproj/project.pbxproj b/LeakDetector.xcodeproj/project.pbxproj new file mode 100644 index 0000000..bb44046 --- /dev/null +++ b/LeakDetector.xcodeproj/project.pbxproj @@ -0,0 +1,631 @@ +// !$*UTF8*$! +{ + archiveVersion = "1"; + objectVersion = "46"; + objects = { + "LeakDetector::LeakDetector" = { + isa = "PBXNativeTarget"; + buildConfigurationList = "OBJ_27"; + buildPhases = ( + "OBJ_30", + "OBJ_36" + ); + dependencies = ( + ); + name = "LeakDetector"; + productName = "LeakDetector"; + productReference = "LeakDetector::LeakDetector::Product"; + productType = "com.apple.product-type.framework"; + }; + "LeakDetector::LeakDetector::Product" = { + isa = "PBXFileReference"; + path = "LeakDetector.framework"; + sourceTree = "BUILT_PRODUCTS_DIR"; + }; + "LeakDetector::LeakDetectorPackageTests::ProductTarget" = { + isa = "PBXAggregateTarget"; + buildConfigurationList = "OBJ_44"; + buildPhases = ( + ); + dependencies = ( + "OBJ_47" + ); + name = "LeakDetectorPackageTests"; + productName = "LeakDetectorPackageTests"; + }; + "LeakDetector::LeakDetectorTests" = { + isa = "PBXNativeTarget"; + buildConfigurationList = "OBJ_49"; + buildPhases = ( + "OBJ_52", + "OBJ_55" + ); + dependencies = ( + "OBJ_57" + ); + name = "LeakDetectorTests"; + productName = "LeakDetectorTests"; + productReference = "LeakDetector::LeakDetectorTests::Product"; + productType = "com.apple.product-type.bundle.unit-test"; + }; + "LeakDetector::LeakDetectorTests::Product" = { + isa = "PBXFileReference"; + path = "LeakDetectorTests.xctest"; + sourceTree = "BUILT_PRODUCTS_DIR"; + }; + "LeakDetector::SwiftPMPackageDescription" = { + isa = "PBXNativeTarget"; + buildConfigurationList = "OBJ_38"; + buildPhases = ( + "OBJ_41" + ); + dependencies = ( + ); + name = "LeakDetectorPackageDescription"; + productName = "LeakDetectorPackageDescription"; + productType = "com.apple.product-type.framework"; + }; + "OBJ_1" = { + isa = "PBXProject"; + attributes = { + LastSwiftMigration = "9999"; + LastUpgradeCheck = "9999"; + }; + buildConfigurationList = "OBJ_2"; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = "en"; + hasScannedForEncodings = "0"; + knownRegions = ( + "en" + ); + mainGroup = "OBJ_5"; + productRefGroup = "OBJ_18"; + projectDirPath = "."; + targets = ( + "LeakDetector::LeakDetector", + "LeakDetector::SwiftPMPackageDescription", + "LeakDetector::LeakDetectorPackageTests::ProductTarget", + "LeakDetector::LeakDetectorTests" + ); + }; + "OBJ_10" = { + isa = "PBXFileReference"; + path = "LeakDetector+UIViewController.swift"; + sourceTree = ""; + }; + "OBJ_11" = { + isa = "PBXFileReference"; + path = "LeakDetector.swift"; + sourceTree = ""; + }; + "OBJ_12" = { + isa = "PBXFileReference"; + path = "Timer.swift"; + sourceTree = ""; + }; + "OBJ_13" = { + isa = "PBXFileReference"; + path = "WeakSet.swift"; + sourceTree = ""; + }; + "OBJ_14" = { + isa = "PBXGroup"; + children = ( + "OBJ_15" + ); + name = "Tests"; + path = ""; + sourceTree = "SOURCE_ROOT"; + }; + "OBJ_15" = { + isa = "PBXGroup"; + children = ( + "OBJ_16", + "OBJ_17" + ); + name = "LeakDetectorTests"; + path = "Tests/LeakDetectorTests"; + sourceTree = "SOURCE_ROOT"; + }; + "OBJ_16" = { + isa = "PBXFileReference"; + path = "LeakDetectorTests.swift"; + sourceTree = ""; + }; + "OBJ_17" = { + isa = "PBXFileReference"; + path = "TimerTests.swift"; + sourceTree = ""; + }; + "OBJ_18" = { + isa = "PBXGroup"; + children = ( + "LeakDetector::LeakDetector::Product", + "LeakDetector::LeakDetectorTests::Product" + ); + name = "Products"; + path = ""; + sourceTree = "BUILT_PRODUCTS_DIR"; + }; + "OBJ_2" = { + isa = "XCConfigurationList"; + buildConfigurations = ( + "OBJ_3", + "OBJ_4" + ); + defaultConfigurationIsVisible = "0"; + defaultConfigurationName = "Release"; + }; + "OBJ_21" = { + isa = "PBXFileReference"; + path = "LeakDetectorDemo"; + sourceTree = "SOURCE_ROOT"; + }; + "OBJ_22" = { + isa = "PBXFileReference"; + path = "LeakDetectorDemoUITests"; + sourceTree = "SOURCE_ROOT"; + }; + "OBJ_23" = { + isa = "PBXFileReference"; + path = "Docs"; + sourceTree = "SOURCE_ROOT"; + }; + "OBJ_24" = { + isa = "PBXFileReference"; + path = "LeakDetectorDemo.xcworkspace"; + sourceTree = "SOURCE_ROOT"; + }; + "OBJ_25" = { + isa = "PBXFileReference"; + path = "README.md"; + sourceTree = ""; + }; + "OBJ_27" = { + isa = "XCConfigurationList"; + buildConfigurations = ( + "OBJ_28", + "OBJ_29" + ); + defaultConfigurationIsVisible = "0"; + defaultConfigurationName = "Release"; + }; + "OBJ_28" = { + isa = "XCBuildConfiguration"; + buildSettings = { + CURRENT_PROJECT_VERSION = "1"; + ENABLE_TESTABILITY = "YES"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks" + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)" + ); + INFOPLIST_FILE = "LeakDetector.xcodeproj/LeakDetector_Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = "13.0"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx" + ); + MACOSX_DEPLOYMENT_TARGET = "10.15"; + OTHER_CFLAGS = ( + "$(inherited)" + ); + OTHER_LDFLAGS = ( + "$(inherited)" + ); + OTHER_SWIFT_FLAGS = ( + "$(inherited)" + ); + PRODUCT_BUNDLE_IDENTIFIER = "LeakDetector"; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = "YES"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( + "$(inherited)" + ); + SWIFT_VERSION = "5.0"; + TARGET_NAME = "LeakDetector"; + TVOS_DEPLOYMENT_TARGET = "9.0"; + WATCHOS_DEPLOYMENT_TARGET = "2.0"; + }; + name = "Debug"; + }; + "OBJ_29" = { + isa = "XCBuildConfiguration"; + buildSettings = { + CURRENT_PROJECT_VERSION = "1"; + ENABLE_TESTABILITY = "YES"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks" + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)" + ); + INFOPLIST_FILE = "LeakDetector.xcodeproj/LeakDetector_Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = "13.0"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx" + ); + MACOSX_DEPLOYMENT_TARGET = "10.15"; + OTHER_CFLAGS = ( + "$(inherited)" + ); + OTHER_LDFLAGS = ( + "$(inherited)" + ); + OTHER_SWIFT_FLAGS = ( + "$(inherited)" + ); + PRODUCT_BUNDLE_IDENTIFIER = "LeakDetector"; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = "YES"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( + "$(inherited)" + ); + SWIFT_VERSION = "5.0"; + TARGET_NAME = "LeakDetector"; + TVOS_DEPLOYMENT_TARGET = "9.0"; + WATCHOS_DEPLOYMENT_TARGET = "2.0"; + }; + name = "Release"; + }; + "OBJ_3" = { + isa = "XCBuildConfiguration"; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = "YES"; + COMBINE_HIDPI_IMAGES = "YES"; + COPY_PHASE_STRIP = "NO"; + DEBUG_INFORMATION_FORMAT = "dwarf"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = "YES"; + GCC_OPTIMIZATION_LEVEL = "0"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "SWIFT_PACKAGE=1", + "DEBUG=1" + ); + MACOSX_DEPLOYMENT_TARGET = "10.10"; + ONLY_ACTIVE_ARCH = "YES"; + OTHER_SWIFT_FLAGS = ( + "$(inherited)", + "-DXcode" + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = "macosx"; + SUPPORTED_PLATFORMS = ( + "$(AVAILABLE_PLATFORMS)" + ); + SUPPORTS_MACCATALYST = "YES"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( + "$(inherited)", + "SWIFT_PACKAGE", + "DEBUG" + ); + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + USE_HEADERMAP = "NO"; + }; + name = "Debug"; + }; + "OBJ_30" = { + isa = "PBXSourcesBuildPhase"; + files = ( + "OBJ_31", + "OBJ_32", + "OBJ_33", + "OBJ_34", + "OBJ_35" + ); + }; + "OBJ_31" = { + isa = "PBXBuildFile"; + fileRef = "OBJ_9"; + }; + "OBJ_32" = { + isa = "PBXBuildFile"; + fileRef = "OBJ_10"; + }; + "OBJ_33" = { + isa = "PBXBuildFile"; + fileRef = "OBJ_11"; + }; + "OBJ_34" = { + isa = "PBXBuildFile"; + fileRef = "OBJ_12"; + }; + "OBJ_35" = { + isa = "PBXBuildFile"; + fileRef = "OBJ_13"; + }; + "OBJ_36" = { + isa = "PBXFrameworksBuildPhase"; + files = ( + ); + }; + "OBJ_38" = { + isa = "XCConfigurationList"; + buildConfigurations = ( + "OBJ_39", + "OBJ_40" + ); + defaultConfigurationIsVisible = "0"; + defaultConfigurationName = "Release"; + }; + "OBJ_39" = { + isa = "XCBuildConfiguration"; + buildSettings = { + LD = "/usr/bin/true"; + OTHER_SWIFT_FLAGS = ( + "-swift-version", + "5", + "-I", + "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2", + "-sdk", + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk", + "-package-description-version", + "5.3.0" + ); + SWIFT_VERSION = "5.0"; + }; + name = "Debug"; + }; + "OBJ_4" = { + isa = "XCBuildConfiguration"; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = "YES"; + COMBINE_HIDPI_IMAGES = "YES"; + COPY_PHASE_STRIP = "YES"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = "s"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "SWIFT_PACKAGE=1" + ); + MACOSX_DEPLOYMENT_TARGET = "10.10"; + OTHER_SWIFT_FLAGS = ( + "$(inherited)", + "-DXcode" + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = "macosx"; + SUPPORTED_PLATFORMS = ( + "$(AVAILABLE_PLATFORMS)" + ); + SUPPORTS_MACCATALYST = "YES"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( + "$(inherited)", + "SWIFT_PACKAGE" + ); + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + USE_HEADERMAP = "NO"; + }; + name = "Release"; + }; + "OBJ_40" = { + isa = "XCBuildConfiguration"; + buildSettings = { + LD = "/usr/bin/true"; + OTHER_SWIFT_FLAGS = ( + "-swift-version", + "5", + "-I", + "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2", + "-sdk", + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk", + "-package-description-version", + "5.3.0" + ); + SWIFT_VERSION = "5.0"; + }; + name = "Release"; + }; + "OBJ_41" = { + isa = "PBXSourcesBuildPhase"; + files = ( + "OBJ_42" + ); + }; + "OBJ_42" = { + isa = "PBXBuildFile"; + fileRef = "OBJ_6"; + }; + "OBJ_44" = { + isa = "XCConfigurationList"; + buildConfigurations = ( + "OBJ_45", + "OBJ_46" + ); + defaultConfigurationIsVisible = "0"; + defaultConfigurationName = "Release"; + }; + "OBJ_45" = { + isa = "XCBuildConfiguration"; + buildSettings = { + }; + name = "Debug"; + }; + "OBJ_46" = { + isa = "XCBuildConfiguration"; + buildSettings = { + }; + name = "Release"; + }; + "OBJ_47" = { + isa = "PBXTargetDependency"; + target = "LeakDetector::LeakDetectorTests"; + }; + "OBJ_49" = { + isa = "XCConfigurationList"; + buildConfigurations = ( + "OBJ_50", + "OBJ_51" + ); + defaultConfigurationIsVisible = "0"; + defaultConfigurationName = "Release"; + }; + "OBJ_5" = { + isa = "PBXGroup"; + children = ( + "OBJ_6", + "OBJ_7", + "OBJ_14", + "OBJ_18", + "OBJ_21", + "OBJ_22", + "OBJ_23", + "OBJ_24", + "OBJ_25" + ); + path = ""; + sourceTree = ""; + }; + "OBJ_50" = { + isa = "XCBuildConfiguration"; + buildSettings = { + CLANG_ENABLE_MODULES = "YES"; + CURRENT_PROJECT_VERSION = "1"; + EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks" + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)" + ); + INFOPLIST_FILE = "LeakDetector.xcodeproj/LeakDetectorTests_Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = "14.0"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@loader_path/../Frameworks", + "@loader_path/Frameworks" + ); + MACOSX_DEPLOYMENT_TARGET = "10.15"; + OTHER_CFLAGS = ( + "$(inherited)" + ); + OTHER_LDFLAGS = ( + "$(inherited)" + ); + OTHER_SWIFT_FLAGS = ( + "$(inherited)" + ); + SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( + "$(inherited)" + ); + SWIFT_VERSION = "5.0"; + TARGET_NAME = "LeakDetectorTests"; + TVOS_DEPLOYMENT_TARGET = "9.0"; + WATCHOS_DEPLOYMENT_TARGET = "7.0"; + }; + name = "Debug"; + }; + "OBJ_51" = { + isa = "XCBuildConfiguration"; + buildSettings = { + CLANG_ENABLE_MODULES = "YES"; + CURRENT_PROJECT_VERSION = "1"; + EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks" + ); + HEADER_SEARCH_PATHS = ( + "$(inherited)" + ); + INFOPLIST_FILE = "LeakDetector.xcodeproj/LeakDetectorTests_Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = "14.0"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@loader_path/../Frameworks", + "@loader_path/Frameworks" + ); + MACOSX_DEPLOYMENT_TARGET = "10.15"; + OTHER_CFLAGS = ( + "$(inherited)" + ); + OTHER_LDFLAGS = ( + "$(inherited)" + ); + OTHER_SWIFT_FLAGS = ( + "$(inherited)" + ); + SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( + "$(inherited)" + ); + SWIFT_VERSION = "5.0"; + TARGET_NAME = "LeakDetectorTests"; + TVOS_DEPLOYMENT_TARGET = "9.0"; + WATCHOS_DEPLOYMENT_TARGET = "7.0"; + }; + name = "Release"; + }; + "OBJ_52" = { + isa = "PBXSourcesBuildPhase"; + files = ( + "OBJ_53", + "OBJ_54" + ); + }; + "OBJ_53" = { + isa = "PBXBuildFile"; + fileRef = "OBJ_16"; + }; + "OBJ_54" = { + isa = "PBXBuildFile"; + fileRef = "OBJ_17"; + }; + "OBJ_55" = { + isa = "PBXFrameworksBuildPhase"; + files = ( + "OBJ_56" + ); + }; + "OBJ_56" = { + isa = "PBXBuildFile"; + fileRef = "LeakDetector::LeakDetector::Product"; + }; + "OBJ_57" = { + isa = "PBXTargetDependency"; + target = "LeakDetector::LeakDetector"; + }; + "OBJ_6" = { + isa = "PBXFileReference"; + explicitFileType = "sourcecode.swift"; + path = "Package.swift"; + sourceTree = ""; + }; + "OBJ_7" = { + isa = "PBXGroup"; + children = ( + "OBJ_8" + ); + name = "Sources"; + path = ""; + sourceTree = "SOURCE_ROOT"; + }; + "OBJ_8" = { + isa = "PBXGroup"; + children = ( + "OBJ_9", + "OBJ_10", + "OBJ_11", + "OBJ_12", + "OBJ_13" + ); + name = "LeakDetector"; + path = "Sources/LeakDetector"; + sourceTree = "SOURCE_ROOT"; + }; + "OBJ_9" = { + isa = "PBXFileReference"; + path = "LeakDetector+NSViewController.swift"; + sourceTree = ""; + }; + }; + rootObject = "OBJ_1"; +} diff --git a/LeakDetector.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/LeakDetector.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..fe1aa71 --- /dev/null +++ b/LeakDetector.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/LeakDetector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/LeakDetector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/LeakDetector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/LeakDetector.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/LeakDetector.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..a72dc2b --- /dev/null +++ b/LeakDetector.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + \ No newline at end of file diff --git a/LeakDetector.xcodeproj/xcshareddata/xcschemes/LeakDetector-Package.xcscheme b/LeakDetector.xcodeproj/xcshareddata/xcschemes/LeakDetector-Package.xcscheme new file mode 100644 index 0000000..aeabaa8 --- /dev/null +++ b/LeakDetector.xcodeproj/xcshareddata/xcschemes/LeakDetector-Package.xcscheme @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Package.swift b/Package.swift index 66ed79d..9bd225f 100644 --- a/Package.swift +++ b/Package.swift @@ -4,7 +4,8 @@ import PackageDescription let package = Package( name: "LeakDetector", platforms: [ - .iOS("13.0"), + .iOS(.v13), + .macOS(.v10_15) ], products: [ .library( diff --git a/Sources/LeakDetector/LeakDetector+NSViewController.swift b/Sources/LeakDetector/LeakDetector+NSViewController.swift new file mode 100644 index 0000000..362eefc --- /dev/null +++ b/Sources/LeakDetector/LeakDetector+NSViewController.swift @@ -0,0 +1,54 @@ +// +// File.swift +// +// +// Created by An Tran on 16.07.21. +// + +import Foundation +#if canImport(Cocoa) +import Cocoa +import Combine + +extension LeakDetector { + + /// Sets up an expectation for the given view controller to be deallocated within the given time. + /// + /// - parameter viewController: The `NSViewController` expected to disappear. + /// - parameter inTime: The time the given view controller is expected to disappear. + /// - returns: `AnyPublisher` that can be used to cancel the expectation. + @discardableResult + public func expectViewControllerDellocated(viewController: NSViewController, inTime time: TimeInterval = .viewDisappearExpectation) -> AnyPublisher { + Timer + .execute(withDelay: time) + .receive(on: DispatchQueue.main) + .handleEvents( + receiveSubscription: { _ in + self.expectationCount += 1 + }, + receiveOutput: { [weak viewController] in + if let viewController = viewController { + let viewDidDisappear = (!viewController.isViewLoaded && viewController.view.window == nil) + let message = "\(viewController) appearance has leaked. Objects are expected to be deallocated at this time: \(self.trackingObjects)" + + if self.isEnabled { + assert(viewDidDisappear, message) + } else if !viewDidDisappear { + print("Leak detection is disabled. This should only be used for debugging purposes.") + print("\(message)") + self.isLeaked.send(message) + } + } + }, + receiveCompletion: { _ in + self.expectationCount -= 1 + }, + receiveCancel: { + self.expectationCount -= 1 + } + ) + .subscribe(on: DispatchQueue.main) + .eraseToAnyPublisher() + } +} +#endif diff --git a/Sources/LeakDetector/LeakDetector+UIViewController.swift b/Sources/LeakDetector/LeakDetector+UIViewController.swift new file mode 100644 index 0000000..4ba2a1f --- /dev/null +++ b/Sources/LeakDetector/LeakDetector+UIViewController.swift @@ -0,0 +1,54 @@ +// +// File.swift +// +// +// Created by An Tran on 16.07.21. +// + +import Foundation +#if canImport(UIKit) +import UIKit +import Combine + +extension LeakDetector { + + /// Sets up an expectation for the given view controller to be deallocated within the given time. + /// + /// - parameter viewController: The `UIViewController` expected to disappear. + /// - parameter inTime: The time the given view controller is expected to disappear. + /// - returns: `AnyPublisher` that can be used to cancel the expectation. + @discardableResult + public func expectViewControllerDellocated(viewController: UIViewController, inTime time: TimeInterval = .viewDisappearExpectation) -> AnyPublisher { + Timer + .execute(withDelay: time) + .receive(on: DispatchQueue.main) + .handleEvents( + receiveSubscription: { _ in + self.expectationCount += 1 + }, + receiveOutput: { [weak viewController] in + if let viewController = viewController { + let viewDidDisappear = (!viewController.isViewLoaded && viewController.view.window == nil) + let message = "\(viewController) appearance has leaked. Objects are expected to be deallocated at this time: \(self.trackingObjects)" + + if self.isEnabled { + assert(viewDidDisappear, message) + } else if !viewDidDisappear { + print("Leak detection is disabled. This should only be used for debugging purposes.") + print("\(message)") + self.isLeaked.send(message) + } + } + }, + receiveCompletion: { _ in + self.expectationCount -= 1 + }, + receiveCancel: { + self.expectationCount -= 1 + } + ) + .subscribe(on: DispatchQueue.main) + .eraseToAnyPublisher() + } +} +#endif diff --git a/Sources/LeakDetector/LeakDetector.swift b/Sources/LeakDetector/LeakDetector.swift index 91ec45b..d45f404 100644 --- a/Sources/LeakDetector/LeakDetector.swift +++ b/Sources/LeakDetector/LeakDetector.swift @@ -4,7 +4,6 @@ import Combine import Foundation -import UIKit /// The default time values used for leak detection expectations. public extension TimeInterval { @@ -46,7 +45,7 @@ public class LeakDetector { // MARK: - Private Interface private(set) var trackingObjects = WeakSet() - @Published private var expectationCount: Int = 0 { + @Published var expectationCount: Int = 0 { didSet { if expectationCount == 0 { // Clear strong key references. @@ -130,45 +129,6 @@ public class LeakDetector { .eraseToAnyPublisher() } - /// Sets up an expectation for the given view controller to be deallocated within the given time. - /// - /// - parameter viewController: The `UIViewController` expected to disappear. - /// - parameter inTime: The time the given view controller is expected to disappear. - /// - returns: `AnyPublisher` that can be used to cancel the expectation. - @discardableResult - public func expectViewControllerDellocated(viewController: UIViewController, inTime time: TimeInterval = .viewDisappearExpectation) -> AnyPublisher { - Timer - .execute(withDelay: time) - .receive(on: DispatchQueue.main) - .handleEvents( - receiveSubscription: { _ in - self.expectationCount += 1 - }, - receiveOutput: { [weak viewController] in - if let viewController = viewController { - let viewDidDisappear = (!viewController.isViewLoaded && viewController.view.window == nil) - let message = "\(viewController) appearance has leaked. Objects are expected to be deallocated at this time: \(self.trackingObjects)" - - if self.isEnabled { - assert(viewDidDisappear, message) - } else if !viewDidDisappear { - print("Leak detection is disabled. This should only be used for debugging purposes.") - print("\(message)") - self.isLeaked.send(message) - } - } - }, - receiveCompletion: { _ in - self.expectationCount -= 1 - }, - receiveCancel: { - self.expectationCount -= 1 - } - ) - .subscribe(on: DispatchQueue.main) - .eraseToAnyPublisher() - } - // MARK: - Internal Interface /// Enable leak detector. Default is false. diff --git a/Tests/LeakDetectorTests/LeakDetectorTests.swift b/Tests/LeakDetectorTests/LeakDetectorTests.swift index f49a5c7..246d089 100644 --- a/Tests/LeakDetectorTests/LeakDetectorTests.swift +++ b/Tests/LeakDetectorTests/LeakDetectorTests.swift @@ -13,7 +13,7 @@ final class LeakDetectorTests: XCTestCase { override func setUp() { super.setUp() - LeakDetector.isEnabled = false + LeakDetector.instance.isEnabled = false parent = Parent() } @@ -48,7 +48,7 @@ final class LeakDetectorTests: XCTestCase { wait(for: [expectation], timeout: .deallocationExpectation + 0.1) - XCTAssertNil(LeakDetector.isLeaked.value) + XCTAssertNil(LeakDetector.instance.isLeaked.value) } func testDetectLeak() { @@ -71,7 +71,7 @@ final class LeakDetectorTests: XCTestCase { wait(for: [expectation], timeout: .deallocationExpectation + 0.1) - XCTAssertNotNil(LeakDetector.isLeaked.value) + XCTAssertNotNil(LeakDetector.instance.isLeaked.value) } }