├── .gitignore
├── Configs
├── LifetimeTracker.plist
└── LifetimeTrackerTests.plist
├── Example
├── .swift-version
├── Example.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── LifetimeTracker-Example.xcscheme
├── Example.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── LifetimeTracker
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
│ ├── Images.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ └── ViewController.swift
├── Podfile
├── Podfile.lock
├── Pods
│ ├── Local Podspecs
│ │ └── LifetimeTracker.podspec.json
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ │ └── project.pbxproj
│ └── Target Support Files
│ │ ├── LifetimeTracker
│ │ ├── Info.plist
│ │ ├── LifetimeTracker-Info.plist
│ │ ├── LifetimeTracker-dummy.m
│ │ ├── LifetimeTracker-prefix.pch
│ │ ├── LifetimeTracker-umbrella.h
│ │ ├── LifetimeTracker.debug.xcconfig
│ │ ├── LifetimeTracker.modulemap
│ │ ├── LifetimeTracker.release.xcconfig
│ │ ├── LifetimeTracker.xcconfig
│ │ ├── ResourceBundle-LifetimeTracker-Info.plist
│ │ └── ResourceBundle-LifetimeTracker-LifetimeTracker-Info.plist
│ │ ├── Pods-Example
│ │ ├── Info.plist
│ │ ├── Pods-Example-Info.plist
│ │ ├── Pods-Example-acknowledgements.markdown
│ │ ├── Pods-Example-acknowledgements.plist
│ │ ├── Pods-Example-dummy.m
│ │ ├── Pods-Example-frameworks.sh
│ │ ├── Pods-Example-resources.sh
│ │ ├── Pods-Example-umbrella.h
│ │ ├── Pods-Example.debug.xcconfig
│ │ ├── Pods-Example.modulemap
│ │ └── Pods-Example.release.xcconfig
│ │ └── Pods-Example_Tests
│ │ ├── Info.plist
│ │ ├── Pods-Example_Tests-Info.plist
│ │ ├── Pods-Example_Tests-acknowledgements.markdown
│ │ ├── Pods-Example_Tests-acknowledgements.plist
│ │ ├── Pods-Example_Tests-dummy.m
│ │ ├── Pods-Example_Tests-frameworks.sh
│ │ ├── Pods-Example_Tests-resources.sh
│ │ ├── Pods-Example_Tests-umbrella.h
│ │ ├── Pods-Example_Tests.debug.xcconfig
│ │ ├── Pods-Example_Tests.modulemap
│ │ └── Pods-Example_Tests.release.xcconfig
└── Tests
│ ├── Info.plist
│ └── Tests.swift
├── ExampleObjC
├── ExampleObjC.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── ExampleObjC.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── ExampleObjC
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
├── Podfile
├── Podfile.lock
└── Pods
│ ├── Local Podspecs
│ └── LifetimeTracker.podspec.json
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ └── project.pbxproj
│ └── Target Support Files
│ ├── LifetimeTracker
│ ├── Info.plist
│ ├── LifetimeTracker-Info.plist
│ ├── LifetimeTracker-dummy.m
│ ├── LifetimeTracker-prefix.pch
│ ├── LifetimeTracker-umbrella.h
│ ├── LifetimeTracker.modulemap
│ ├── LifetimeTracker.xcconfig
│ ├── ResourceBundle-LifetimeTracker-Info.plist
│ └── ResourceBundle-LifetimeTracker-LifetimeTracker-Info.plist
│ └── Pods-ExampleObjC
│ ├── Info.plist
│ ├── Pods-ExampleObjC-Info.plist
│ ├── Pods-ExampleObjC-acknowledgements.markdown
│ ├── Pods-ExampleObjC-acknowledgements.plist
│ ├── Pods-ExampleObjC-dummy.m
│ ├── Pods-ExampleObjC-frameworks.sh
│ ├── Pods-ExampleObjC-resources.sh
│ ├── Pods-ExampleObjC-umbrella.h
│ ├── Pods-ExampleObjC.debug.xcconfig
│ ├── Pods-ExampleObjC.modulemap
│ └── Pods-ExampleObjC.release.xcconfig
├── Funding.yml
├── LICENSE
├── LifetimeTracker.podspec
├── LifetimeTracker.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ ├── LifetimeTracker-iOS.xcscheme
│ ├── LifetimeTracker-macOS.xcscheme
│ ├── LifetimeTracker-tvOS.xcscheme
│ └── LifetimeTracker-watchOS.xcscheme
├── Package.swift
├── README.md
├── Resources
├── demo-bar.gif
├── demo-circular.gif
└── ignore.swift
├── Sources
├── Bundle+Extensions.swift
├── Constants.swift
├── DeallocTracker.swift
├── Extensions.swift
├── LifetimeTracker.swift
├── Localizable.strings
├── Resources
│ ├── BarDashboard.storyboard
│ ├── CircularDashboard.storyboard
│ ├── DashboardTableView.storyboard
│ ├── DashboardTableViewCell.xib
│ └── DashboardTableViewHeaderView.xib
└── iOS
│ ├── SettingsManager.swift
│ └── UI
│ ├── BarDashboard
│ └── BarDashboardViewController.swift
│ ├── CircularDashboard
│ └── CircularDashboardViewController.swift
│ ├── Constants+UIKit.swift
│ ├── DashboardTableView
│ ├── DashboardTableViewCell.swift
│ ├── DashboardTableViewController.swift
│ └── DashboardTableViewHeaderView.swift
│ ├── Extensions+UIKit.swift
│ ├── HideOption.swift
│ ├── LifetimeTracker+DashboardView.swift
│ └── LifetimeTrackerListViewController.swift
└── Tests
├── LifetimeTrackerTests
├── LifetimeTrackerTests.swift
└── VisibilityTests.swift
└── LinuxMain.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 | .DS_Store
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 | *.dSYM.zip
30 | *.dSYM
31 |
32 | ## Playgrounds
33 | timeline.xctimeline
34 | playground.xcworkspace
35 |
36 | # Swift Package Manager
37 | #
38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
39 | # Packages/
40 | # Package.pins
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots
68 | fastlane/test_output
69 |
--------------------------------------------------------------------------------
/Configs/LifetimeTracker.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2017 Krzysztof Zablocki. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Configs/LifetimeTrackerTests.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/.swift-version:
--------------------------------------------------------------------------------
1 | 5.0
2 |
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/xcshareddata/xcschemes/LifetimeTracker-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
51 |
52 |
53 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
76 |
78 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/Example/Example.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/LifetimeTracker/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Krzysztof Zablocki on 07/31/2017.
6 | // Copyright (c) 2017 Krzysztof Zablocki. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import LifetimeTracker
11 |
12 |
13 | @UIApplicationMain
14 | class AppDelegate: UIResponder, UIApplicationDelegate {
15 |
16 | var window: UIWindow?
17 | var extraVC = [UIViewController]()
18 |
19 |
20 | internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
21 | #if DEBUG
22 | LifetimeTracker.setup(
23 | onUpdate: LifetimeTrackerDashboardIntegration(
24 | visibility: .alwaysVisible,
25 | style: .bar,
26 | textColorForNoIssues: .systemGreen,
27 | textColorForLeakDetected: .systemRed
28 | ).refreshUI
29 | )
30 | #else
31 | #endif
32 |
33 | window = UIWindow()
34 | window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
35 | window?.makeKeyAndVisible()
36 | return true
37 | }
38 |
39 | func applicationWillResignActive(_ application: UIApplication) {
40 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
41 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
42 | }
43 |
44 | func applicationDidEnterBackground(_ application: UIApplication) {
45 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
46 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
47 | }
48 |
49 | func applicationWillEnterForeground(_ application: UIApplication) {
50 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
51 | }
52 |
53 | func applicationDidBecomeActive(_ application: UIApplication) {
54 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
55 | }
56 |
57 | func applicationWillTerminate(_ application: UIApplication) {
58 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
59 | }
60 |
61 |
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/Example/LifetimeTracker/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Example/LifetimeTracker/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
31 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Example/LifetimeTracker/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Example/LifetimeTracker/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Example/LifetimeTracker/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Krzysztof Zablocki on 07/31/2017.
6 | // Copyright (c) 2017 Krzysztof Zablocki. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import LifetimeTracker
11 |
12 | // MARK: - DetailItem -
13 |
14 | class DetailItem: LifetimeTrackable {
15 |
16 | class var lifetimeConfiguration: LifetimeConfiguration {
17 | // There can be up to three 3 instances from the class. But only three in total including the subclasses
18 | return LifetimeConfiguration(maxCount: 3, groupName: "Detail Item", groupMaxCount: 3)
19 | }
20 |
21 | init() {
22 | self.trackLifetime()
23 | }
24 | }
25 |
26 | // MARK: - DetailItem Subclasses
27 |
28 | class AudtioDetailItem: DetailItem { }
29 | class ImageDetailItem: DetailItem { }
30 | class VideoDetailItem: DetailItem {
31 |
32 | override class var lifetimeConfiguration: LifetimeConfiguration {
33 | // There should only be one video item as the memory usage is too high
34 | let configuration = super.lifetimeConfiguration
35 | configuration.maxCount = 1
36 | return configuration
37 | }
38 | }
39 |
40 | // MARK: - ViewController -
41 |
42 | var leakStorage = [AnyObject]()
43 |
44 | class ViewController: UIViewController, LifetimeTrackable {
45 |
46 | static var lifetimeConfiguration = LifetimeConfiguration(maxCount: 1, groupName: "VC")
47 |
48 | // MARK: - Initialization
49 |
50 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
51 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
52 |
53 | trackLifetime()
54 |
55 | }
56 |
57 | required init?(coder aDecoder: NSCoder) {
58 | super.init(coder: aDecoder)
59 |
60 | trackLifetime()
61 | }
62 |
63 | // MARK: - IBActions
64 |
65 | @IBAction func createLeak(_ sender: Any) {
66 | leakStorage.append(ViewController())
67 |
68 | leakStorage.append(AudtioDetailItem())
69 | leakStorage.append(ImageDetailItem())
70 | leakStorage.append(VideoDetailItem())
71 | }
72 |
73 | @IBAction func removeLeaks(_ sender: Any) {
74 | leakStorage.removeAll()
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '8.0'
2 |
3 | use_frameworks!
4 |
5 | target 'Example' do
6 |
7 | pod 'LifetimeTracker', :path => '../'
8 |
9 | target 'Example_Tests' do
10 | inherit! :search_paths
11 | end
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - LifetimeTracker (1.8.1)
3 |
4 | DEPENDENCIES:
5 | - LifetimeTracker (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | LifetimeTracker:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | LifetimeTracker: be33b0d89357dd2f381eb8aca636d184b538d5e9
13 |
14 | PODFILE CHECKSUM: e91e3be8fb02f5c6156c564a223f1b57ddffa7f5
15 |
16 | COCOAPODS: 1.11.2
17 |
--------------------------------------------------------------------------------
/Example/Pods/Local Podspecs/LifetimeTracker.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "LifetimeTracker",
3 | "version": "1.8.1",
4 | "summary": "Framework to visually warn you when retain cycle / leak happens.",
5 | "description": "Mini framework that can surface retain cycle issues sooner.",
6 | "homepage": "https://github.com/krzysztofzablocki/LifetimeTracker",
7 | "license": {
8 | "type": "MIT",
9 | "file": "LICENSE"
10 | },
11 | "authors": {
12 | "Krzysztof Zablocki": "krzysztof.zablocki@pixle.pl"
13 | },
14 | "social_media_url": "http://twitter.com/merowing_",
15 | "platforms": {
16 | "ios": "8.0",
17 | "osx": "10.10"
18 | },
19 | "source": {
20 | "git": "https://github.com/krzysztofzablocki/LifetimeTracker.git",
21 | "tag": "1.8.1"
22 | },
23 | "ios": {
24 | "source_files": [
25 | "Sources/*.swift",
26 | "Sources/iOS/**/*.swift"
27 | ],
28 | "resources": "Sources/Resources/**/*.{xib,storyboard}",
29 | "frameworks": [
30 | "Foundation",
31 | "UIKit"
32 | ]
33 | },
34 | "osx": {
35 | "source_files": "Sources/*.swift",
36 | "frameworks": [
37 | "Foundation"
38 | ]
39 | },
40 | "resource_bundles": {
41 | "LifetimeTracker": [
42 | "Sources/**/*.{strings}"
43 | ]
44 | },
45 | "swift_versions": "5.0",
46 | "swift_version": "5.0"
47 | }
48 |
--------------------------------------------------------------------------------
/Example/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - LifetimeTracker (1.8.1)
3 |
4 | DEPENDENCIES:
5 | - LifetimeTracker (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | LifetimeTracker:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | LifetimeTracker: be33b0d89357dd2f381eb8aca636d184b538d5e9
13 |
14 | PODFILE CHECKSUM: e91e3be8fb02f5c6156c564a223f1b57ddffa7f5
15 |
16 | COCOAPODS: 1.11.2
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.5.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/LifetimeTracker-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.8.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/LifetimeTracker-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_LifetimeTracker : NSObject
3 | @end
4 | @implementation PodsDummy_LifetimeTracker
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/LifetimeTracker-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/LifetimeTracker-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double LifetimeTrackerVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char LifetimeTrackerVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/LifetimeTracker.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
5 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "UIKit"
6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_ROOT = ${SRCROOT}
10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
13 | SKIP_INSTALL = YES
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/LifetimeTracker.modulemap:
--------------------------------------------------------------------------------
1 | framework module LifetimeTracker {
2 | umbrella header "LifetimeTracker-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/LifetimeTracker.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
5 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "UIKit"
6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_ROOT = ${SRCROOT}
10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
13 | SKIP_INSTALL = YES
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/LifetimeTracker.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "UIKit"
4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/ResourceBundle-LifetimeTracker-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleIdentifier
8 | ${PRODUCT_BUNDLE_IDENTIFIER}
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundleName
12 | ${PRODUCT_NAME}
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.5.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/LifetimeTracker/ResourceBundle-LifetimeTracker-LifetimeTracker-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleIdentifier
8 | ${PRODUCT_BUNDLE_IDENTIFIER}
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundleName
12 | ${PRODUCT_NAME}
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.8.1
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## LifetimeTracker
5 |
6 | The MIT License (MIT)
7 |
8 | Copyright (c) 2017 Krzysztof Zablocki
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 |
28 |
29 | Generated by CocoaPods - https://cocoapods.org
30 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | The MIT License (MIT)
18 |
19 | Copyright (c) 2017 Krzysztof Zablocki
20 |
21 | Permission is hereby granted, free of charge, to any person obtaining a copy
22 | of this software and associated documentation files (the "Software"), to deal
23 | in the Software without restriction, including without limitation the rights
24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 | copies of the Software, and to permit persons to whom the Software is
26 | furnished to do so, subject to the following conditions:
27 |
28 | The above copyright notice and this permission notice shall be included in all
29 | copies or substantial portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | SOFTWARE.
38 |
39 |
40 | License
41 | MIT
42 | Title
43 | LifetimeTracker
44 | Type
45 | PSGroupSpecifier
46 |
47 |
48 | FooterText
49 | Generated by CocoaPods - https://cocoapods.org
50 | Title
51 |
52 | Type
53 | PSGroupSpecifier
54 |
55 |
56 | StringsTable
57 | Acknowledgements
58 | Title
59 | Acknowledgements
60 |
61 |
62 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_Example : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_Example
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 | BCSYMBOLMAP_DIR="BCSymbolMaps"
23 |
24 |
25 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
26 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
27 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
28 |
29 | # Copies and strips a vendored framework
30 | install_framework()
31 | {
32 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
33 | local source="${BUILT_PRODUCTS_DIR}/$1"
34 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
35 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
36 | elif [ -r "$1" ]; then
37 | local source="$1"
38 | fi
39 |
40 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
41 |
42 | if [ -L "${source}" ]; then
43 | echo "Symlinked..."
44 | source="$(readlink "${source}")"
45 | fi
46 |
47 | if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
48 | # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
49 | find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
50 | echo "Installing $f"
51 | install_bcsymbolmap "$f" "$destination"
52 | rm "$f"
53 | done
54 | rmdir "${source}/${BCSYMBOLMAP_DIR}"
55 | fi
56 |
57 | # Use filter instead of exclude so missing patterns don't throw errors.
58 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
59 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
60 |
61 | local basename
62 | basename="$(basename -s .framework "$1")"
63 | binary="${destination}/${basename}.framework/${basename}"
64 |
65 | if ! [ -r "$binary" ]; then
66 | binary="${destination}/${basename}"
67 | elif [ -L "${binary}" ]; then
68 | echo "Destination binary is symlinked..."
69 | dirname="$(dirname "${binary}")"
70 | binary="${dirname}/$(readlink "${binary}")"
71 | fi
72 |
73 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
74 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
75 | strip_invalid_archs "$binary"
76 | fi
77 |
78 | # Resign the code if required by the build settings to avoid unstable apps
79 | code_sign_if_enabled "${destination}/$(basename "$1")"
80 |
81 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
82 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
83 | local swift_runtime_libs
84 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
85 | for lib in $swift_runtime_libs; do
86 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
87 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
88 | code_sign_if_enabled "${destination}/${lib}"
89 | done
90 | fi
91 | }
92 | # Copies and strips a vendored dSYM
93 | install_dsym() {
94 | local source="$1"
95 | warn_missing_arch=${2:-true}
96 | if [ -r "$source" ]; then
97 | # Copy the dSYM into the targets temp dir.
98 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
99 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
100 |
101 | local basename
102 | basename="$(basename -s .dSYM "$source")"
103 | binary_name="$(ls "$source/Contents/Resources/DWARF")"
104 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
105 |
106 | # Strip invalid architectures from the dSYM.
107 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
108 | strip_invalid_archs "$binary" "$warn_missing_arch"
109 | fi
110 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
111 | # Move the stripped file into its final destination.
112 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
113 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
114 | else
115 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
116 | mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
117 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
118 | fi
119 | fi
120 | }
121 |
122 | # Used as a return value for each invocation of `strip_invalid_archs` function.
123 | STRIP_BINARY_RETVAL=0
124 |
125 | # Strip invalid architectures
126 | strip_invalid_archs() {
127 | binary="$1"
128 | warn_missing_arch=${2:-true}
129 | # Get architectures for current target binary
130 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
131 | # Intersect them with the architectures we are building for
132 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
133 | # If there are no archs supported by this binary then warn the user
134 | if [[ -z "$intersected_archs" ]]; then
135 | if [[ "$warn_missing_arch" == "true" ]]; then
136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
137 | fi
138 | STRIP_BINARY_RETVAL=1
139 | return
140 | fi
141 | stripped=""
142 | for arch in $binary_archs; do
143 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
144 | # Strip non-valid architectures in-place
145 | lipo -remove "$arch" -output "$binary" "$binary"
146 | stripped="$stripped $arch"
147 | fi
148 | done
149 | if [[ "$stripped" ]]; then
150 | echo "Stripped $binary of architectures:$stripped"
151 | fi
152 | STRIP_BINARY_RETVAL=0
153 | }
154 |
155 | # Copies the bcsymbolmap files of a vendored framework
156 | install_bcsymbolmap() {
157 | local bcsymbolmap_path="$1"
158 | local destination="${BUILT_PRODUCTS_DIR}"
159 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
160 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
161 | }
162 |
163 | # Signs a framework with the provided identity
164 | code_sign_if_enabled() {
165 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
166 | # Use the current code_sign_identity
167 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
168 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
169 |
170 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
171 | code_sign_cmd="$code_sign_cmd &"
172 | fi
173 | echo "$code_sign_cmd"
174 | eval "$code_sign_cmd"
175 | fi
176 | }
177 |
178 | if [[ "$CONFIGURATION" == "Debug" ]]; then
179 | install_framework "${BUILT_PRODUCTS_DIR}/LifetimeTracker/LifetimeTracker.framework"
180 | fi
181 | if [[ "$CONFIGURATION" == "Release" ]]; then
182 | install_framework "${BUILT_PRODUCTS_DIR}/LifetimeTracker/LifetimeTracker.framework"
183 | fi
184 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
185 | wait
186 | fi
187 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
8 | # resources to, so exit 0 (signalling the script phase was successful).
9 | exit 0
10 | fi
11 |
12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
13 |
14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
15 | > "$RESOURCES_TO_COPY"
16 |
17 | XCASSET_FILES=()
18 |
19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
22 |
23 | case "${TARGETED_DEVICE_FAMILY:-}" in
24 | 1,2)
25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
26 | ;;
27 | 1)
28 | TARGET_DEVICE_ARGS="--target-device iphone"
29 | ;;
30 | 2)
31 | TARGET_DEVICE_ARGS="--target-device ipad"
32 | ;;
33 | 3)
34 | TARGET_DEVICE_ARGS="--target-device tv"
35 | ;;
36 | 4)
37 | TARGET_DEVICE_ARGS="--target-device watch"
38 | ;;
39 | *)
40 | TARGET_DEVICE_ARGS="--target-device mac"
41 | ;;
42 | esac
43 |
44 | install_resource()
45 | {
46 | if [[ "$1" = /* ]] ; then
47 | RESOURCE_PATH="$1"
48 | else
49 | RESOURCE_PATH="${PODS_ROOT}/$1"
50 | fi
51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
52 | cat << EOM
53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
54 | EOM
55 | exit 1
56 | fi
57 | case $RESOURCE_PATH in
58 | *.storyboard)
59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
61 | ;;
62 | *.xib)
63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
65 | ;;
66 | *.framework)
67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
71 | ;;
72 | *.xcdatamodel)
73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
75 | ;;
76 | *.xcdatamodeld)
77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
79 | ;;
80 | *.xcmappingmodel)
81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
83 | ;;
84 | *.xcassets)
85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
87 | ;;
88 | *)
89 | echo "$RESOURCE_PATH" || true
90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
91 | ;;
92 | esac
93 | }
94 |
95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
100 | fi
101 | rm -f "$RESOURCES_TO_COPY"
102 |
103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
104 | then
105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
107 | while read line; do
108 | if [[ $line != "${PODS_ROOT}*" ]]; then
109 | XCASSET_FILES+=("$line")
110 | fi
111 | done <<<"$OTHER_XCASSETS"
112 |
113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
115 | else
116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
117 | fi
118 | fi
119 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_ExampleVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_ExampleVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker/LifetimeTracker.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "LifetimeTracker" -framework "UIKit"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_Example {
2 | umbrella header "Pods-Example-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker/LifetimeTracker.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "LifetimeTracker" -framework "UIKit"
9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 | PODS_BUILD_DIR = ${BUILD_DIR}
11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 | PODS_ROOT = ${SRCROOT}/Pods
14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
16 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 | Generated by CocoaPods - https://cocoapods.org
4 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Generated by CocoaPods - https://cocoapods.org
18 | Title
19 |
20 | Type
21 | PSGroupSpecifier
22 |
23 |
24 | StringsTable
25 | Acknowledgements
26 | Title
27 | Acknowledgements
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_Example_Tests : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_Example_Tests
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
7 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
8 | # frameworks to, so exit 0 (signalling the script phase was successful).
9 | exit 0
10 | fi
11 |
12 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
13 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
14 |
15 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
16 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
17 |
18 | # Used as a return value for each invocation of `strip_invalid_archs` function.
19 | STRIP_BINARY_RETVAL=0
20 |
21 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
22 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
23 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
24 |
25 | # Copies and strips a vendored framework
26 | install_framework()
27 | {
28 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
29 | local source="${BUILT_PRODUCTS_DIR}/$1"
30 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
31 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
32 | elif [ -r "$1" ]; then
33 | local source="$1"
34 | fi
35 |
36 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
37 |
38 | if [ -L "${source}" ]; then
39 | echo "Symlinked..."
40 | source="$(readlink "${source}")"
41 | fi
42 |
43 | # Use filter instead of exclude so missing patterns don't throw errors.
44 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
45 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
46 |
47 | local basename
48 | basename="$(basename -s .framework "$1")"
49 | binary="${destination}/${basename}.framework/${basename}"
50 | if ! [ -r "$binary" ]; then
51 | binary="${destination}/${basename}"
52 | fi
53 |
54 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
55 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
56 | strip_invalid_archs "$binary"
57 | fi
58 |
59 | # Resign the code if required by the build settings to avoid unstable apps
60 | code_sign_if_enabled "${destination}/$(basename "$1")"
61 |
62 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
63 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
64 | local swift_runtime_libs
65 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
66 | for lib in $swift_runtime_libs; do
67 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
68 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
69 | code_sign_if_enabled "${destination}/${lib}"
70 | done
71 | fi
72 | }
73 |
74 | # Copies and strips a vendored dSYM
75 | install_dsym() {
76 | local source="$1"
77 | if [ -r "$source" ]; then
78 | # Copy the dSYM into a the targets temp dir.
79 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
80 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
81 |
82 | local basename
83 | basename="$(basename -s .framework.dSYM "$source")"
84 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
85 |
86 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
87 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
88 | strip_invalid_archs "$binary"
89 | fi
90 |
91 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
92 | # Move the stripped file into its final destination.
93 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
94 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
95 | else
96 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
97 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
98 | fi
99 | fi
100 | }
101 |
102 | # Signs a framework with the provided identity
103 | code_sign_if_enabled() {
104 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
105 | # Use the current code_sign_identitiy
106 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
107 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
108 |
109 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
110 | code_sign_cmd="$code_sign_cmd &"
111 | fi
112 | echo "$code_sign_cmd"
113 | eval "$code_sign_cmd"
114 | fi
115 | }
116 |
117 | # Strip invalid architectures
118 | strip_invalid_archs() {
119 | binary="$1"
120 | # Get architectures for current target binary
121 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
122 | # Intersect them with the architectures we are building for
123 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
124 | # If there are no archs supported by this binary then warn the user
125 | if [[ -z "$intersected_archs" ]]; then
126 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
127 | STRIP_BINARY_RETVAL=0
128 | return
129 | fi
130 | stripped=""
131 | for arch in $binary_archs; do
132 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
133 | # Strip non-valid architectures in-place
134 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
135 | stripped="$stripped $arch"
136 | fi
137 | done
138 | if [[ "$stripped" ]]; then
139 | echo "Stripped $binary of architectures:$stripped"
140 | fi
141 | STRIP_BINARY_RETVAL=1
142 | }
143 |
144 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
145 | wait
146 | fi
147 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
8 | # resources to, so exit 0 (signalling the script phase was successful).
9 | exit 0
10 | fi
11 |
12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
13 |
14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
15 | > "$RESOURCES_TO_COPY"
16 |
17 | XCASSET_FILES=()
18 |
19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
22 |
23 | case "${TARGETED_DEVICE_FAMILY:-}" in
24 | 1,2)
25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
26 | ;;
27 | 1)
28 | TARGET_DEVICE_ARGS="--target-device iphone"
29 | ;;
30 | 2)
31 | TARGET_DEVICE_ARGS="--target-device ipad"
32 | ;;
33 | 3)
34 | TARGET_DEVICE_ARGS="--target-device tv"
35 | ;;
36 | 4)
37 | TARGET_DEVICE_ARGS="--target-device watch"
38 | ;;
39 | *)
40 | TARGET_DEVICE_ARGS="--target-device mac"
41 | ;;
42 | esac
43 |
44 | install_resource()
45 | {
46 | if [[ "$1" = /* ]] ; then
47 | RESOURCE_PATH="$1"
48 | else
49 | RESOURCE_PATH="${PODS_ROOT}/$1"
50 | fi
51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
52 | cat << EOM
53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
54 | EOM
55 | exit 1
56 | fi
57 | case $RESOURCE_PATH in
58 | *.storyboard)
59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
61 | ;;
62 | *.xib)
63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
65 | ;;
66 | *.framework)
67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
71 | ;;
72 | *.xcdatamodel)
73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
75 | ;;
76 | *.xcdatamodeld)
77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
79 | ;;
80 | *.xcmappingmodel)
81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
83 | ;;
84 | *.xcassets)
85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
87 | ;;
88 | *)
89 | echo "$RESOURCE_PATH" || true
90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
91 | ;;
92 | esac
93 | }
94 |
95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
100 | fi
101 | rm -f "$RESOURCES_TO_COPY"
102 |
103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
104 | then
105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
107 | while read line; do
108 | if [[ $line != "${PODS_ROOT}*" ]]; then
109 | XCASSET_FILES+=("$line")
110 | fi
111 | done <<<"$OTHER_XCASSETS"
112 |
113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
115 | else
116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
117 | fi
118 | fi
119 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_Example_TestsVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_Example_TestsVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker/LifetimeTracker.framework/Headers"
5 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "LifetimeTracker" -framework "UIKit"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_Example_Tests {
2 | umbrella header "Pods-Example_Tests-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-Example_Tests/Pods-Example_Tests.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker/LifetimeTracker.framework/Headers"
5 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "LifetimeTracker" -framework "UIKit"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/Example/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import XCTest
3 | import LifetimeTracker
4 |
5 | class Tests: XCTestCase {
6 |
7 | override func setUp() {
8 | super.setUp()
9 | // Put setup code here. This method is called before the invocation of each test method in the class.
10 | }
11 |
12 | override func tearDown() {
13 | // Put teardown code here. This method is called after the invocation of each test method in the class.
14 | super.tearDown()
15 | }
16 |
17 | func testExample() {
18 | // This is an example of a functional test case.
19 | XCTAssert(true, "Pass")
20 | }
21 |
22 | func testPerformanceExample() {
23 | // This is an example of a performance test case.
24 | self.measure() {
25 | // Put the code you want to measure the time of here.
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // ExampleObjC
4 | //
5 | // Created by Krzysztof Zablocki on 17/01/2018.
6 | // Copyright © 2018 Pixle. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // ExampleObjC
4 | //
5 | // Created by Krzysztof Zablocki on 17/01/2018.
6 | // Copyright © 2018 Pixle. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | @import LifetimeTracker;
11 |
12 | @interface AppDelegate ()
13 |
14 | @end
15 |
16 | @implementation AppDelegate
17 |
18 |
19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
20 | LifetimeTrackerDashboardIntegration *dashboardIntegration = [LifetimeTrackerDashboardIntegration new];
21 | [dashboardIntegration setVisibleWhenIssueDetected];
22 | [dashboardIntegration useBarStyle];
23 | [LifetimeTracker setupOnLeakDetected:^(Entry * _Nonnull entry, EntriesGroup * _Nonnull group) {
24 | NSLog(@"Leak info:%@-%@",entry.name,group.name);
25 | } onUpdate:^(NSDictionary * groups) {
26 | [dashboardIntegration refreshUIWithTrackedGroups: groups];
27 | }];
28 | return YES;
29 | }
30 |
31 |
32 | - (void)applicationWillResignActive:(UIApplication *)application {
33 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
34 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
35 | }
36 |
37 |
38 | - (void)applicationDidEnterBackground:(UIApplication *)application {
39 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
40 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
41 | }
42 |
43 |
44 | - (void)applicationWillEnterForeground:(UIApplication *)application {
45 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
46 | }
47 |
48 |
49 | - (void)applicationDidBecomeActive:(UIApplication *)application {
50 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
51 | }
52 |
53 |
54 | - (void)applicationWillTerminate:(UIApplication *)application {
55 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
56 | }
57 |
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
28 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // ExampleObjC
4 | //
5 | // Created by Krzysztof Zablocki on 17/01/2018.
6 | // Copyright © 2018 Pixle. All rights reserved.
7 | //
8 |
9 | #import
10 | @import LifetimeTracker;
11 |
12 | @interface ViewController : UIViewController
13 |
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // ExampleObjC
4 | //
5 | // Created by Krzysztof Zablocki on 17/01/2018.
6 | // Copyright © 2018 Pixle. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | @interface ViewController ()
12 | @property (nonatomic, retain) NSMutableArray* leakStorage;
13 | @end
14 |
15 | @implementation ViewController
16 | - (instancetype)initWithCoder:(NSCoder *)aDecoder
17 | {
18 | self = [super initWithCoder:aDecoder];
19 | if (self) {
20 | self.leakStorage = [NSMutableArray new];
21 | }
22 |
23 | [self trackLifetime];
24 | return self;
25 | }
26 |
27 | - (instancetype)init
28 | {
29 | self = [super init];
30 | if (self) {
31 | self.leakStorage = [NSMutableArray new];
32 | }
33 | [self trackLifetime];
34 | return self;
35 | }
36 |
37 | + (LifetimeConfiguration *)lifetimeConfiguration {
38 | return [[LifetimeConfiguration alloc] initWithMaxCount:1 groupName:@"VC"];
39 | }
40 |
41 | - (IBAction)createLeaks:(id)sender {
42 | [self.leakStorage addObject:[ViewController new]];
43 | [self.leakStorage addObject:[ViewController new]];
44 | }
45 |
46 | - (IBAction)removeLeaks:(id)sender {
47 | [self.leakStorage removeAllObjects];
48 | }
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/ExampleObjC/ExampleObjC/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // ExampleObjC
4 | //
5 | // Created by Krzysztof Zablocki on 17/01/2018.
6 | // Copyright © 2018 Pixle. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ExampleObjC/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '8.0'
2 |
3 | use_frameworks!
4 |
5 | target 'ExampleObjC' do
6 | pod 'LifetimeTracker', :path => '../'
7 | end
8 |
--------------------------------------------------------------------------------
/ExampleObjC/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - LifetimeTracker (1.7.1)
3 |
4 | DEPENDENCIES:
5 | - LifetimeTracker (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | LifetimeTracker:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | LifetimeTracker: e364d6b8f4de0cd3bcd278b33a80bd1660c6fcaf
13 |
14 | PODFILE CHECKSUM: d7142788e4e191a028bf1f058d7f8e372fac6645
15 |
16 | COCOAPODS: 1.8.4
17 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Local Podspecs/LifetimeTracker.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "LifetimeTracker",
3 | "version": "1.7.1",
4 | "summary": "Framework to visually warn you when retain cycle / leak happens.",
5 | "description": "Mini framework that can surface retain cycle issues sooner.",
6 | "homepage": "https://github.com/krzysztofzablocki/LifetimeTracker",
7 | "license": {
8 | "type": "MIT",
9 | "file": "LICENSE"
10 | },
11 | "authors": {
12 | "Krzysztof Zablocki": "krzysztof.zablocki@pixle.pl"
13 | },
14 | "social_media_url": "http://twitter.com/merowing_",
15 | "platforms": {
16 | "ios": "8.0",
17 | "osx": "10.10"
18 | },
19 | "source": {
20 | "git": "https://github.com/krzysztofzablocki/LifetimeTracker.git",
21 | "tag": "1.7.1"
22 | },
23 | "ios": {
24 | "source_files": [
25 | "Sources/*.swift",
26 | "Sources/iOS/**/*.swift"
27 | ],
28 | "resources": "Sources/iOS/*.{xib,storyboard}",
29 | "frameworks": [
30 | "Foundation",
31 | "UIKit"
32 | ]
33 | },
34 | "osx": {
35 | "source_files": "Sources/*.swift",
36 | "frameworks": [
37 | "Foundation"
38 | ]
39 | },
40 | "resource_bundles": {
41 | "LifetimeTracker": [
42 | "Sources/**/*.{strings}"
43 | ]
44 | },
45 | "swift_versions": "5.0",
46 | "swift_version": "5.0"
47 | }
48 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - LifetimeTracker (1.7.1)
3 |
4 | DEPENDENCIES:
5 | - LifetimeTracker (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | LifetimeTracker:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | LifetimeTracker: e364d6b8f4de0cd3bcd278b33a80bd1660c6fcaf
13 |
14 | PODFILE CHECKSUM: d7142788e4e191a028bf1f058d7f8e372fac6645
15 |
16 | COCOAPODS: 1.8.4
17 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.3.3
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/LifetimeTracker-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.7.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/LifetimeTracker-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_LifetimeTracker : NSObject
3 | @end
4 | @implementation PodsDummy_LifetimeTracker
5 | @end
6 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/LifetimeTracker-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/LifetimeTracker-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double LifetimeTrackerVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char LifetimeTrackerVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/LifetimeTracker.modulemap:
--------------------------------------------------------------------------------
1 | framework module LifetimeTracker {
2 | umbrella header "LifetimeTracker-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/LifetimeTracker.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "UIKit"
4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/ResourceBundle-LifetimeTracker-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleIdentifier
8 | ${PRODUCT_BUNDLE_IDENTIFIER}
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundleName
12 | ${PRODUCT_NAME}
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.3.3
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/LifetimeTracker/ResourceBundle-LifetimeTracker-LifetimeTracker-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleIdentifier
8 | ${PRODUCT_BUNDLE_IDENTIFIER}
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundleName
12 | ${PRODUCT_NAME}
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.7.1
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## LifetimeTracker
5 |
6 | The MIT License (MIT)
7 |
8 | Copyright (c) 2017 Krzysztof Zablocki
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 |
28 |
29 | Generated by CocoaPods - https://cocoapods.org
30 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | The MIT License (MIT)
18 |
19 | Copyright (c) 2017 Krzysztof Zablocki
20 |
21 | Permission is hereby granted, free of charge, to any person obtaining a copy
22 | of this software and associated documentation files (the "Software"), to deal
23 | in the Software without restriction, including without limitation the rights
24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 | copies of the Software, and to permit persons to whom the Software is
26 | furnished to do so, subject to the following conditions:
27 |
28 | The above copyright notice and this permission notice shall be included in all
29 | copies or substantial portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | SOFTWARE.
38 |
39 |
40 | License
41 | MIT
42 | Title
43 | LifetimeTracker
44 | Type
45 | PSGroupSpecifier
46 |
47 |
48 | FooterText
49 | Generated by CocoaPods - https://cocoapods.org
50 | Title
51 |
52 | Type
53 | PSGroupSpecifier
54 |
55 |
56 | StringsTable
57 | Acknowledgements
58 | Title
59 | Acknowledgements
60 |
61 |
62 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_ExampleObjC : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_ExampleObjC
5 | @end
6 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 |
23 | # Used as a return value for each invocation of `strip_invalid_archs` function.
24 | STRIP_BINARY_RETVAL=0
25 |
26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
29 |
30 | # Copies and strips a vendored framework
31 | install_framework()
32 | {
33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
34 | local source="${BUILT_PRODUCTS_DIR}/$1"
35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
37 | elif [ -r "$1" ]; then
38 | local source="$1"
39 | fi
40 |
41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
42 |
43 | if [ -L "${source}" ]; then
44 | echo "Symlinked..."
45 | source="$(readlink "${source}")"
46 | fi
47 |
48 | # Use filter instead of exclude so missing patterns don't throw errors.
49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
51 |
52 | local basename
53 | basename="$(basename -s .framework "$1")"
54 | binary="${destination}/${basename}.framework/${basename}"
55 |
56 | if ! [ -r "$binary" ]; then
57 | binary="${destination}/${basename}"
58 | elif [ -L "${binary}" ]; then
59 | echo "Destination binary is symlinked..."
60 | dirname="$(dirname "${binary}")"
61 | binary="${dirname}/$(readlink "${binary}")"
62 | fi
63 |
64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
66 | strip_invalid_archs "$binary"
67 | fi
68 |
69 | # Resign the code if required by the build settings to avoid unstable apps
70 | code_sign_if_enabled "${destination}/$(basename "$1")"
71 |
72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
74 | local swift_runtime_libs
75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
76 | for lib in $swift_runtime_libs; do
77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
79 | code_sign_if_enabled "${destination}/${lib}"
80 | done
81 | fi
82 | }
83 |
84 | # Copies and strips a vendored dSYM
85 | install_dsym() {
86 | local source="$1"
87 | if [ -r "$source" ]; then
88 | # Copy the dSYM into a the targets temp dir.
89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
91 |
92 | local basename
93 | basename="$(basename -s .framework.dSYM "$source")"
94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
95 |
96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
97 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
98 | strip_invalid_archs "$binary"
99 | fi
100 |
101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
102 | # Move the stripped file into its final destination.
103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
105 | else
106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
108 | fi
109 | fi
110 | }
111 |
112 | # Copies the bcsymbolmap files of a vendored framework
113 | install_bcsymbolmap() {
114 | local bcsymbolmap_path="$1"
115 | local destination="${BUILT_PRODUCTS_DIR}"
116 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
117 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
118 | }
119 |
120 | # Signs a framework with the provided identity
121 | code_sign_if_enabled() {
122 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
123 | # Use the current code_sign_identity
124 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
125 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
126 |
127 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
128 | code_sign_cmd="$code_sign_cmd &"
129 | fi
130 | echo "$code_sign_cmd"
131 | eval "$code_sign_cmd"
132 | fi
133 | }
134 |
135 | # Strip invalid architectures
136 | strip_invalid_archs() {
137 | binary="$1"
138 | # Get architectures for current target binary
139 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
140 | # Intersect them with the architectures we are building for
141 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
142 | # If there are no archs supported by this binary then warn the user
143 | if [[ -z "$intersected_archs" ]]; then
144 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
145 | STRIP_BINARY_RETVAL=0
146 | return
147 | fi
148 | stripped=""
149 | for arch in $binary_archs; do
150 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
151 | # Strip non-valid architectures in-place
152 | lipo -remove "$arch" -output "$binary" "$binary"
153 | stripped="$stripped $arch"
154 | fi
155 | done
156 | if [[ "$stripped" ]]; then
157 | echo "Stripped $binary of architectures:$stripped"
158 | fi
159 | STRIP_BINARY_RETVAL=1
160 | }
161 |
162 |
163 | if [[ "$CONFIGURATION" == "Debug" ]]; then
164 | install_framework "${BUILT_PRODUCTS_DIR}/LifetimeTracker/LifetimeTracker.framework"
165 | fi
166 | if [[ "$CONFIGURATION" == "Release" ]]; then
167 | install_framework "${BUILT_PRODUCTS_DIR}/LifetimeTracker/LifetimeTracker.framework"
168 | fi
169 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
170 | wait
171 | fi
172 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=()
10 |
11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
14 |
15 | case "${TARGETED_DEVICE_FAMILY}" in
16 | 1,2)
17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
18 | ;;
19 | 1)
20 | TARGET_DEVICE_ARGS="--target-device iphone"
21 | ;;
22 | 2)
23 | TARGET_DEVICE_ARGS="--target-device ipad"
24 | ;;
25 | 3)
26 | TARGET_DEVICE_ARGS="--target-device tv"
27 | ;;
28 | 4)
29 | TARGET_DEVICE_ARGS="--target-device watch"
30 | ;;
31 | *)
32 | TARGET_DEVICE_ARGS="--target-device mac"
33 | ;;
34 | esac
35 |
36 | install_resource()
37 | {
38 | if [[ "$1" = /* ]] ; then
39 | RESOURCE_PATH="$1"
40 | else
41 | RESOURCE_PATH="${PODS_ROOT}/$1"
42 | fi
43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
44 | cat << EOM
45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
46 | EOM
47 | exit 1
48 | fi
49 | case $RESOURCE_PATH in
50 | *.storyboard)
51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
53 | ;;
54 | *.xib)
55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
57 | ;;
58 | *.framework)
59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
63 | ;;
64 | *.xcdatamodel)
65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
67 | ;;
68 | *.xcdatamodeld)
69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
71 | ;;
72 | *.xcmappingmodel)
73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
75 | ;;
76 | *.xcassets)
77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
79 | ;;
80 | *)
81 | echo "$RESOURCE_PATH" || true
82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
83 | ;;
84 | esac
85 | }
86 |
87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
92 | fi
93 | rm -f "$RESOURCES_TO_COPY"
94 |
95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
96 | then
97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
99 | while read line; do
100 | if [[ $line != "${PODS_ROOT}*" ]]; then
101 | XCASSET_FILES+=("$line")
102 | fi
103 | done <<<"$OTHER_XCASSETS"
104 |
105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
106 | fi
107 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_ExampleObjCVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_ExampleObjCVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC.debug.xcconfig:
--------------------------------------------------------------------------------
1 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker/LifetimeTracker.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "LifetimeTracker" -framework "UIKit"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_ExampleObjC {
2 | umbrella header "Pods-ExampleObjC-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/ExampleObjC/Pods/Target Support Files/Pods-ExampleObjC/Pods-ExampleObjC.release.xcconfig:
--------------------------------------------------------------------------------
1 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/LifetimeTracker/LifetimeTracker.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "LifetimeTracker" -framework "UIKit"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/Funding.yml:
--------------------------------------------------------------------------------
1 | custom: https://www.merowing.info/membership
2 | github: krzysztofzablocki
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Krzysztof Zablocki
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/LifetimeTracker.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "LifetimeTracker"
3 | s.version = "1.8.3"
4 | s.summary = "Framework to visually warn you when retain cycle / leak happens."
5 | s.description = <<-DESC
6 | Mini framework that can surface retain cycle issues sooner.
7 | DESC
8 | s.homepage = "https://github.com/krzysztofzablocki/LifetimeTracker"
9 | s.license = { :type => "MIT", :file => "LICENSE" }
10 | s.author = { "Krzysztof Zablocki" => "krzysztof.zablocki@pixle.pl" }
11 | s.social_media_url = "http://twitter.com/merowing_"
12 | s.ios.deployment_target = "12.0"
13 | s.osx.deployment_target = '10.13'
14 | s.source = { :git => "https://github.com/krzysztofzablocki/LifetimeTracker.git", :tag => s.version.to_s }
15 | s.ios.source_files = "Sources/*.swift", "Sources/iOS/**/*.swift"
16 | s.macos.source_files = "Sources/*.swift"
17 | s.ios.resources = "Sources/Resources/**/*.{xib,storyboard}"
18 | s.resource_bundle = { "LifetimeTracker" => ["Sources/**/*.{strings}"] }
19 | s.ios.frameworks = ["Foundation", "UIKit"]
20 | s.macos.frameworks = ["Foundation"]
21 | s.swift_version = "5.0"
22 | end
23 |
--------------------------------------------------------------------------------
/LifetimeTracker.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LifetimeTracker.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LifetimeTracker.xcodeproj/xcshareddata/xcschemes/LifetimeTracker-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
64 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/LifetimeTracker.xcodeproj/xcshareddata/xcschemes/LifetimeTracker-macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
64 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/LifetimeTracker.xcodeproj/xcshareddata/xcschemes/LifetimeTracker-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
64 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/LifetimeTracker.xcodeproj/xcshareddata/xcschemes/LifetimeTracker-watchOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
44 |
45 |
51 |
52 |
53 |
54 |
60 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "LifetimeTracker",
7 | defaultLocalization: "en",
8 | products: [
9 | .library(
10 | name: "LifetimeTracker",
11 | targets: ["LifetimeTracker"]
12 | ),
13 | ],
14 | targets: [
15 | .target(
16 | name: "LifetimeTracker",
17 | path: "Sources",
18 | resources: [
19 | .process("Resources"),
20 | .process("Localizable.strings", localization: .default),
21 | ]
22 | )
23 | ]
24 | )
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LifetimeTracker
2 |
3 |
4 | |  | |  |
5 | |:--:| :--: | :--: |
6 | | Bar style | | Circular style |
7 |
8 | LifetimeTracker can surface retain cycle / memory issues right as you develop your application, and it will surface them to you immediately, so you can find them with more ease.
9 |
10 | Instruments and Memory Graph Debugger are great, but too many times, developers forget to check for issues as they close the feature implementation.
11 |
12 | If you use those tools sporadically many of the issues they surface will require you to investigate the cause and cost you a lot of time in the process.
13 |
14 | Other tools like [FBRetainCycleDetector](https://github.com/facebook/FBRetainCycleDetector) rely on objc runtime magic to find the problems, but that means they can't really be used for pure Swift classes. This small tool simply focuses on tracking lifetime of objects which means that it can be used in both Objective-C and Swift codebases, and it doesn't rely on any complex or automatic magic behaviour.
15 |
16 | [**If you'd like to support my work and improve your engineering workflows, check out my SwiftyStack course**](https://www.swiftystack.com/)
17 |
18 | ## Installation
19 |
20 | ### CocoaPods
21 |
22 | Add `pod 'LifetimeTracker'` to your Podfile.
23 |
24 | ### Carthage
25 |
26 | Add `github "krzysztofzablocki/LifetimeTracker"` to your Cartfile.
27 |
28 | ### Swift Package Manager
29 |
30 | Add `LifetimeTracker"` to the dependencies value of your Package.swift.
31 |
32 | ```swift
33 | dependencies: [
34 | .package(url: "https://github.com/krzysztofzablocki/LifetimeTracker.git", .upToNextMajor(from: "1.8.0"))
35 | ]
36 | ```
37 |
38 | ## Integration
39 |
40 | To Integrate visual notifications simply add following line at the start of `AppDelegate(didFinishLaunchingWithOptions:)` or if you are using iOS 13+ SceneDelegates in `scene(willConnectTo:options:)`.
41 |
42 | Swift:
43 |
44 | ```swift
45 | #if DEBUG
46 | LifetimeTracker.setup(
47 | onUpdate: LifetimeTrackerDashboardIntegration(
48 | visibility: .alwaysVisible,
49 | style: .bar,
50 | textColorForNoIssues: .systemGreen,
51 | textColorForLeakDetected: .systemRed
52 | ).refreshUI
53 | )
54 | #endif
55 | ```
56 |
57 | Objective-C:
58 |
59 | ```objc
60 | LifetimeTrackerDashboardIntegration *dashboardIntegration = [LifetimeTrackerDashboardIntegration new];
61 | [dashboardIntegration setVisibleWhenIssueDetected];
62 | [dashboardIntegration useBarStyle];
63 | [LifetimeTracker setupOnUpdate:^(NSDictionary * groups) {
64 | [dashboardIntegration refreshUIWithTrackedGroups: groups];
65 | }];
66 | ```
67 |
68 | You can control when the dashboard is visible: `alwaysVisible`, `alwaysHidden`, or `visibleWithIssuesDetected`.
69 |
70 | There are two styles available. A overlay bar view which shows the detailed list of issues directly on the screen or a circular view which displays only the amount of issues and opens the detailed list as modal view controller.
71 |
72 | ## Tracking key actors
73 |
74 | Usually, you want to use LifetimeTracker to track only key actors in your app, like ViewModels / Controllers etc. When you have more than `maxCount` items alive, the tracker will let you know.
75 |
76 | ### Swift
77 |
78 | You conform to `LifetimeTrackable` and call `trackLifetime()` at the end of your init functions:
79 |
80 | ```swift
81 | class SectionFrontViewController: UIViewController, LifetimeTrackable {
82 | class var lifetimeConfiguration: LifetimeConfiguration {
83 | return LifetimeConfiguration(maxCount: 1, groupName: "VC")
84 | }
85 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
86 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
87 | /// ...
88 | trackLifetime()
89 | }
90 | }
91 | ```
92 |
93 | ### Objective-C
94 |
95 | You conform to `LifetimeTrackable` and call `[self trackLifetime]` at the end of your init functions:
96 |
97 | ```objc
98 | @import LifetimeTracker;
99 |
100 | @interface SectionFrontViewController()
101 |
102 | @implementation SectionFrontViewController
103 |
104 | +(LifetimeConfiguration *)lifetimeConfiguration
105 | {
106 | return [[LifetimeConfiguration alloc] initWithMaxCount:1 groupName:@"VC"];
107 | }
108 |
109 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
110 | {
111 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
112 | if (self) {
113 | /// …
114 | [self trackLifetime];
115 | }
116 | return self;
117 | }
118 | @end
119 | ```
120 |
121 | ## Integrating with [Danger](https://danger.systems)
122 |
123 | If you are using Danger, you can use it to add both checkboxes to each PR to ensure people have verified no retain cycles were created but also to inform you when someone forgets to call `trackLifetime()` function.
124 |
125 | ```ruby
126 | #
127 | # ** FILE CHECKS **
128 | # Checks for certain rules and warns if needed.
129 | # Some rules can be disabled by using // danger:disable rule_name
130 | #
131 | # Rules:
132 | # - Check if the modified file is a View and doesn't implement LifetimeTrackable (lifetime_tracking)
133 |
134 | # Sometimes an added file is also counted as modified. We want the files to be checked only once.
135 | files_to_check = (git.modified_files + git.added_files).uniq
136 | (files_to_check - %w(Dangerfile)).each do |file|
137 | next unless File.file?(file)
138 | # Only check inside swift files
139 | next unless File.extname(file).include?(".swift")
140 |
141 | # Will be used to check if we're inside a comment block.
142 | is_comment_block = false
143 |
144 | # Collects all disabled rules for this file.
145 | disabled_rules = []
146 |
147 | filelines = File.readlines(file)
148 | filelines.each_with_index do |line, index|
149 | if is_comment_block
150 | if line.include?("*/")
151 | is_comment_block = false
152 | end
153 | elsif line.include?("/*")
154 | is_comment_block = true
155 | elsif line.include?("danger:disable")
156 | rule_to_disable = line.split.last
157 | disabled_rules.push(rule_to_disable)
158 | else
159 | # Start our custom line checks
160 | # e.g. you could do something like check for methods that only call the super class' method
161 | #if line.include?("override") and line.include?("func") and filelines[index+1].include?("super") and filelines[index+2].include?("}")
162 | # warn("Override methods which only call super can be removed", file: file, line: index+3)
163 | #end
164 | end
165 | end
166 |
167 | # Only continue checks for Lifetime Trackable types
168 | next unless (File.basename(file).include?("ViewModel") or File.basename(file).include?("ViewController") or File.basename(file).include?("View.swift")) and !File.basename(file).include?("Node") and !File.basename(file).include?("Tests") and !File.basename(file).include?("FlowCoordinator")
169 |
170 | if disabled_rules.include?("lifetime_tracking") == false
171 | if File.readlines(file).grep(/LifetimeTrackable/).any?
172 | fail("You forgot to call trackLifetime() from your initializers in " + File.basename(file, ".*") + " (lifetime_tracking)") unless File.readlines(file).grep(/trackLifetime()/).any?
173 | else
174 | warn("Please add support for LifetimeTrackable to " + File.basename(file, ".*") + " . (lifetime_tracking)")
175 | end
176 | markdown("- [ ] I've verified that showing and hiding " + File.basename(file, ".*") + " doesn't surface any [LifetimeTracker](https://github.com/krzysztofzablocki/LifetimeTracker) issues")
177 | end
178 |
179 | end
180 | ```
181 |
182 | ## Surface last notification from the stack
183 |
184 | Sometimes it is useful to get information about last retain cycle in order to log it to external sources such as analytics/trackers. In order to do that we can update initial configuration with `onLeakDetected`:
185 |
186 | ```objc
187 | [LifetimeTracker setupOnLeakDetected:^(Entry * entry, EntriesGroup * group) {
188 | NSLog(@"POSSIBLE LEAK ALERT: %@ - current count %li, max count %li", entry.name, (long)entry.count, (long)entry.maxCount);
189 | } onUpdate:^(NSDictionary * groups) {
190 | [dashboardIntegration refreshUIWithTrackedGroups: groups];
191 | }];
192 | ```
193 |
194 | ```swift
195 | LifetimeTracker.setup(onLeakDetected: { entity, _ in
196 | log.warning("POSSIBLE LEAK ALERT: \(entity.name) - current count: \(entity.count), max count: \(entity.maxCount)")
197 | }, onUpdate: LifetimeTrackerDashboardIntegration(visibility: .alwaysVisible, style: .bar).refreshUI)
198 | ```
199 |
200 | ## Group tracked objects
201 |
202 | You can group tracked objects together. `maxCount` of a group will be calculated by `maxCount` of all members per default. However, you can override it and provide a separate value to the group with `groupMaxCount`.
203 |
204 | You may want to do this when you have a set of subclasses which can appear x times each, but in total only less than the sum of all subclasses:
205 |
206 | ```swift
207 | // DetailPage: UIViewController
208 |
209 | // VideoDetailPage: DetailItem
210 | LifetimeConfiguration(maxCount: 3, groupName: "Detail Page")
211 |
212 | // ImageDetailPage: DetailItem
213 | LifetimeConfiguration(maxCount: 3, groupName: "Detail Page")
214 |
215 | => Group warning if 7 DetailPage objects are alive
216 |
217 | // VideoDetailPage: DetailItem
218 | LifetimeConfiguration(maxCount: 3, groupName: "Detail Page", groupMaxCount: 3)
219 |
220 | // ImageDetailPage: DetailItem
221 | LifetimeConfiguration(maxCount: 3, groupName: "Detail Page", groupMaxCount: 3)
222 |
223 | => Group warning if 4 DetailPage object are alive
224 |
225 | ```
226 |
227 | ## Writing integration tests for memory leaks
228 |
229 | You can access the summary label using accessibility identifier `LifetimeTracker.summaryLabel`, which allows you to write integration tests that end up with looking up whether any issues were found.
230 |
231 | ## License
232 |
233 | LifetimeTracker is available under the MIT license. See [LICENSE](LICENSE) for more information.
234 |
235 | ## Attributions
236 |
237 | I've used [SwiftPlate](https://github.com/JohnSundell/SwiftPlate) to generate xcodeproj compatible with CocoaPods and Carthage.
238 |
--------------------------------------------------------------------------------
/Resources/demo-bar.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/krzysztofzablocki/LifetimeTracker/30d347811bfcf2f37ef0c2ed7e866269c4f836ad/Resources/demo-bar.gif
--------------------------------------------------------------------------------
/Resources/demo-circular.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/krzysztofzablocki/LifetimeTracker/30d347811bfcf2f37ef0c2ed7e866269c4f836ad/Resources/demo-circular.gif
--------------------------------------------------------------------------------
/Sources/Bundle+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | //
4 | //
5 | // Created by Leo Tsuchiya on 6/6/21.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Bundle {
11 |
12 | /// Returns a package manager appropriate `Bundle`.
13 | static var resolvedBundle: Bundle {
14 | #if SWIFT_PACKAGE
15 | return Bundle.module
16 | #else
17 | return Bundle(for: LifetimeTracker.self)
18 | #endif
19 | }
20 | static var stringBundle: Bundle {
21 | #if SWIFT_PACKAGE
22 | return Bundle.module
23 | #else
24 | let mainBundle = Bundle(for: LifetimeTracker.self)
25 | if let podBundlePath = mainBundle.path(forResource: "LifetimeTracker", ofType: "bundle") {
26 | return Bundle(path: podBundlePath) ?? mainBundle
27 | }
28 | return mainBundle
29 | #endif
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Hans Seiffert on 23.10.17.
6 | // Copyright © 2017 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | internal struct Constants {
12 |
13 | struct Identifier {
14 |
15 | struct EntryGroup {
16 | static let none = "lifetimetracker.nogroup.identifier"
17 | }
18 |
19 | struct Reuse {
20 | static let dashboardCell = "lifetimeTrackerDashboardTableViewCell"
21 | static let dashboardHeader = "lifetimeTrackerDashboardHeaderViewCell"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Sources/DeallocTracker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DeallocTracker.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Krzysztof Zablocki on 9/25/17.
6 | // Copyright © 2017 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | fileprivate final class DeallocTracker {
12 | let onDealloc: () -> Void
13 |
14 | init(onDealloc: @escaping () -> Void) {
15 | self.onDealloc = onDealloc
16 | }
17 |
18 | deinit {
19 | onDealloc()
20 | }
21 | }
22 |
23 | /// Executes action upon deallocation of owner
24 | ///
25 | /// - Parameters:
26 | /// - owner: Owner to track.
27 | /// - closure: Closure to execute.
28 | internal func onDealloc(of owner: Any, closure: @escaping () -> Void) {
29 | let tracker = DeallocTracker(onDealloc: closure)
30 | objc_setAssociatedObject(owner, getID(tracker), tracker, .OBJC_ASSOCIATION_RETAIN)
31 | }
32 |
33 | // https://github.com/atrick/swift-evolution/blob/diagnose-implicit-raw-bitwise/proposals/nnnn-implicit-raw-bitwise-conversion.md#associated-object-string-keys
34 | private func getID(_ object: AnyObject) -> UnsafeRawPointer {
35 | return UnsafeRawPointer(Unmanaged.passUnretained(object).toOpaque())
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Hans Seiffert on 23.10.17.
6 | // Copyright © 2017 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | internal extension String {
12 |
13 | var lt_localized: String {
14 | Bundle.stringBundle.localizedString(forKey: self, value: self, table: nil)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | LifetimeTracker
4 |
5 | Created by Hans Seiffert on 23.10.17.
6 |
7 | */
8 |
9 | "popover.dasboard.title" = "LifetimeTracker";
10 |
11 | "dashboard.header.issue.description.leakDetected" = "Detected";
12 |
13 | "dashboard.header.issue.description.noIssues" = "No issues detected";
14 |
15 | "dashboard.sectionHeader.title.noGroup" = "Others";
16 |
17 | "macCount.notSpecified" = "∞";
18 |
19 | "word.leak" = "leak";
20 |
21 | "word.leaks" = "leaks";
22 |
23 | "settings" = "Settings";
24 |
25 | "settings.cancel" = "Cancel";
26 |
27 | "settings.hide.title" = "Hide LifetimeTracker";
28 |
29 | "settings.hide.sheet.title" = "Hide until ...";
30 |
31 | "settings.hide.sheet.untilMoreIssue" = "more issues are detected";
32 |
33 | "settings.hide.sheet.untilNewType" = "new issue types are detected";
34 |
35 | "settings.hide.sheet.untilRestart" = "the app was restarted";
36 |
--------------------------------------------------------------------------------
/Sources/Resources/DashboardTableView.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Sources/Resources/DashboardTableViewCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/Sources/Resources/DashboardTableViewHeaderView.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Sources/iOS/SettingsManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SettingsManager.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Thanh Duc Do on 23.08.18.
6 | // Copyright © 2018 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct SettingsManager {
12 |
13 | // On iPhone, this has no effect if the alert has preferredStyle: .actionSheet.
14 | // On iPad, this creates a root-less popover which mimics the appearance of an actionSheet
15 | // without requiring a sourceView or barButton.
16 | private static func createRootlessPopover(centeredOn view: UIView, alert: UIAlertController) {
17 | if let popoverController = alert.popoverPresentationController {
18 | popoverController.sourceView = view
19 | popoverController.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
20 | popoverController.permittedArrowDirections = []
21 | }
22 | }
23 |
24 | static func showSettingsActionSheet(on viewController: UIViewController, completionHandler: @escaping (HideOption) -> Void) {
25 | let alert = UIAlertController(title: "settings".lt_localized, message: nil, preferredStyle: .actionSheet)
26 | alert.addAction(UIAlertAction(title: "settings.hide.title".lt_localized, style: .default, handler: { (action: UIAlertAction) in
27 | let alert = UIAlertController(title: "settings.hide.sheet.title".lt_localized, message: nil, preferredStyle: .actionSheet)
28 | alert.addAction(UIAlertAction(title: "settings.hide.sheet.untilMoreIssue".lt_localized, style: .default, handler: { (action: UIAlertAction) in
29 | completionHandler(.untilMoreIssue)
30 | }))
31 | alert.addAction(UIAlertAction(title: "settings.hide.sheet.untilNewType".lt_localized, style: .default, handler: { (action: UIAlertAction) in
32 | completionHandler(.untilNewIssueType)
33 | }))
34 | alert.addAction(UIAlertAction(title: "settings.hide.sheet.untilRestart".lt_localized, style: .default, handler: { (action: UIAlertAction) in
35 | completionHandler(.always)
36 | }))
37 | alert.addAction(UIAlertAction(title: "settings.cancel".lt_localized, style: .cancel, handler: { (action: UIAlertAction) in
38 | completionHandler(.none)
39 | }))
40 | createRootlessPopover(centeredOn: viewController.view, alert: alert)
41 | viewController.present(alert, animated: true, completion: nil)
42 | }))
43 | alert.addAction(UIAlertAction(title: "settings.cancel".lt_localized, style: .cancel, handler: { (action: UIAlertAction) in
44 | completionHandler(.none)
45 | }))
46 |
47 | createRootlessPopover(centeredOn: viewController.view, alert: alert)
48 |
49 | viewController.present(alert, animated: true, completion: nil)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/iOS/UI/BarDashboard/BarDashboardViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarDashboardViewController.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Krzysztof Zablocki on 9/25/17.
6 | //
7 |
8 | import UIKit
9 |
10 | struct BarDashboardViewModel {
11 | let leaksCount: Int
12 | let summary: NSAttributedString
13 | let sections: [GroupModel]
14 | let textColorForNoIssues: UIColor
15 | let textColorForLeakDetected: UIColor
16 |
17 | init(
18 | leaksCount: Int = 0,
19 | summary: NSAttributedString = NSAttributedString(),
20 | sections: [GroupModel] = [],
21 | textColorForNoIssues: UIColor = .systemGreen,
22 | textColorForLeakDetected: UIColor = .systemRed
23 | ) {
24 | self.leaksCount = leaksCount
25 | self.summary = summary
26 | self.sections = sections
27 | self.textColorForNoIssues = textColorForNoIssues
28 | self.textColorForLeakDetected = textColorForLeakDetected
29 | }
30 | }
31 |
32 | final class BarDashboardViewController: UIViewController, LifetimeTrackerViewable {
33 |
34 | enum State {
35 | case open
36 | case closed
37 |
38 | var opposite: State {
39 | switch self {
40 | case .open: return .closed
41 | case .closed: return .open
42 | }
43 | }
44 | }
45 |
46 | enum Edge: Int {
47 | case top
48 | case bottom
49 | }
50 |
51 | class func makeFromNib() -> UIViewController & LifetimeTrackerViewable {
52 | let storyboard = UIStoryboard(name: Constants.Storyboard.barDashboard.name, bundle: .resolvedBundle)
53 | return storyboard.instantiateViewController(withIdentifier: String(describing: self)) as! BarDashboardViewController
54 | }
55 |
56 | private var state: State = .closed {
57 | didSet { clampDragOffset() }
58 | }
59 |
60 | private var hideOption: HideOption = .none {
61 | didSet {
62 | if hideOption != .none {
63 | view.window?.isHidden = true
64 | }
65 | }
66 | }
67 |
68 | fileprivate var dashboardViewModel = BarDashboardViewModel()
69 | @IBOutlet private var tableViewController: DashboardTableViewController?
70 | @IBOutlet private var summaryLabel: UILabel?
71 | @IBOutlet private weak var barView: UIView!
72 | @IBOutlet private weak var headerView: UIView?
73 |
74 | public var edge: Edge = .bottom
75 |
76 | private let closedHeight: CGFloat = Constants.Layout.Dashboard.headerHeight
77 | private var originalOffset: CGFloat = 0
78 | private var dragOffset: CGFloat = 0 {
79 | didSet { relayout() }
80 | }
81 | private var offsetForCloseJumpBack: CGFloat = 0
82 | private var currentScreenSize: CGSize = CGSize.zero
83 | private var fullScreen: Bool = false
84 |
85 | override func viewDidLoad() {
86 | super.viewDidLoad()
87 |
88 | view.translatesAutoresizingMaskIntoConstraints = false
89 |
90 | addTapGestureRecognizer()
91 | addPanGestureRecognizer()
92 | dragOffset = maximumYPosition
93 | }
94 |
95 | override var prefersStatusBarHidden: Bool {
96 | return false
97 | }
98 |
99 | func update(with vm: BarDashboardViewModel) {
100 | summaryLabel?.attributedText = vm.summary
101 |
102 | if hideOption.shouldUIBeShown(oldModel: dashboardViewModel, newModel: vm) {
103 | view.isHidden = false
104 | hideOption = .none
105 | }
106 |
107 | dashboardViewModel = vm
108 |
109 | tableViewController?.update(dashboardViewModel: vm)
110 |
111 | // Update the drag offset as the height might increase. The offset has to be decreased in this case
112 | if (dragOffset + heightToShow) > maximumHeight {
113 | dragOffset = maximumHeight - heightToShow
114 | offsetForCloseJumpBack = maximumHeight - closedHeight
115 | }
116 |
117 | relayout()
118 | }
119 |
120 | override func viewDidLayoutSubviews() {
121 | super.viewDidLayoutSubviews()
122 |
123 | if currentScreenSize != UIScreen.main.bounds.size {
124 | dragOffset = maximumYPosition
125 | offsetForCloseJumpBack = maximumHeight - closedHeight
126 | }
127 | currentScreenSize = UIScreen.main.bounds.size
128 |
129 | relayout()
130 | }
131 |
132 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
133 | if segue.identifier == Constants.Segue.embedDashboardTableView.identifier {
134 | tableViewController = segue.destination as? DashboardTableViewController
135 | tableViewController?.update(dashboardViewModel: dashboardViewModel)
136 | }
137 | }
138 |
139 | // MARK: - Layout
140 |
141 | private var heightToShow: CGFloat {
142 | var height = CGFloat(0)
143 | switch state {
144 | case .closed:
145 | height = closedHeight
146 | case .open:
147 | height = heightToFitTableView
148 | }
149 | return min(maximumHeight, height)
150 | }
151 |
152 | private var minimumYPosition: CGFloat {
153 | if #available(iOS 11, *) {
154 | return view.safeAreaInsets.top
155 | } else {
156 | return 0.0
157 | }
158 | }
159 |
160 | private var maximumHeight: CGFloat {
161 | if #available(iOS 11, *) {
162 | return UIScreen.main.bounds.height - view.safeAreaInsets.top - view.safeAreaInsets.bottom
163 | } else {
164 | return UIScreen.main.bounds.height
165 | }
166 | }
167 |
168 | private var maximumYPosition: CGFloat {
169 | if #available(iOS 11, *) {
170 | return maximumHeight - heightToShow - view.safeAreaInsets.bottom + view.safeAreaInsets.top
171 | } else {
172 | return maximumHeight - heightToShow
173 | }
174 | }
175 |
176 | private var heightToFitTableView: CGFloat {
177 | let size = tableViewController?.contentSize ?? CGSize.zero
178 | return max(Constants.Layout.Dashboard.minTotalHeight, size.height + closedHeight)
179 | }
180 |
181 | private var layoutWidth: CGFloat { return UIScreen.main.bounds.width }
182 |
183 | private func relayout() {
184 | guard let window = view.window else { return }
185 |
186 | // Prevent black areas during device orientation
187 | window.clipsToBounds = true
188 | window.translatesAutoresizingMaskIntoConstraints = true
189 | window.frame = CGRect(x: 0, y: fullScreen ? 0 : dragOffset, width: UIScreen.main.bounds.width, height: fullScreen ? UIScreen.main.bounds.height : heightToShow)
190 | view.layoutIfNeeded()
191 | }
192 |
193 | // MARK: - Expand / collapse
194 |
195 | func addTapGestureRecognizer() {
196 | let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(headerTapped))
197 | headerView?.addGestureRecognizer(tapGestureRecognizer)
198 | }
199 |
200 | @objc func headerTapped() {
201 | if state == .closed {
202 | offsetForCloseJumpBack = dragOffset
203 | }
204 | state = state.opposite
205 |
206 | if state == .closed && offsetForCloseJumpBack == maximumYPosition {
207 | dragOffset = offsetForCloseJumpBack
208 | }
209 |
210 | UIView.animateKeyframes(withDuration: Constants.Layout.animationDuration, delay: 0, options: [.beginFromCurrentState, .calculationModeCubicPaced] , animations: {
211 | self.relayout()
212 | }, completion: nil)
213 | }
214 |
215 | // MARK: - Settings
216 |
217 | @IBAction private func settingsButtonTapped(_ sender: UIButton) {
218 | guard let originalWindowFrame = view.window?.frame.origin else {
219 | return
220 | }
221 | let originalBarFrame = barView.frame
222 | barView.translatesAutoresizingMaskIntoConstraints = true
223 | barView.frame = CGRect(x: originalWindowFrame.x, y: originalWindowFrame.y, width: originalBarFrame.width, height: originalBarFrame.height)
224 | fullScreen = true
225 | relayout()
226 | SettingsManager.showSettingsActionSheet(on: self, completionHandler: { [weak self] (selectedOption: HideOption) in
227 | self?.hideOption = selectedOption
228 | self?.barView.translatesAutoresizingMaskIntoConstraints = false
229 | self?.fullScreen = false
230 | self?.relayout()
231 | })
232 | }
233 |
234 | // MARK: Panning
235 |
236 | func addPanGestureRecognizer() {
237 | let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(toolbarPanned))
238 | view.addGestureRecognizer(panGestureRecognizer)
239 | }
240 |
241 | @objc func toolbarPanned(_ gestureRecognizer: UIPanGestureRecognizer) {
242 | switch gestureRecognizer.state {
243 | case .began:
244 | originalOffset = dragOffset
245 | case .changed:
246 | let translation = gestureRecognizer.translation(in: self.view)
247 | dragOffset = originalOffset + translation.y
248 | clampDragOffset()
249 | if state == .open {
250 | offsetForCloseJumpBack = dragOffset
251 | }
252 | default: break
253 | }
254 | }
255 |
256 | func clampDragOffset() {
257 | if dragOffset < minimumYPosition {
258 | dragOffset = minimumYPosition
259 | } else if dragOffset > maximumYPosition {
260 | dragOffset = maximumYPosition
261 | }
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/Sources/iOS/UI/Constants+UIKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Hans Seiffert on 09.11.17.
6 | // Copyright © 2017 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension Constants {
12 |
13 | struct Layout {
14 | static let animationDuration: TimeInterval = 0.3
15 |
16 | struct Dashboard {
17 | static let headerHeight: CGFloat = 44.0
18 | static let cellHeight: CGFloat = 44
19 | static let minTotalHeight: CGFloat = headerHeight + cellHeight
20 | static let sectionHeaderHeight: CGFloat = 30
21 | }
22 | }
23 |
24 | enum Segue {
25 | case embedDashboardTableView
26 |
27 | var identifier: String {
28 | switch self {
29 | case .embedDashboardTableView: return "embedDashboardTableViewController"
30 | }
31 | }
32 | }
33 |
34 | enum Storyboard {
35 | case circularDashboard
36 | case barDashboard
37 |
38 | var name: String {
39 | switch self {
40 | case .circularDashboard: return "CircularDashboard"
41 | case .barDashboard: return "BarDashboard"
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/iOS/UI/DashboardTableView/DashboardTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DashboardTableViewCell.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Hans Seiffert on 21.10.17.
6 | //
7 |
8 | import UIKit
9 |
10 | class DashboardTableViewCell: UITableViewCell {
11 |
12 | @IBOutlet private weak var groupIndicatorView: UIView!
13 | @IBOutlet private weak var classIndicatorView: UIView!
14 | @IBOutlet private weak var descriptionLabel: UILabel!
15 |
16 | class var nib: UINib {
17 | return UINib(nibName: String(describing: self), bundle: .resolvedBundle)
18 | }
19 |
20 | override func prepareForReuse() {
21 | super.prepareForReuse()
22 | groupIndicatorView.backgroundColor = .clear
23 | classIndicatorView.backgroundColor = .clear
24 | descriptionLabel.text = nil
25 | }
26 |
27 | func setup(groupColor: UIColor, classColor: UIColor, description: String) {
28 | groupIndicatorView.backgroundColor = groupColor
29 | classIndicatorView.backgroundColor = classColor
30 | descriptionLabel.text = description
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/iOS/UI/DashboardTableView/DashboardTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DashboardTableViewController.swift
3 | // LifetimeTracker-iOS
4 | //
5 | // Created by Hans Seiffert on 18.03.18.
6 | // Copyright © 2018 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class DashboardTableViewController: UIViewController {
12 |
13 | @IBOutlet weak var tableView: UITableView?
14 |
15 | fileprivate var dashboardViewModel = BarDashboardViewModel()
16 |
17 | var contentSize: CGSize {
18 | return tableView?.contentSize ?? CGSize.zero
19 | }
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 |
24 | tableView?.register(DashboardTableViewHeaderView.lt_nibInOwnBundle, forHeaderFooterViewReuseIdentifier: Constants.Identifier.Reuse.dashboardHeader)
25 | tableView?.register(DashboardTableViewCell.lt_nibInOwnBundle, forCellReuseIdentifier: Constants.Identifier.Reuse.dashboardCell)
26 |
27 | tableView?.scrollsToTop = false
28 | }
29 |
30 | func update(dashboardViewModel: BarDashboardViewModel) {
31 | self.dashboardViewModel = dashboardViewModel
32 |
33 | tableView?.reloadData()
34 | tableView?.layoutIfNeeded()
35 | }
36 | }
37 |
38 | // MARK: - UITableViewDataSource
39 |
40 | extension DashboardTableViewController: UITableViewDataSource {
41 |
42 | func numberOfSections(in tableView: UITableView) -> Int {
43 | return dashboardViewModel.sections.count
44 | }
45 |
46 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
47 | guard section < dashboardViewModel.sections.count else {
48 | return 0
49 | }
50 |
51 | return dashboardViewModel.sections[section].entries.count
52 | }
53 |
54 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
55 | guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.Identifier.Reuse.dashboardCell, for: indexPath) as? DashboardTableViewCell else {
56 | return UITableViewCell()
57 | }
58 |
59 | let group = dashboardViewModel.sections[indexPath.section]
60 | let entry = group.entries[indexPath.row]
61 | cell.setup(groupColor: group.color, classColor: entry.color, description: entry.description)
62 |
63 | return cell
64 | }
65 |
66 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
67 | return Constants.Layout.Dashboard.cellHeight
68 | }
69 | }
70 |
71 | // MARK: - UITableViewDelegate
72 |
73 | extension DashboardTableViewController: UITableViewDelegate {
74 |
75 | func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
76 | guard section < dashboardViewModel.sections.count,
77 | let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: Constants.Identifier.Reuse.dashboardHeader) as? DashboardTableViewHeaderView else {
78 | return nil
79 | }
80 |
81 | let section = dashboardViewModel.sections[section]
82 | headerView.setup(color: section.color, title: section.title)
83 |
84 | return headerView
85 | }
86 |
87 | func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
88 | return Constants.Layout.Dashboard.sectionHeaderHeight
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Sources/iOS/UI/DashboardTableView/DashboardTableViewHeaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DashboardTableViewHeaderView.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Hans Seiffert on 21.10.17.
6 | //
7 |
8 | import UIKit
9 |
10 | class DashboardTableViewHeaderView: UITableViewHeaderFooterView {
11 |
12 | @IBOutlet private weak var indicatorView: UIView!
13 | @IBOutlet private weak var groupNameLabel: UILabel!
14 |
15 | class var nib: UINib {
16 | return UINib(nibName: String(describing: self), bundle: .resolvedBundle)
17 | }
18 |
19 | override func prepareForReuse() {
20 | super.prepareForReuse()
21 | indicatorView.backgroundColor = .clear
22 | groupNameLabel.text = nil
23 | }
24 |
25 | func setup(color: UIColor, title: String) {
26 | indicatorView.backgroundColor = color
27 | groupNameLabel.text = title
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/iOS/UI/Extensions+UIKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Hans Seiffert on 09.11.17.
6 | // Copyright © 2017 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | internal extension UIView {
12 |
13 | class var lt_nibInOwnBundle: UINib {
14 | return UINib(nibName: String(describing: self), bundle: .resolvedBundle)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/iOS/UI/HideOption.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HideOption.swift
3 | // LifetimeTracker-iOS
4 | //
5 | // Created by Thanh Duc Do on 29.08.18.
6 | // Copyright © 2018 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | enum HideOption {
10 | case untilMoreIssue
11 | case untilNewIssueType
12 | case always
13 | case none
14 |
15 | func shouldUIBeShown(oldModel: BarDashboardViewModel, newModel: BarDashboardViewModel) -> Bool {
16 | switch self {
17 | case .untilMoreIssue:
18 | if oldModel.leaksCount < newModel.leaksCount {
19 | return true
20 | }
21 | return false
22 | case .untilNewIssueType:
23 | var oldGroupModelTitleSet = Set()
24 | for oldGroupModel in oldModel.sections {
25 | oldGroupModelTitleSet.insert(oldGroupModel.groupName)
26 | }
27 |
28 | for newGroupModel in newModel.sections {
29 | if !oldGroupModelTitleSet.contains(newGroupModel.groupName) && newGroupModel.entries.count > newGroupModel.entries.capacity {
30 | return true
31 | } else if let oldGroupModel = oldModel.sections.first(where: { (groupModel: GroupModel) -> Bool in
32 | groupModel.groupName == newGroupModel.groupName
33 | }) {
34 | if oldGroupModel.groupCount<=oldGroupModel.groupMaxCount && newGroupModel.groupCount>newGroupModel.groupMaxCount {
35 | return true
36 | }
37 | }
38 | }
39 | return false
40 | default:
41 | return false
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/iOS/UI/LifetimeTrackerListViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LifetimeTrackerListViewController.swift
3 | // LifetimeTracker-iOS
4 | //
5 | // Created by Hans Seiffert on 18.03.18.
6 | // Copyright © 2018 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol PopoverViewControllerDelegate: AnyObject {
12 | func dismissPopoverViewController()
13 | func changeHideOption(for hideOption: HideOption)
14 | }
15 |
16 | class LifetimeTrackerListViewController: UIViewController {
17 |
18 | weak var delegate: PopoverViewControllerDelegate?
19 |
20 | weak var tableViewController: DashboardTableViewController?
21 |
22 | var dashboardViewModel = BarDashboardViewModel()
23 |
24 | override func viewDidLoad() {
25 | super.viewDidLoad()
26 | }
27 |
28 | @IBAction func closeButtonPressed(_ sender: Any) {
29 | delegate?.dismissPopoverViewController()
30 | }
31 |
32 | @IBAction func settingsButtonPressed(_ sender: Any) {
33 | SettingsManager.showSettingsActionSheet(on: self, completionHandler: { [weak self] (selectedOption: HideOption) in
34 | self?.delegate?.changeHideOption(for: selectedOption)
35 | })
36 | }
37 |
38 | func update(dashboardViewModel: BarDashboardViewModel) {
39 | self.dashboardViewModel = dashboardViewModel
40 |
41 | title = "popover.dasboard.title".lt_localized
42 |
43 | tableViewController?.update(dashboardViewModel: dashboardViewModel)
44 | }
45 |
46 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
47 | if segue.identifier == Constants.Segue.embedDashboardTableView.identifier {
48 | tableViewController = segue.destination as? DashboardTableViewController
49 | tableViewController?.update(dashboardViewModel: dashboardViewModel)
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Tests/LifetimeTrackerTests/LifetimeTrackerTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LifetimeTrackerTests.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Krzysztof Zablocki on 27/07/2017.
6 | // Copyright © 2017 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import LifetimeTracker
12 |
13 | private final class Foo {}
14 |
15 | private final class TrackableObject: NSObject, LifetimeTrackable {
16 |
17 | static var lifetimeConfiguration = LifetimeConfiguration(maxCount: 1, groupName: "TrackableObject")
18 |
19 | override init() {
20 | super.init()
21 |
22 | trackLifetime()
23 | }
24 | }
25 |
26 | class LifetimeTrackerTests: XCTestCase {
27 |
28 | override func setUp() {
29 | LifetimeTracker.setup { (trackedGroups: [String: LifetimeTracker.EntriesGroup]) in
30 | // Nothing to do here
31 | }
32 | }
33 | override func tearDown() {
34 | LifetimeTracker.instance = nil
35 | }
36 |
37 | func testDeallocTrackerFiresOnDealloc() {
38 | var fake: Foo? = Foo()
39 | var wasCalled = false
40 |
41 | onDealloc(of: fake as Any) { wasCalled = true }
42 | fake = nil
43 |
44 | XCTAssertTrue(wasCalled)
45 | }
46 |
47 | func testDeallocTrackerDoesntFire() {
48 | let fake: Foo? = Foo()
49 | var wasCalled = false
50 |
51 | onDealloc(of: fake as Any) { wasCalled = true }
52 |
53 | XCTAssertFalse(wasCalled)
54 | }
55 |
56 | func testEntryMaxCountDoesNotChangeAfterMultipleAllocations() {
57 |
58 | var currentEntryMaxCount: Int? {
59 | return LifetimeTracker.instance?.trackedGroups["TrackableObject"]?.entries[TrackableObject.lifetimeConfiguration.instanceName]?.maxCount
60 | }
61 |
62 | TrackableObject.lifetimeConfiguration = LifetimeConfiguration(maxCount: 1, groupName: "TrackableObject")
63 |
64 | // Create the initial object with a count of 1
65 | let _ = TrackableObject()
66 |
67 | // Test that the inital maxCount is used
68 | XCTAssertEqual(currentEntryMaxCount, 1, "Entry maxCount != 1 after the first initialization")
69 |
70 | // Test that a second allocation doesn't change the initial maxCount
71 | let _ = TrackableObject()
72 | XCTAssertEqual(currentEntryMaxCount, 1, "Entry maxCount != 1 after the first initialization")
73 | }
74 |
75 | func testConfigurationMaxCountIncrementationUpdatesEntryAndGroupMaxCount() {
76 |
77 | var currentEntryMaxCount: Int? {
78 | return LifetimeTracker.instance?.trackedGroups["TrackableObject"]?.entries[TrackableObject.lifetimeConfiguration.instanceName]?.maxCount
79 | }
80 | var currentGroupMaxCount: Int? {
81 | return LifetimeTracker.instance?.trackedGroups["TrackableObject"]?.maxCount
82 | }
83 |
84 | // Create the initial object with a count of 1
85 | TrackableObject.lifetimeConfiguration = LifetimeConfiguration(maxCount: 1, groupName: "TrackableObject")
86 | let _ = TrackableObject()
87 |
88 | // Test that the inital maxCount is used
89 | XCTAssertEqual(currentEntryMaxCount, 1, "Entry maxCount != 1 after the first initialization")
90 | XCTAssertEqual(currentGroupMaxCount, 1, "Group maxCount != 1 after the first initialization")
91 |
92 | // Test that a modification of the objects maxCount with a allocation or deallocation does change the entries and groups maxCount
93 | TrackableObject.lifetimeConfiguration.maxCount = 2
94 | let _ = TrackableObject()
95 | XCTAssertEqual(currentEntryMaxCount, 2, "Entry maxCount != 2 after the modification of maxCount")
96 | XCTAssertEqual(currentGroupMaxCount, 2, "Group maxCount != 2 after the modification of maxCount")
97 | }
98 |
99 | func testConfigurationMaxCountDecrementationUpdatesEntryAndGroupMaxCount() {
100 |
101 | var currentEntryMaxCount: Int? {
102 | return LifetimeTracker.instance?.trackedGroups["TrackableObject"]?.entries[TrackableObject.lifetimeConfiguration.instanceName]?.maxCount
103 | }
104 | var currentGroupMaxCount: Int? {
105 | return LifetimeTracker.instance?.trackedGroups["TrackableObject"]?.maxCount
106 | }
107 |
108 | // Create the initial object with a count of 3
109 | TrackableObject.lifetimeConfiguration = LifetimeConfiguration(maxCount: 3, groupName: "TrackableObject")
110 | let _ = TrackableObject()
111 |
112 | // Test that the inital maxCount is used
113 | XCTAssertEqual(currentEntryMaxCount, 3, "Entry maxCount != 3 after the first initialization")
114 | XCTAssertEqual(currentGroupMaxCount, 3, "Group maxCount != 3 after the first initialization")
115 |
116 | // Test that a modification of the objects maxCount after a new allocation does change the entries and groups maxCount
117 | TrackableObject.lifetimeConfiguration.maxCount = 2
118 | let _ = TrackableObject()
119 | XCTAssertEqual(currentEntryMaxCount, 2, "Entry maxCount != 2 after the modification of maxCount")
120 | XCTAssertEqual(currentGroupMaxCount, 2, "Group maxCount != 2 after the modification of maxCount")
121 | }
122 |
123 | func testConfigurationMaxCountIncrementationDoeNotChangeOverriddenGroupsMaxCount() {
124 |
125 | var currentEntryMaxCount: Int? {
126 | return LifetimeTracker.instance?.trackedGroups["TrackableObject"]?.entries[TrackableObject.lifetimeConfiguration.instanceName]?.maxCount
127 | }
128 | var currentGroupMaxCount: Int? {
129 | return LifetimeTracker.instance?.trackedGroups["TrackableObject"]?.maxCount
130 | }
131 |
132 | // Create the initial object with a count of 3
133 | TrackableObject.lifetimeConfiguration = LifetimeConfiguration(maxCount: 1, groupName: "TrackableObject", groupMaxCount: 2)
134 | let _ = TrackableObject()
135 |
136 | // Test that the inital maxCount is used
137 | XCTAssertEqual(currentEntryMaxCount, 1, "Entry maxCount != 1 after the first initialization")
138 | XCTAssertEqual(currentGroupMaxCount, 2, "Overriden group maxCount != 2 after the first initialization")
139 |
140 | // Test that a modification of the objects maxCount after a new allocation doesn't change the overriden group maxCount
141 | TrackableObject.lifetimeConfiguration.maxCount = 2
142 | let _ = TrackableObject()
143 | XCTAssertEqual(currentEntryMaxCount, 2, "Entry maxCount != 2 after the modification of maxCount")
144 | XCTAssertEqual(currentGroupMaxCount, 2, "Overriden group maxCount != 2 after the modification of maxCount")
145 | }
146 |
147 | func testLeakClosure() {
148 | var hasLeaked = false
149 | LifetimeTracker.instance?.onLeakDetected = { entry, group in
150 | hasLeaked = true
151 | }
152 |
153 | TrackableObject.lifetimeConfiguration = LifetimeConfiguration(maxCount: 1)
154 | var trackables = [TrackableObject]()
155 | trackables.append(TrackableObject())
156 | XCTAssert(!hasLeaked)
157 | trackables.append(TrackableObject())
158 | XCTAssert(hasLeaked)
159 | }
160 |
161 | static var allTests = [
162 | ("testDeallocTrackerFiresOnDealloc", testDeallocTrackerFiresOnDealloc),
163 | ("testDeallocTrackerDoesntFire", testDeallocTrackerDoesntFire),
164 | ("testEntryMaxCountDoesNotChangeAfterMultipleAllocations", testEntryMaxCountDoesNotChangeAfterMultipleAllocations),
165 | ("testConfigurationMaxCountIncrementationUpdatesEntryAndGroupMaxCount", testConfigurationMaxCountIncrementationUpdatesEntryAndGroupMaxCount),
166 | ("testConfigurationMaxCountDecrementationUpdatesEntryAndGroupMaxCount", testConfigurationMaxCountDecrementationUpdatesEntryAndGroupMaxCount),
167 | ("testConfigurationMaxCountIncrementationDoeNotChangeOverriddenGroupsMaxCount", testConfigurationMaxCountIncrementationDoeNotChangeOverriddenGroupsMaxCount),
168 | ("testLeakClosure", testLeakClosure)
169 | ]
170 | }
171 |
--------------------------------------------------------------------------------
/Tests/LifetimeTrackerTests/VisibilityTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VisibilityTests.swift
3 | // LifetimeTracker
4 | //
5 | // Created by Jim Roepcke on 2017-10-24.
6 | // Copyright © 2017 LifetimeTracker. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | @testable import LifetimeTracker
12 |
13 | private typealias Visibility = LifetimeTrackerDashboardIntegration.Visibility
14 |
15 | class VisibilityTests: XCTestCase {
16 |
17 | func testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreNoIssuesToDisplay() {
18 | let behavior = Visibility.alwaysHidden
19 | let hasIssuesToDisplay = false
20 | XCTAssertTrue(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay))
21 | }
22 |
23 | func testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreIssuesToDisplay() {
24 | let behavior = Visibility.alwaysHidden
25 | let hasIssuesToDisplay = true
26 | XCTAssertTrue(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay))
27 | }
28 |
29 | func testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreNoIssuesToDisplay() {
30 | let behavior = Visibility.alwaysVisible
31 | let hasIssuesToDisplay = false
32 | XCTAssertFalse(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay))
33 | }
34 |
35 | func testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreIssuesToDisplay() {
36 | let behavior = Visibility.alwaysVisible
37 | let hasIssuesToDisplay = true
38 | XCTAssertFalse(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay))
39 | }
40 |
41 | func testHidesWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreNoIssuesToDisplay() {
42 | let behavior = Visibility.visibleWithIssuesDetected
43 | let hasIssuesToDisplay = false
44 | XCTAssertTrue(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay))
45 | }
46 |
47 | func testDoesNotHideWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreIssuesToDisplay() {
48 | let behavior = Visibility.visibleWithIssuesDetected
49 | let hasIssuesToDisplay = true
50 | XCTAssertFalse(behavior.windowIsHidden(hasIssuesToDisplay: hasIssuesToDisplay))
51 | }
52 |
53 | static var allTests = [
54 | ("testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreNoIssuesToDisplay", testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreNoIssuesToDisplay),
55 | ("testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreIssuesToDisplay", testHidesWindowWhenBehaviorIsAlwaysHiddenAndThereAreIssuesToDisplay),
56 | ("testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreNoIssuesToDisplay", testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreNoIssuesToDisplay),
57 | ("testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreIssuesToDisplay", testDoesNotHideWindowWhenBehaviorIsAlwaysVisibleAndThereAreIssuesToDisplay),
58 | ("testHidesWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreNoIssuesToDisplay", testHidesWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreNoIssuesToDisplay),
59 | ("testDoesNotHideWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreIssuesToDisplay", testDoesNotHideWindowWhenBehaviorIsVisibleWithIssuesDetectedAndThereAreIssuesToDisplay),
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import LifetimeTrackerTests
3 |
4 | XCTMain([
5 | testCase(LifetimeTrackerTests.allTests),
6 | testCase(VisibilityTests.allTests),
7 | ])
8 |
--------------------------------------------------------------------------------