├── .github
└── FUNDING.yml
├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── GDPerformanceView-Swift.podspec
├── GDPerformanceView-Swift.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── GDPerformanceView-iOS.xcscheme
├── GDPerformanceView-Swift
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── GDPerformanceMonitoring
│ ├── LinkedFramesList.swift
│ ├── MarginLabel.swift
│ ├── PerformanceMonitor.swift
│ ├── PerformanceView.swift
│ ├── PerformanceСalculator.swift
│ ├── Protocols.swift
│ └── WindowViewController.swift
└── Info.plist
├── GDPerformanceView-iOS
├── GDPerformanceView-iOS.h
└── Info.plist
├── LICENSE
├── Package.swift
├── README.md
├── performance_view.PNG
├── performance_view_2.PNG
├── performance_view_3.PNG
└── performance_view_4.PNG
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: ['dani-gavrilov']
4 | # patreon: # Replace with a single Patreon username
5 | # open_collective: # Replace with a single Open Collective username
6 | # ko_fi: # Replace with a single Ko-fi username
7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | # liberapay: # Replace with a single Liberapay username
10 | # issuehunt: # Replace with a single IssueHunt username
11 | # otechie: # Replace with a single Otechie username
12 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 | build/
4 | DerivedData
5 | .idea/
6 | xcuserdata/
7 | *.xcuserdatad
8 | *.xcuserstate
9 | *.xccheckout
10 | *.xcscmblueprint
11 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "GDPerformanceView-Swift"
3 | s.version = "2.1.1"
4 | s.summary = "Shows FPS, CPU and memory usage, device model, app and iOS versions above the status bar and report FPS, CPU and memory usage via delegate."
5 | s.homepage = "https://github.com/dani-gavrilov/GDPerformanceView-Swift"
6 | s.license = { :type => "MIT", :file => "LICENSE" }
7 | s.author = { "Gavrilov Daniil" => "daniilmbox@gmail.com" }
8 | s.platform = :ios, "9.0"
9 | s.ios.deployment_target = "9.0"
10 | s.source = { :git => "https://github.com/dani-gavrilov/GDPerformanceView-Swift.git", :tag => s.version.to_s }
11 | s.source_files = "GDPerformanceView-Swift/GDPerformanceMonitoring/*.swift"
12 | s.frameworks = "UIKit", "Foundation", "QuartzCore"
13 | s.requires_arc = true
14 | s.swift_versions = ['4.2', '5.0']
15 | end
16 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0C340AB821A348C600734F1C /* MarginLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB121A348C600734F1C /* MarginLabel.swift */; };
11 | 0C340AB921A348C600734F1C /* MarginLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB121A348C600734F1C /* MarginLabel.swift */; };
12 | 0C340ABA21A348C600734F1C /* PerformanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB221A348C600734F1C /* PerformanceView.swift */; };
13 | 0C340ABB21A348C600734F1C /* PerformanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB221A348C600734F1C /* PerformanceView.swift */; };
14 | 0C340ABC21A348C600734F1C /* Protocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB321A348C600734F1C /* Protocols.swift */; };
15 | 0C340ABD21A348C600734F1C /* Protocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB321A348C600734F1C /* Protocols.swift */; };
16 | 0C340ABE21A348C600734F1C /* LinkedFramesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB421A348C600734F1C /* LinkedFramesList.swift */; };
17 | 0C340ABF21A348C600734F1C /* LinkedFramesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB421A348C600734F1C /* LinkedFramesList.swift */; };
18 | 0C340AC021A348C600734F1C /* WindowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB521A348C600734F1C /* WindowViewController.swift */; };
19 | 0C340AC121A348C600734F1C /* WindowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB521A348C600734F1C /* WindowViewController.swift */; };
20 | 0C340AC221A348C600734F1C /* PerformanceMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB621A348C600734F1C /* PerformanceMonitor.swift */; };
21 | 0C340AC321A348C600734F1C /* PerformanceMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB621A348C600734F1C /* PerformanceMonitor.swift */; };
22 | 0C340AC421A348C600734F1C /* PerformanceСalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB721A348C600734F1C /* PerformanceСalculator.swift */; };
23 | 0C340AC521A348C600734F1C /* PerformanceСalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C340AB721A348C600734F1C /* PerformanceСalculator.swift */; };
24 | 42AD06F31E1D18C400A5C840 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42AD06E71E1D18C400A5C840 /* AppDelegate.swift */; };
25 | 42AD06F41E1D18C400A5C840 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42AD06E81E1D18C400A5C840 /* Assets.xcassets */; };
26 | 42AD06F51E1D18C400A5C840 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42AD06E91E1D18C400A5C840 /* LaunchScreen.storyboard */; };
27 | 42AD06F61E1D18C400A5C840 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42AD06EB1E1D18C400A5C840 /* Main.storyboard */; };
28 | 42C2CBE81E244D6300A96A93 /* GDPerformanceView-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 42C2CBE61E244D6300A96A93 /* GDPerformanceView-iOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
29 | 42C2CBEB1E244D6300A96A93 /* GDPerformanceView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C2CBE41E244D6300A96A93 /* GDPerformanceView.framework */; };
30 | 42C2CBEC1E244D6300A96A93 /* GDPerformanceView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 42C2CBE41E244D6300A96A93 /* GDPerformanceView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
31 | /* End PBXBuildFile section */
32 |
33 | /* Begin PBXContainerItemProxy section */
34 | 42C2CBE91E244D6300A96A93 /* PBXContainerItemProxy */ = {
35 | isa = PBXContainerItemProxy;
36 | containerPortal = 4237B6D01E0FE2290059FF8B /* Project object */;
37 | proxyType = 1;
38 | remoteGlobalIDString = 42C2CBE31E244D6300A96A93;
39 | remoteInfo = "GDPerformanceView-iOS";
40 | };
41 | /* End PBXContainerItemProxy section */
42 |
43 | /* Begin PBXCopyFilesBuildPhase section */
44 | 42630D0B1E24439C005AAE56 /* Embed Frameworks */ = {
45 | isa = PBXCopyFilesBuildPhase;
46 | buildActionMask = 2147483647;
47 | dstPath = "";
48 | dstSubfolderSpec = 10;
49 | files = (
50 | 42C2CBEC1E244D6300A96A93 /* GDPerformanceView.framework in Embed Frameworks */,
51 | );
52 | name = "Embed Frameworks";
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXCopyFilesBuildPhase section */
56 |
57 | /* Begin PBXFileReference section */
58 | 0C340AB121A348C600734F1C /* MarginLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarginLabel.swift; sourceTree = ""; };
59 | 0C340AB221A348C600734F1C /* PerformanceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceView.swift; sourceTree = ""; };
60 | 0C340AB321A348C600734F1C /* Protocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Protocols.swift; sourceTree = ""; };
61 | 0C340AB421A348C600734F1C /* LinkedFramesList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkedFramesList.swift; sourceTree = ""; };
62 | 0C340AB521A348C600734F1C /* WindowViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowViewController.swift; sourceTree = ""; };
63 | 0C340AB621A348C600734F1C /* PerformanceMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceMonitor.swift; sourceTree = ""; };
64 | 0C340AB721A348C600734F1C /* PerformanceСalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PerformanceСalculator.swift"; sourceTree = ""; };
65 | 4237B6D81E0FE22A0059FF8B /* GDPerformanceView-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "GDPerformanceView-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; };
66 | 42AD06E71E1D18C400A5C840 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
67 | 42AD06E81E1D18C400A5C840 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
68 | 42AD06EA1E1D18C400A5C840 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
69 | 42AD06EC1E1D18C400A5C840 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
70 | 42AD06F11E1D18C400A5C840 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
71 | 42C2CBE41E244D6300A96A93 /* GDPerformanceView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GDPerformanceView.framework; sourceTree = BUILT_PRODUCTS_DIR; };
72 | 42C2CBE61E244D6300A96A93 /* GDPerformanceView-iOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GDPerformanceView-iOS.h"; sourceTree = ""; };
73 | 42C2CBE71E244D6300A96A93 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
74 | /* End PBXFileReference section */
75 |
76 | /* Begin PBXFrameworksBuildPhase section */
77 | 4237B6D51E0FE2290059FF8B /* Frameworks */ = {
78 | isa = PBXFrameworksBuildPhase;
79 | buildActionMask = 2147483647;
80 | files = (
81 | 42C2CBEB1E244D6300A96A93 /* GDPerformanceView.framework in Frameworks */,
82 | );
83 | runOnlyForDeploymentPostprocessing = 0;
84 | };
85 | 42C2CBE01E244D6300A96A93 /* Frameworks */ = {
86 | isa = PBXFrameworksBuildPhase;
87 | buildActionMask = 2147483647;
88 | files = (
89 | );
90 | runOnlyForDeploymentPostprocessing = 0;
91 | };
92 | /* End PBXFrameworksBuildPhase section */
93 |
94 | /* Begin PBXGroup section */
95 | 4237B6CF1E0FE2290059FF8B = {
96 | isa = PBXGroup;
97 | children = (
98 | 42AD06E61E1D18C400A5C840 /* GDPerformanceView-Swift */,
99 | 42C2CBE51E244D6300A96A93 /* GDPerformanceView-iOS */,
100 | 4237B6D91E0FE22A0059FF8B /* Products */,
101 | );
102 | sourceTree = "";
103 | };
104 | 4237B6D91E0FE22A0059FF8B /* Products */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 4237B6D81E0FE22A0059FF8B /* GDPerformanceView-Swift.app */,
108 | 42C2CBE41E244D6300A96A93 /* GDPerformanceView.framework */,
109 | );
110 | name = Products;
111 | sourceTree = "";
112 | };
113 | 42AD06E61E1D18C400A5C840 /* GDPerformanceView-Swift */ = {
114 | isa = PBXGroup;
115 | children = (
116 | 42AD06ED1E1D18C400A5C840 /* GDPerformanceMonitoring */,
117 | 42AD06E71E1D18C400A5C840 /* AppDelegate.swift */,
118 | 42AD06E81E1D18C400A5C840 /* Assets.xcassets */,
119 | 42AD06E91E1D18C400A5C840 /* LaunchScreen.storyboard */,
120 | 42AD06EB1E1D18C400A5C840 /* Main.storyboard */,
121 | 42AD06F11E1D18C400A5C840 /* Info.plist */,
122 | );
123 | path = "GDPerformanceView-Swift";
124 | sourceTree = "";
125 | };
126 | 42AD06ED1E1D18C400A5C840 /* GDPerformanceMonitoring */ = {
127 | isa = PBXGroup;
128 | children = (
129 | 0C340AB621A348C600734F1C /* PerformanceMonitor.swift */,
130 | 0C340AB221A348C600734F1C /* PerformanceView.swift */,
131 | 0C340AB721A348C600734F1C /* PerformanceСalculator.swift */,
132 | 0C340AB521A348C600734F1C /* WindowViewController.swift */,
133 | 0C340AB121A348C600734F1C /* MarginLabel.swift */,
134 | 0C340AB321A348C600734F1C /* Protocols.swift */,
135 | 0C340AB421A348C600734F1C /* LinkedFramesList.swift */,
136 | );
137 | path = GDPerformanceMonitoring;
138 | sourceTree = "";
139 | };
140 | 42C2CBE51E244D6300A96A93 /* GDPerformanceView-iOS */ = {
141 | isa = PBXGroup;
142 | children = (
143 | 42C2CBE61E244D6300A96A93 /* GDPerformanceView-iOS.h */,
144 | 42C2CBE71E244D6300A96A93 /* Info.plist */,
145 | );
146 | path = "GDPerformanceView-iOS";
147 | sourceTree = "";
148 | };
149 | /* End PBXGroup section */
150 |
151 | /* Begin PBXHeadersBuildPhase section */
152 | 42C2CBE11E244D6300A96A93 /* Headers */ = {
153 | isa = PBXHeadersBuildPhase;
154 | buildActionMask = 2147483647;
155 | files = (
156 | 42C2CBE81E244D6300A96A93 /* GDPerformanceView-iOS.h in Headers */,
157 | );
158 | runOnlyForDeploymentPostprocessing = 0;
159 | };
160 | /* End PBXHeadersBuildPhase section */
161 |
162 | /* Begin PBXNativeTarget section */
163 | 4237B6D71E0FE2290059FF8B /* GDPerformanceView-Swift */ = {
164 | isa = PBXNativeTarget;
165 | buildConfigurationList = 4237B6EA1E0FE22A0059FF8B /* Build configuration list for PBXNativeTarget "GDPerformanceView-Swift" */;
166 | buildPhases = (
167 | 4237B6D41E0FE2290059FF8B /* Sources */,
168 | 4237B6D51E0FE2290059FF8B /* Frameworks */,
169 | 4237B6D61E0FE2290059FF8B /* Resources */,
170 | 42630D0B1E24439C005AAE56 /* Embed Frameworks */,
171 | );
172 | buildRules = (
173 | );
174 | dependencies = (
175 | 42C2CBEA1E244D6300A96A93 /* PBXTargetDependency */,
176 | );
177 | name = "GDPerformanceView-Swift";
178 | productName = "GDPerfomanceView-Swift";
179 | productReference = 4237B6D81E0FE22A0059FF8B /* GDPerformanceView-Swift.app */;
180 | productType = "com.apple.product-type.application";
181 | };
182 | 42C2CBE31E244D6300A96A93 /* GDPerformanceView-iOS */ = {
183 | isa = PBXNativeTarget;
184 | buildConfigurationList = 42C2CBED1E244D6300A96A93 /* Build configuration list for PBXNativeTarget "GDPerformanceView-iOS" */;
185 | buildPhases = (
186 | 42C2CBDF1E244D6300A96A93 /* Sources */,
187 | 42C2CBE01E244D6300A96A93 /* Frameworks */,
188 | 42C2CBE11E244D6300A96A93 /* Headers */,
189 | 42C2CBE21E244D6300A96A93 /* Resources */,
190 | );
191 | buildRules = (
192 | );
193 | dependencies = (
194 | );
195 | name = "GDPerformanceView-iOS";
196 | productName = "GDPerformanceView-iOS";
197 | productReference = 42C2CBE41E244D6300A96A93 /* GDPerformanceView.framework */;
198 | productType = "com.apple.product-type.framework";
199 | };
200 | /* End PBXNativeTarget section */
201 |
202 | /* Begin PBXProject section */
203 | 4237B6D01E0FE2290059FF8B /* Project object */ = {
204 | isa = PBXProject;
205 | attributes = {
206 | LastSwiftUpdateCheck = 0820;
207 | LastUpgradeCheck = 1200;
208 | ORGANIZATIONNAME = "Daniil Gavrilov";
209 | TargetAttributes = {
210 | 4237B6D71E0FE2290059FF8B = {
211 | CreatedOnToolsVersion = 8.2;
212 | DevelopmentTeam = RU64C364MT;
213 | ProvisioningStyle = Automatic;
214 | };
215 | 42C2CBE31E244D6300A96A93 = {
216 | CreatedOnToolsVersion = 8.2.1;
217 | DevelopmentTeam = RU64C364MT;
218 | LastSwiftMigration = 1020;
219 | ProvisioningStyle = Automatic;
220 | };
221 | };
222 | };
223 | buildConfigurationList = 4237B6D31E0FE2290059FF8B /* Build configuration list for PBXProject "GDPerformanceView-Swift" */;
224 | compatibilityVersion = "Xcode 3.2";
225 | developmentRegion = en;
226 | hasScannedForEncodings = 0;
227 | knownRegions = (
228 | en,
229 | Base,
230 | );
231 | mainGroup = 4237B6CF1E0FE2290059FF8B;
232 | productRefGroup = 4237B6D91E0FE22A0059FF8B /* Products */;
233 | projectDirPath = "";
234 | projectRoot = "";
235 | targets = (
236 | 4237B6D71E0FE2290059FF8B /* GDPerformanceView-Swift */,
237 | 42C2CBE31E244D6300A96A93 /* GDPerformanceView-iOS */,
238 | );
239 | };
240 | /* End PBXProject section */
241 |
242 | /* Begin PBXResourcesBuildPhase section */
243 | 4237B6D61E0FE2290059FF8B /* Resources */ = {
244 | isa = PBXResourcesBuildPhase;
245 | buildActionMask = 2147483647;
246 | files = (
247 | 42AD06F61E1D18C400A5C840 /* Main.storyboard in Resources */,
248 | 42AD06F41E1D18C400A5C840 /* Assets.xcassets in Resources */,
249 | 42AD06F51E1D18C400A5C840 /* LaunchScreen.storyboard in Resources */,
250 | );
251 | runOnlyForDeploymentPostprocessing = 0;
252 | };
253 | 42C2CBE21E244D6300A96A93 /* Resources */ = {
254 | isa = PBXResourcesBuildPhase;
255 | buildActionMask = 2147483647;
256 | files = (
257 | );
258 | runOnlyForDeploymentPostprocessing = 0;
259 | };
260 | /* End PBXResourcesBuildPhase section */
261 |
262 | /* Begin PBXSourcesBuildPhase section */
263 | 4237B6D41E0FE2290059FF8B /* Sources */ = {
264 | isa = PBXSourcesBuildPhase;
265 | buildActionMask = 2147483647;
266 | files = (
267 | 0C340ABE21A348C600734F1C /* LinkedFramesList.swift in Sources */,
268 | 42AD06F31E1D18C400A5C840 /* AppDelegate.swift in Sources */,
269 | 0C340ABC21A348C600734F1C /* Protocols.swift in Sources */,
270 | 0C340AC221A348C600734F1C /* PerformanceMonitor.swift in Sources */,
271 | 0C340AC421A348C600734F1C /* PerformanceСalculator.swift in Sources */,
272 | 0C340AC021A348C600734F1C /* WindowViewController.swift in Sources */,
273 | 0C340AB821A348C600734F1C /* MarginLabel.swift in Sources */,
274 | 0C340ABA21A348C600734F1C /* PerformanceView.swift in Sources */,
275 | );
276 | runOnlyForDeploymentPostprocessing = 0;
277 | };
278 | 42C2CBDF1E244D6300A96A93 /* Sources */ = {
279 | isa = PBXSourcesBuildPhase;
280 | buildActionMask = 2147483647;
281 | files = (
282 | 0C340AC521A348C600734F1C /* PerformanceСalculator.swift in Sources */,
283 | 0C340AC121A348C600734F1C /* WindowViewController.swift in Sources */,
284 | 0C340AB921A348C600734F1C /* MarginLabel.swift in Sources */,
285 | 0C340ABB21A348C600734F1C /* PerformanceView.swift in Sources */,
286 | 0C340ABF21A348C600734F1C /* LinkedFramesList.swift in Sources */,
287 | 0C340AC321A348C600734F1C /* PerformanceMonitor.swift in Sources */,
288 | 0C340ABD21A348C600734F1C /* Protocols.swift in Sources */,
289 | );
290 | runOnlyForDeploymentPostprocessing = 0;
291 | };
292 | /* End PBXSourcesBuildPhase section */
293 |
294 | /* Begin PBXTargetDependency section */
295 | 42C2CBEA1E244D6300A96A93 /* PBXTargetDependency */ = {
296 | isa = PBXTargetDependency;
297 | target = 42C2CBE31E244D6300A96A93 /* GDPerformanceView-iOS */;
298 | targetProxy = 42C2CBE91E244D6300A96A93 /* PBXContainerItemProxy */;
299 | };
300 | /* End PBXTargetDependency section */
301 |
302 | /* Begin PBXVariantGroup section */
303 | 42AD06E91E1D18C400A5C840 /* LaunchScreen.storyboard */ = {
304 | isa = PBXVariantGroup;
305 | children = (
306 | 42AD06EA1E1D18C400A5C840 /* Base */,
307 | );
308 | name = LaunchScreen.storyboard;
309 | sourceTree = "";
310 | };
311 | 42AD06EB1E1D18C400A5C840 /* Main.storyboard */ = {
312 | isa = PBXVariantGroup;
313 | children = (
314 | 42AD06EC1E1D18C400A5C840 /* Base */,
315 | );
316 | name = Main.storyboard;
317 | sourceTree = "";
318 | };
319 | /* End PBXVariantGroup section */
320 |
321 | /* Begin XCBuildConfiguration section */
322 | 4237B6E81E0FE22A0059FF8B /* Debug */ = {
323 | isa = XCBuildConfiguration;
324 | buildSettings = {
325 | ALWAYS_SEARCH_USER_PATHS = NO;
326 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
327 | CLANG_ANALYZER_NONNULL = YES;
328 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
329 | CLANG_CXX_LIBRARY = "libc++";
330 | CLANG_ENABLE_MODULES = YES;
331 | CLANG_ENABLE_OBJC_ARC = YES;
332 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
333 | CLANG_WARN_BOOL_CONVERSION = YES;
334 | CLANG_WARN_COMMA = YES;
335 | CLANG_WARN_CONSTANT_CONVERSION = YES;
336 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
337 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
338 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
339 | CLANG_WARN_EMPTY_BODY = YES;
340 | CLANG_WARN_ENUM_CONVERSION = YES;
341 | CLANG_WARN_INFINITE_RECURSION = YES;
342 | CLANG_WARN_INT_CONVERSION = YES;
343 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
344 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
345 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
346 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
347 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
348 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
349 | CLANG_WARN_STRICT_PROTOTYPES = YES;
350 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
351 | CLANG_WARN_UNREACHABLE_CODE = YES;
352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
354 | COPY_PHASE_STRIP = NO;
355 | DEBUG_INFORMATION_FORMAT = dwarf;
356 | ENABLE_STRICT_OBJC_MSGSEND = YES;
357 | ENABLE_TESTABILITY = YES;
358 | GCC_C_LANGUAGE_STANDARD = gnu99;
359 | GCC_DYNAMIC_NO_PIC = NO;
360 | GCC_NO_COMMON_BLOCKS = YES;
361 | GCC_OPTIMIZATION_LEVEL = 0;
362 | GCC_PREPROCESSOR_DEFINITIONS = (
363 | "DEBUG=1",
364 | "$(inherited)",
365 | );
366 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
367 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
368 | GCC_WARN_UNDECLARED_SELECTOR = YES;
369 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
370 | GCC_WARN_UNUSED_FUNCTION = YES;
371 | GCC_WARN_UNUSED_VARIABLE = YES;
372 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
373 | MTL_ENABLE_DEBUG_INFO = YES;
374 | ONLY_ACTIVE_ARCH = YES;
375 | SDKROOT = iphoneos;
376 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
377 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
378 | TARGETED_DEVICE_FAMILY = "1,2";
379 | };
380 | name = Debug;
381 | };
382 | 4237B6E91E0FE22A0059FF8B /* Release */ = {
383 | isa = XCBuildConfiguration;
384 | buildSettings = {
385 | ALWAYS_SEARCH_USER_PATHS = NO;
386 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
387 | CLANG_ANALYZER_NONNULL = YES;
388 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
389 | CLANG_CXX_LIBRARY = "libc++";
390 | CLANG_ENABLE_MODULES = YES;
391 | CLANG_ENABLE_OBJC_ARC = YES;
392 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
393 | CLANG_WARN_BOOL_CONVERSION = YES;
394 | CLANG_WARN_COMMA = YES;
395 | CLANG_WARN_CONSTANT_CONVERSION = YES;
396 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
397 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
398 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
399 | CLANG_WARN_EMPTY_BODY = YES;
400 | CLANG_WARN_ENUM_CONVERSION = YES;
401 | CLANG_WARN_INFINITE_RECURSION = YES;
402 | CLANG_WARN_INT_CONVERSION = YES;
403 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
404 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
405 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
406 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
407 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
408 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
409 | CLANG_WARN_STRICT_PROTOTYPES = YES;
410 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
411 | CLANG_WARN_UNREACHABLE_CODE = YES;
412 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
413 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
414 | COPY_PHASE_STRIP = NO;
415 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
416 | ENABLE_NS_ASSERTIONS = NO;
417 | ENABLE_STRICT_OBJC_MSGSEND = YES;
418 | GCC_C_LANGUAGE_STANDARD = gnu99;
419 | GCC_NO_COMMON_BLOCKS = YES;
420 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
421 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
422 | GCC_WARN_UNDECLARED_SELECTOR = YES;
423 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
424 | GCC_WARN_UNUSED_FUNCTION = YES;
425 | GCC_WARN_UNUSED_VARIABLE = YES;
426 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
427 | MTL_ENABLE_DEBUG_INFO = NO;
428 | SDKROOT = iphoneos;
429 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
430 | TARGETED_DEVICE_FAMILY = "1,2";
431 | VALIDATE_PRODUCT = YES;
432 | };
433 | name = Release;
434 | };
435 | 4237B6EB1E0FE22A0059FF8B /* Debug */ = {
436 | isa = XCBuildConfiguration;
437 | buildSettings = {
438 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
439 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
440 | DEVELOPMENT_TEAM = RU64C364MT;
441 | INFOPLIST_FILE = "GDPerformanceView-Swift/Info.plist";
442 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
443 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
444 | MARKETING_VERSION = 2.1.1;
445 | PRODUCT_BUNDLE_IDENTIFIER = "GD.GDPerformanceView-Swift";
446 | PRODUCT_NAME = "$(TARGET_NAME)";
447 | SWIFT_VERSION = 5.0;
448 | };
449 | name = Debug;
450 | };
451 | 4237B6EC1E0FE22A0059FF8B /* Release */ = {
452 | isa = XCBuildConfiguration;
453 | buildSettings = {
454 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
455 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
456 | DEVELOPMENT_TEAM = RU64C364MT;
457 | INFOPLIST_FILE = "GDPerformanceView-Swift/Info.plist";
458 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
459 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
460 | MARKETING_VERSION = 2.1.1;
461 | PRODUCT_BUNDLE_IDENTIFIER = "GD.GDPerformanceView-Swift";
462 | PRODUCT_NAME = "$(TARGET_NAME)";
463 | SWIFT_VERSION = 5.0;
464 | };
465 | name = Release;
466 | };
467 | 42C2CBEE1E244D6300A96A93 /* Debug */ = {
468 | isa = XCBuildConfiguration;
469 | buildSettings = {
470 | CODE_SIGN_IDENTITY = "";
471 | CURRENT_PROJECT_VERSION = 1;
472 | DEFINES_MODULE = YES;
473 | DEVELOPMENT_TEAM = RU64C364MT;
474 | DYLIB_COMPATIBILITY_VERSION = 1;
475 | DYLIB_CURRENT_VERSION = 1;
476 | DYLIB_INSTALL_NAME_BASE = "@rpath";
477 | INFOPLIST_FILE = "GDPerformanceView-iOS/Info.plist";
478 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
479 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
480 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
481 | MARKETING_VERSION = 2.1.1;
482 | PRODUCT_BUNDLE_IDENTIFIER = "GD.GDPerformanceView-iOS";
483 | PRODUCT_NAME = GDPerformanceView;
484 | SKIP_INSTALL = YES;
485 | SUPPORTS_MACCATALYST = NO;
486 | SWIFT_VERSION = 5.0;
487 | VERSIONING_SYSTEM = "apple-generic";
488 | VERSION_INFO_PREFIX = "";
489 | };
490 | name = Debug;
491 | };
492 | 42C2CBEF1E244D6300A96A93 /* Release */ = {
493 | isa = XCBuildConfiguration;
494 | buildSettings = {
495 | CODE_SIGN_IDENTITY = "";
496 | CURRENT_PROJECT_VERSION = 1;
497 | DEFINES_MODULE = YES;
498 | DEVELOPMENT_TEAM = RU64C364MT;
499 | DYLIB_COMPATIBILITY_VERSION = 1;
500 | DYLIB_CURRENT_VERSION = 1;
501 | DYLIB_INSTALL_NAME_BASE = "@rpath";
502 | INFOPLIST_FILE = "GDPerformanceView-iOS/Info.plist";
503 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
504 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
506 | MARKETING_VERSION = 2.1.1;
507 | PRODUCT_BUNDLE_IDENTIFIER = "GD.GDPerformanceView-iOS";
508 | PRODUCT_NAME = GDPerformanceView;
509 | SKIP_INSTALL = YES;
510 | SUPPORTS_MACCATALYST = NO;
511 | SWIFT_VERSION = 5.0;
512 | VERSIONING_SYSTEM = "apple-generic";
513 | VERSION_INFO_PREFIX = "";
514 | };
515 | name = Release;
516 | };
517 | /* End XCBuildConfiguration section */
518 |
519 | /* Begin XCConfigurationList section */
520 | 4237B6D31E0FE2290059FF8B /* Build configuration list for PBXProject "GDPerformanceView-Swift" */ = {
521 | isa = XCConfigurationList;
522 | buildConfigurations = (
523 | 4237B6E81E0FE22A0059FF8B /* Debug */,
524 | 4237B6E91E0FE22A0059FF8B /* Release */,
525 | );
526 | defaultConfigurationIsVisible = 0;
527 | defaultConfigurationName = Release;
528 | };
529 | 4237B6EA1E0FE22A0059FF8B /* Build configuration list for PBXNativeTarget "GDPerformanceView-Swift" */ = {
530 | isa = XCConfigurationList;
531 | buildConfigurations = (
532 | 4237B6EB1E0FE22A0059FF8B /* Debug */,
533 | 4237B6EC1E0FE22A0059FF8B /* Release */,
534 | );
535 | defaultConfigurationIsVisible = 0;
536 | defaultConfigurationName = Release;
537 | };
538 | 42C2CBED1E244D6300A96A93 /* Build configuration list for PBXNativeTarget "GDPerformanceView-iOS" */ = {
539 | isa = XCConfigurationList;
540 | buildConfigurations = (
541 | 42C2CBEE1E244D6300A96A93 /* Debug */,
542 | 42C2CBEF1E244D6300A96A93 /* Release */,
543 | );
544 | defaultConfigurationIsVisible = 0;
545 | defaultConfigurationName = Release;
546 | };
547 | /* End XCConfigurationList section */
548 | };
549 | rootObject = 4237B6D01E0FE2290059FF8B /* Project object */;
550 | }
551 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift.xcodeproj/xcshareddata/xcschemes/GDPerformanceView-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | @UIApplicationMain
26 | class AppDelegate: UIResponder, UIApplicationDelegate {
27 |
28 | var window: UIWindow?
29 |
30 | var performanceView: PerformanceMonitor?
31 |
32 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
33 |
34 | #if DEBUG
35 | PerformanceMonitor.shared().start()
36 | #endif
37 |
38 | return true
39 | }
40 |
41 | func applicationWillResignActive(_ application: UIApplication) {
42 | // 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.
43 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
44 | }
45 |
46 | func applicationDidEnterBackground(_ application: UIApplication) {
47 | // 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.
48 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
49 | }
50 |
51 | func applicationWillEnterForeground(_ application: UIApplication) {
52 | // 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.
53 | }
54 |
55 | func applicationDidBecomeActive(_ application: UIApplication) {
56 | // 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.
57 | }
58 |
59 | func applicationWillTerminate(_ application: UIApplication) {
60 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/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 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/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 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/GDPerformanceMonitoring/LinkedFramesList.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import Foundation
24 |
25 | // MARK: Class Definition
26 |
27 | /// Linked list node. Represents frame timestamp.
28 | internal class FrameNode {
29 |
30 | // MARK: Public Properties
31 |
32 | var next: FrameNode?
33 | weak var previous: FrameNode?
34 |
35 | private(set) var timestamp: TimeInterval
36 |
37 | /// Initializes linked list node with parameters.
38 | ///
39 | /// - Parameter timeInterval: Frame timestamp.
40 | public init(timestamp: TimeInterval) {
41 | self.timestamp = timestamp
42 | }
43 | }
44 |
45 | // MARK: Class Definition
46 |
47 | /// Linked list. Each node represents frame timestamp.
48 | /// The only function is append, which will add a new frame and remove all frames older than a second from the last timestamp.
49 | /// As a result, the number of items in the list will represent the number of frames for the last second.
50 | internal class LinkedFramesList {
51 |
52 | // MARK: Private Properties
53 |
54 | private var head: FrameNode?
55 | private var tail: FrameNode?
56 |
57 | // MARK: Public Properties
58 |
59 | private(set) var count = 0
60 | }
61 |
62 | // MARK: Public Methods
63 |
64 | internal extension LinkedFramesList {
65 | /// Appends new frame with parameters.
66 | ///
67 | /// - Parameter timestamp: New frame timestamp.
68 | func append(frameWithTimestamp timestamp: TimeInterval) {
69 | let newNode = FrameNode(timestamp: timestamp)
70 | if let lastNode = self.tail {
71 | newNode.previous = lastNode
72 | lastNode.next = newNode
73 | self.tail = newNode
74 | } else {
75 | self.head = newNode
76 | self.tail = newNode
77 | }
78 |
79 | self.count += 1
80 | self.removeFrameNodes(olderThanTimestampMoreThanSecond: timestamp)
81 | }
82 | }
83 |
84 | // MARK: Support Methods
85 |
86 | private extension LinkedFramesList {
87 | func removeFrameNodes(olderThanTimestampMoreThanSecond timestamp: TimeInterval) {
88 | while let firstNode = self.head {
89 | guard timestamp - firstNode.timestamp > 1.0 else {
90 | break
91 | }
92 |
93 | let nextNode = firstNode.next
94 | nextNode?.previous = nil
95 | firstNode.next = nil
96 | self.head = nextNode
97 |
98 | self.count -= 1
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/GDPerformanceMonitoring/MarginLabel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | // MARK: Class Definition
26 |
27 | /// Label indented from the edge on the left and right.
28 | internal class MarginLabel: UILabel {
29 |
30 | // MARK: Private Properties
31 |
32 | private var edgeInsets = UIEdgeInsets.init(top: 0.0, left: 5.0, bottom: 0.0, right: 5.0)
33 |
34 | // MARK: Properties Overriders
35 |
36 | override internal var intrinsicContentSize: CGSize {
37 | get {
38 | var size = super.intrinsicContentSize
39 | size.width += self.edgeInsets.left + self.edgeInsets.right
40 | size.height += self.edgeInsets.top + self.edgeInsets.bottom
41 | return size
42 | }
43 | }
44 |
45 | // MARK: Init Methods & Superclass Overriders
46 |
47 | override func drawText(in rect: CGRect) {
48 | super.drawText(in: rect.inset(by: self.edgeInsets))
49 | }
50 |
51 | override func sizeThatFits(_ size: CGSize) -> CGSize {
52 | var sizeThatFits = super.sizeThatFits(size)
53 | sizeThatFits.width += self.edgeInsets.left + self.edgeInsets.right
54 | sizeThatFits.height += self.edgeInsets.top + self.edgeInsets.bottom
55 | return sizeThatFits
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/GDPerformanceMonitoring/PerformanceMonitor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | // MARK: Class Definition
26 |
27 | public class PerformanceMonitor {
28 |
29 | // MARK: Enums
30 |
31 | public enum Style {
32 | case dark
33 | case light
34 | case custom(backgroundColor: UIColor, borderColor: UIColor, borderWidth: CGFloat, cornerRadius: CGFloat, textColor: UIColor, font: UIFont)
35 | }
36 |
37 | public enum UserInfo {
38 | case none
39 | case custom(string: String)
40 | }
41 |
42 | private enum States {
43 | case started
44 | case paused
45 | case pausedBySystem
46 | }
47 |
48 | // MARK: Structs
49 |
50 | public struct DisplayOptions: OptionSet {
51 | public let rawValue: Int
52 |
53 | /// CPU usage and FPS.
54 | public static let performance = DisplayOptions(rawValue: 1 << 0)
55 |
56 | /// Memory usage.
57 | public static let memory = DisplayOptions(rawValue: 1 << 1)
58 |
59 | /// Application version with build number.
60 | public static let application = DisplayOptions(rawValue: 1 << 2)
61 |
62 | /// Device model.
63 | public static let device = DisplayOptions(rawValue: 1 << 3)
64 |
65 | /// System name with version.
66 | public static let system = DisplayOptions(rawValue: 1 << 4)
67 |
68 | /// Default dispaly options - CPU usage and FPS, application version with build number and system name with version.
69 | public static let `default`: DisplayOptions = [.performance, .application, .system]
70 |
71 | /// All dispaly options.
72 | public static let all: DisplayOptions = [.performance, .memory, .application, .device, .system]
73 |
74 | public init(rawValue: Int) {
75 | self.rawValue = rawValue
76 | }
77 | }
78 |
79 | // MARK: Public Properties
80 |
81 | public weak var delegate: PerformanceMonitorDelegate?
82 |
83 | public var performanceViewConfigurator: PerformanceViewConfigurator {
84 | get {
85 | return self.performanceView
86 | }
87 | set { }
88 | }
89 |
90 | public var statusBarConfigurator: StatusBarConfigurator {
91 | get {
92 | guard let rootViewController = self.performanceView.rootViewController as? WindowViewController else {
93 | fatalError("Root view controller must be a kind of WindowViewController.")
94 | }
95 | return rootViewController
96 | }
97 | set { }
98 | }
99 |
100 | // MARK: Private Properties
101 |
102 | private static var sharedPerformanceMonitor: PerformanceMonitor!
103 |
104 | private let performanceView = PerformanceView()
105 | private let performanceCalculator = PerformanceCalculator()
106 | private var state = States.paused
107 |
108 | // MARK: Init Methods & Superclass Overriders
109 |
110 | /// Initializes performance monitor with parameters.
111 | ///
112 | /// - Parameters:
113 | /// - options: Display options. Allows to change the format of the displayed information.
114 | /// - style: Style. Allows to change the appearance of the displayed information.
115 | /// - delegate: Performance monitor output.
116 | required public init(options: DisplayOptions = .default, style: Style = .dark, delegate: PerformanceMonitorDelegate? = nil) {
117 | self.performanceView.options = options
118 | self.performanceView.style = style
119 |
120 | self.performanceCalculator.onReport = { [weak self] (performanceReport) in
121 | DispatchQueue.main.async {
122 | self?.apply(performanceReport: performanceReport)
123 | }
124 | }
125 |
126 | self.delegate = delegate
127 | self.subscribeToNotifications()
128 | }
129 |
130 | /// Initializes performance monitor singleton with default properties.
131 | ///
132 | /// - Returns: Performance monitor singleton.
133 | public class func shared() -> PerformanceMonitor {
134 | if self.sharedPerformanceMonitor == nil {
135 | self.sharedPerformanceMonitor = PerformanceMonitor()
136 | }
137 | return self.sharedPerformanceMonitor
138 | }
139 |
140 | deinit {
141 | NotificationCenter.default.removeObserver(self)
142 | }
143 | }
144 |
145 | // MARK: Public Methods
146 |
147 | public extension PerformanceMonitor {
148 | func hide() {
149 | self.performanceView.hide()
150 | }
151 |
152 | func show() {
153 | self.performanceView.show()
154 | }
155 |
156 | func start() {
157 | switch self.state {
158 | case .started:
159 | return
160 | case .paused, .pausedBySystem:
161 | self.state = .started
162 | self.performanceCalculator.start()
163 | }
164 | }
165 |
166 | func pause() {
167 | switch self.state {
168 | case .paused:
169 | return
170 | case .started, .pausedBySystem:
171 | self.state = .paused
172 | self.performanceCalculator.pause()
173 | }
174 | }
175 | }
176 |
177 | // MARK: Notifications & Observers
178 |
179 | private extension PerformanceMonitor {
180 | func applicationWillEnterForegroundNotification(notification: Notification) {
181 | switch self.state {
182 | case .started, .paused:
183 | return
184 | case .pausedBySystem:
185 | self.state = .started
186 | self.performanceCalculator.start()
187 | }
188 | }
189 |
190 | func applicationDidEnterBackgroundNotification(notification: Notification) {
191 | switch self.state {
192 | case .paused, .pausedBySystem:
193 | return
194 | case .started:
195 | self.state = .pausedBySystem
196 | self.performanceCalculator.pause()
197 | }
198 | }
199 | }
200 |
201 | // MARK: Configurations
202 |
203 | private extension PerformanceMonitor {
204 | func subscribeToNotifications() {
205 | NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [weak self] (notification) in
206 | self?.applicationWillEnterForegroundNotification(notification: notification)
207 | }
208 |
209 | NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { [weak self] (notification) in
210 | self?.applicationDidEnterBackgroundNotification(notification: notification)
211 | }
212 | }
213 | }
214 |
215 | // MARK: Support Methods
216 |
217 | private extension PerformanceMonitor {
218 | func apply(performanceReport: PerformanceReport) {
219 | self.performanceView.update(withPerformanceReport: performanceReport)
220 | self.delegate?.performanceMonitor(didReport: performanceReport)
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/GDPerformanceMonitoring/PerformanceView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | // MARK: Class Definition
26 |
27 | /// Performance view. Displays performance information above status bar. Appearance and output can be changed via properties.
28 | internal class PerformanceView: UIWindow, PerformanceViewConfigurator {
29 |
30 | // MARK: Structs
31 |
32 | private struct Constants {
33 | static let prefferedHeight: CGFloat = 20.0
34 | static let borderWidth: CGFloat = 1.0
35 | static let cornerRadius: CGFloat = 5.0
36 | static let pointSize: CGFloat = 8.0
37 | static let defaultStatusBarHeight: CGFloat = 20.0
38 | static let safeAreaInsetDifference: CGFloat = 11.0
39 | }
40 |
41 | // MARK: Public Properties
42 |
43 | /// Allows to change the format of the displayed information.
44 | public var options = PerformanceMonitor.DisplayOptions.default {
45 | didSet {
46 | self.configureStaticInformation()
47 | }
48 | }
49 |
50 | public var userInfo = PerformanceMonitor.UserInfo.none {
51 | didSet {
52 | self.configureUserInformation()
53 | }
54 | }
55 |
56 | /// Allows to change the appearance of the displayed information.
57 | public var style = PerformanceMonitor.Style.dark {
58 | didSet {
59 | self.configureView(withStyle: self.style)
60 | }
61 | }
62 |
63 | /// Allows to add gesture recognizers to the view.
64 | public var interactors: [UIGestureRecognizer]? {
65 | didSet {
66 | self.configureView(withInteractors: self.interactors)
67 | }
68 | }
69 |
70 | // MARK: Private Properties
71 |
72 | private let monitoringTextLabel = MarginLabel()
73 | private var staticInformation: String?
74 | private var userInformation: String?
75 |
76 | // MARK: Init Methods & Superclass Overriders
77 |
78 | required internal init() {
79 | super.init(frame: PerformanceView.windowFrame(withPrefferedHeight: Constants.prefferedHeight))
80 | if #available(iOS 13, *) {
81 | self.windowScene = PerformanceView.keyWindowScene()
82 | }
83 |
84 | self.configureWindow()
85 | self.configureMonitoringTextLabel()
86 | self.subscribeToNotifications()
87 | }
88 |
89 | required init?(coder aDecoder: NSCoder) {
90 | super.init(coder: aDecoder)
91 | }
92 |
93 | override func layoutSubviews() {
94 | super.layoutSubviews()
95 |
96 | self.layoutWindow()
97 | }
98 |
99 | override func becomeKey() {
100 | self.isHidden = true
101 |
102 | DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
103 | self.showViewAboveStatusBarIfNeeded()
104 | }
105 | }
106 |
107 | override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
108 | guard let interactors = self.interactors, interactors.count > 0 else {
109 | return false
110 | }
111 | return super.point(inside: point, with: event)
112 | }
113 |
114 | deinit {
115 | NotificationCenter.default.removeObserver(self)
116 | }
117 | }
118 |
119 | // MARK: Public Methods
120 |
121 | internal extension PerformanceView {
122 | /// Hides monitoring view.
123 | func hide() {
124 | self.monitoringTextLabel.isHidden = true
125 | }
126 |
127 | /// Shows monitoring view.
128 | func show() {
129 | self.monitoringTextLabel.isHidden = false
130 | }
131 |
132 | /// Updates monitoring label with performance report.
133 | ///
134 | /// - Parameter report: Performance report.
135 | func update(withPerformanceReport report: PerformanceReport) {
136 | var monitoringTexts: [String] = []
137 | if self.options.contains(.performance) {
138 | let performance = String(format: "CPU: %.1f%%, FPS: %d", report.cpuUsage, report.fps)
139 | monitoringTexts.append(performance)
140 | }
141 |
142 | if self.options.contains(.memory) {
143 | let bytesInMegabyte = 1024.0 * 1024.0
144 | let usedMemory = Double(report.memoryUsage.used) / bytesInMegabyte
145 | let totalMemory = Double(report.memoryUsage.total) / bytesInMegabyte
146 | let memory = String(format: "%.1f of %.0f MB used", usedMemory, totalMemory)
147 | monitoringTexts.append(memory)
148 | }
149 |
150 | if let staticInformation = self.staticInformation {
151 | monitoringTexts.append(staticInformation)
152 | }
153 |
154 | if let userInformation = self.userInformation {
155 | monitoringTexts.append(userInformation)
156 | }
157 |
158 | self.monitoringTextLabel.text = (monitoringTexts.count > 0 ? monitoringTexts.joined(separator: "\n") : nil)
159 | self.showViewAboveStatusBarIfNeeded()
160 | self.layoutMonitoringLabel()
161 | }
162 | }
163 |
164 | // MARK: Notifications & Observers
165 |
166 | private extension PerformanceView {
167 | func applicationWillChangeStatusBarFrame(notification: Notification) {
168 | self.layoutWindow()
169 | }
170 | }
171 |
172 | // MARK: Configurations
173 |
174 | private extension PerformanceView {
175 | func configureWindow() {
176 | self.rootViewController = WindowViewController()
177 | self.windowLevel = UIWindow.Level.statusBar + 1.0
178 | self.backgroundColor = .clear
179 | self.clipsToBounds = true
180 | self.isHidden = true
181 | }
182 |
183 | func configureMonitoringTextLabel() {
184 | self.monitoringTextLabel.textAlignment = NSTextAlignment.center
185 | self.monitoringTextLabel.numberOfLines = 0
186 | self.monitoringTextLabel.clipsToBounds = true
187 | self.addSubview(self.monitoringTextLabel)
188 | }
189 |
190 | func configureStaticInformation() {
191 | var staticInformations: [String] = []
192 | if self.options.contains(.application) {
193 | let applicationVersion = self.applicationVersion()
194 | staticInformations.append(applicationVersion)
195 | }
196 | if self.options.contains(.device) {
197 | let deviceModel = self.deviceModel()
198 | staticInformations.append(deviceModel)
199 | }
200 | if self.options.contains(.system) {
201 | let systemVersion = self.systemVersion()
202 | staticInformations.append(systemVersion)
203 | }
204 |
205 | self.staticInformation = (staticInformations.count > 0 ? staticInformations.joined(separator: ", ") : nil)
206 | }
207 |
208 | func configureUserInformation() {
209 | var staticInformation: String?
210 | switch self.userInfo {
211 | case .none:
212 | break
213 | case .custom(let string):
214 | staticInformation = string
215 | }
216 |
217 | self.userInformation = staticInformation
218 | }
219 |
220 | func subscribeToNotifications() {
221 | NotificationCenter.default.addObserver(forName: UIApplication.willChangeStatusBarFrameNotification, object: nil, queue: .main) { [weak self] (notification) in
222 | self?.applicationWillChangeStatusBarFrame(notification: notification)
223 | }
224 | }
225 |
226 | func configureView(withStyle style: PerformanceMonitor.Style) {
227 | switch style {
228 | case .dark:
229 | self.monitoringTextLabel.backgroundColor = .black
230 | self.monitoringTextLabel.layer.borderColor = UIColor.white.cgColor
231 | self.monitoringTextLabel.layer.borderWidth = Constants.borderWidth
232 | self.monitoringTextLabel.layer.cornerRadius = Constants.cornerRadius
233 | self.monitoringTextLabel.textColor = .white
234 | self.monitoringTextLabel.font = UIFont.systemFont(ofSize: Constants.pointSize)
235 | case .light:
236 | self.monitoringTextLabel.backgroundColor = .white
237 | self.monitoringTextLabel.layer.borderColor = UIColor.black.cgColor
238 | self.monitoringTextLabel.layer.borderWidth = Constants.borderWidth
239 | self.monitoringTextLabel.layer.cornerRadius = Constants.cornerRadius
240 | self.monitoringTextLabel.textColor = .black
241 | self.monitoringTextLabel.font = UIFont.systemFont(ofSize: Constants.pointSize)
242 | case .custom(let backgroundColor, let borderColor, let borderWidth, let cornerRadius, let textColor, let font):
243 | self.monitoringTextLabel.backgroundColor = backgroundColor
244 | self.monitoringTextLabel.layer.borderColor = borderColor.cgColor
245 | self.monitoringTextLabel.layer.borderWidth = borderWidth
246 | self.monitoringTextLabel.layer.cornerRadius = cornerRadius
247 | self.monitoringTextLabel.textColor = textColor
248 | self.monitoringTextLabel.font = font
249 | }
250 | }
251 |
252 | func configureView(withInteractors interactors: [UIGestureRecognizer]?) {
253 | if let recognizers = self.gestureRecognizers {
254 | for recognizer in recognizers {
255 | self.removeGestureRecognizer(recognizer)
256 | }
257 | }
258 |
259 | if let recognizers = interactors {
260 | for recognizer in recognizers {
261 | self.addGestureRecognizer(recognizer)
262 | }
263 | }
264 | }
265 | }
266 |
267 | // MARK: Layout View
268 |
269 | private extension PerformanceView {
270 | func layoutWindow() {
271 | self.frame = PerformanceView.windowFrame(withPrefferedHeight: self.monitoringTextLabel.bounds.height)
272 | self.layoutMonitoringLabel()
273 | }
274 |
275 | func layoutMonitoringLabel() {
276 | let windowWidth = self.bounds.width
277 | let windowHeight = self.bounds.height
278 | let labelSize = self.monitoringTextLabel.sizeThatFits(CGSize(width: windowWidth, height: CGFloat.greatestFiniteMagnitude))
279 |
280 | if windowHeight != labelSize.height {
281 | self.frame = PerformanceView.windowFrame(withPrefferedHeight: self.monitoringTextLabel.bounds.height)
282 | }
283 |
284 | self.monitoringTextLabel.frame = CGRect(x: (windowWidth - labelSize.width) / 2.0, y: (windowHeight - labelSize.height) / 2.0, width: labelSize.width, height: labelSize.height)
285 | }
286 | }
287 |
288 | // MARK: Support Methods
289 |
290 | private extension PerformanceView {
291 | func showViewAboveStatusBarIfNeeded() {
292 | guard UIApplication.shared.applicationState == UIApplication.State.active, self.canBeVisible(), self.isHidden else {
293 | return
294 | }
295 | self.isHidden = false
296 | }
297 |
298 | func applicationVersion() -> String {
299 | var applicationVersion = ""
300 | var applicationBuildNumber = ""
301 | if let infoDictionary = Bundle.main.infoDictionary {
302 | if let versionNumber = infoDictionary["CFBundleShortVersionString"] as? String {
303 | applicationVersion = versionNumber
304 | }
305 | if let buildNumber = infoDictionary["CFBundleVersion"] as? String {
306 | applicationBuildNumber = buildNumber
307 | }
308 | }
309 | return "app v\(applicationVersion) (\(applicationBuildNumber))"
310 | }
311 |
312 | func deviceModel() -> String {
313 | var systemInfo = utsname()
314 | uname(&systemInfo)
315 | let machineMirror = Mirror(reflecting: systemInfo.machine)
316 | let model = machineMirror.children.reduce("") { identifier, element in
317 | guard let value = element.value as? Int8, value != 0 else {
318 | return identifier
319 | }
320 | return identifier + String(UnicodeScalar(UInt8(value)))
321 | }
322 | return model
323 | }
324 |
325 | func systemVersion() -> String {
326 | let systemName = UIDevice.current.systemName
327 | let systemVersion = UIDevice.current.systemVersion
328 | return "\(systemName) v\(systemVersion)"
329 | }
330 |
331 | func canBeVisible() -> Bool {
332 | if let window = PerformanceView.keyWindow(), window.isKeyWindow, !window.isHidden {
333 | return true
334 | }
335 | return false
336 | }
337 | }
338 |
339 | // MARK: Class Methods
340 |
341 | private extension PerformanceView {
342 | class func windowFrame(withPrefferedHeight height: CGFloat) -> CGRect {
343 | guard let window = PerformanceView.keyWindow() else {
344 | return .zero
345 | }
346 |
347 | var topInset: CGFloat = 0.0
348 | if #available(iOS 11.0, *), let safeAreaTop = window.rootViewController?.view.safeAreaInsets.top {
349 | if safeAreaTop > 0.0 {
350 | if safeAreaTop > Constants.defaultStatusBarHeight {
351 | topInset = safeAreaTop - Constants.safeAreaInsetDifference
352 | } else {
353 | topInset = safeAreaTop - Constants.defaultStatusBarHeight
354 | }
355 | } else {
356 | topInset = safeAreaTop
357 | }
358 | }
359 | return CGRect(x: 0.0, y: topInset, width: window.bounds.width, height: height)
360 | }
361 |
362 | class func keyWindow() -> UIWindow? {
363 | if #available(iOS 13, *) {
364 | return UIApplication.shared.windows.first(where: { $0.isKeyWindow })
365 | } else {
366 | return UIApplication.shared.keyWindow
367 | }
368 | }
369 |
370 | @available(iOS 13, *)
371 | class func keyWindowScene() -> UIWindowScene? {
372 | return UIApplication.shared.connectedScenes
373 | .filter { $0.activationState == .foregroundActive }
374 | .first as? UIWindowScene
375 | }
376 | }
377 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/GDPerformanceMonitoring/PerformanceСalculator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import QuartzCore
24 |
25 | // MARK: Class Definition
26 |
27 | /// Performance calculator. Uses CADisplayLink to count FPS. Also counts CPU and memory usage.
28 | internal class PerformanceCalculator {
29 |
30 | // MARK: Structs
31 |
32 | private struct Constants {
33 | static let accumulationTimeInSeconds = 1.0
34 | }
35 |
36 | // MARK: Internal Properties
37 |
38 | internal var onReport: ((_ performanceReport: PerformanceReport) -> ())?
39 |
40 | // MARK: Private Properties
41 |
42 | private var displayLink: CADisplayLink!
43 | private let linkedFramesList = LinkedFramesList()
44 | private var startTimestamp: TimeInterval?
45 | private var accumulatedInformationIsEnough = false
46 |
47 | // MARK: Init Methods & Superclass Overriders
48 |
49 | required internal init() {
50 | self.configureDisplayLink()
51 | }
52 | }
53 |
54 | // MARK: Public Methods
55 |
56 | internal extension PerformanceCalculator {
57 | /// Starts performance monitoring.
58 | func start() {
59 | self.startTimestamp = Date().timeIntervalSince1970
60 | self.displayLink?.isPaused = false
61 | }
62 |
63 | /// Pauses performance monitoring.
64 | func pause() {
65 | self.displayLink?.isPaused = true
66 | self.startTimestamp = nil
67 | self.accumulatedInformationIsEnough = false
68 | }
69 | }
70 |
71 | // MARK: Timer Actions
72 |
73 | private extension PerformanceCalculator {
74 | @objc func displayLinkAction(displayLink: CADisplayLink) {
75 | self.linkedFramesList.append(frameWithTimestamp: displayLink.timestamp)
76 | self.takePerformanceEvidence()
77 | }
78 | }
79 |
80 | // MARK: Monitoring
81 |
82 | private extension PerformanceCalculator {
83 | func takePerformanceEvidence() {
84 | if self.accumulatedInformationIsEnough {
85 | let cpuUsage = self.cpuUsage()
86 | let fps = self.linkedFramesList.count
87 | let memoryUsage = self.memoryUsage()
88 | self.report(cpuUsage: cpuUsage, fps: fps, memoryUsage: memoryUsage)
89 | } else if let start = self.startTimestamp, Date().timeIntervalSince1970 - start >= Constants.accumulationTimeInSeconds {
90 | self.accumulatedInformationIsEnough = true
91 | }
92 | }
93 |
94 | func cpuUsage() -> Double {
95 | var totalUsageOfCPU: Double = 0.0
96 | var threadsList: thread_act_array_t?
97 | var threadsCount = mach_msg_type_number_t(0)
98 | let threadsResult = withUnsafeMutablePointer(to: &threadsList) {
99 | return $0.withMemoryRebound(to: thread_act_array_t?.self, capacity: 1) {
100 | task_threads(mach_task_self_, $0, &threadsCount)
101 | }
102 | }
103 |
104 | if threadsResult == KERN_SUCCESS, let threadsList = threadsList {
105 | for index in 0...stride))
126 | return totalUsageOfCPU
127 | }
128 |
129 | func memoryUsage() -> MemoryUsage {
130 | var taskInfo = task_vm_info_data_t()
131 | var count = mach_msg_type_number_t(MemoryLayout.size) / 4
132 | let result: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
133 | $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
134 | task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &count)
135 | }
136 | }
137 |
138 | var used: UInt64 = 0
139 | if result == KERN_SUCCESS {
140 | used = UInt64(taskInfo.phys_footprint)
141 | }
142 |
143 | let total = ProcessInfo.processInfo.physicalMemory
144 | return (used, total)
145 | }
146 | }
147 |
148 | // MARK: Configurations
149 |
150 | private extension PerformanceCalculator {
151 | func configureDisplayLink() {
152 | self.displayLink = CADisplayLink(target: self, selector: #selector(PerformanceCalculator.displayLinkAction(displayLink:)))
153 | self.displayLink.isPaused = true
154 | self.displayLink?.add(to: .current, forMode: .common)
155 | }
156 | }
157 |
158 | // MARK: Support Methods
159 |
160 | private extension PerformanceCalculator {
161 | func report(cpuUsage: Double, fps: Int, memoryUsage: MemoryUsage) {
162 | let performanceReport = (cpuUsage: cpuUsage, fps: fps, memoryUsage: memoryUsage)
163 | self.onReport?(performanceReport)
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/GDPerformanceMonitoring/Protocols.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | /// Memory usage tuple. Contains used and total memory in bytes.
26 | public typealias MemoryUsage = (used: UInt64, total: UInt64)
27 |
28 | /// Performance report tuple. Contains CPU usage in percentages, FPS and memory usage.
29 | public typealias PerformanceReport = (cpuUsage: Double, fps: Int, memoryUsage: MemoryUsage)
30 |
31 | /// Performance monitor delegate. Gets called on the main thread.
32 | public protocol PerformanceMonitorDelegate: class {
33 | /// Reports monitoring information to the receiver.
34 | ///
35 | /// - Parameters:
36 | /// - performanceReport: Performance report tuple. Contains CPU usage in percentages, FPS and memory usage.
37 | func performanceMonitor(didReport performanceReport: PerformanceReport)
38 | }
39 |
40 | public protocol PerformanceViewConfigurator {
41 | var options: PerformanceMonitor.DisplayOptions { get set }
42 | var userInfo: PerformanceMonitor.UserInfo { get set }
43 | var style: PerformanceMonitor.Style { get set }
44 | var interactors: [UIGestureRecognizer]? { get set }
45 | }
46 |
47 | public protocol StatusBarConfigurator {
48 | var statusBarHidden: Bool { get set }
49 | var statusBarStyle: UIStatusBarStyle { get set }
50 | }
51 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/GDPerformanceMonitoring/WindowViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | import UIKit
24 |
25 | // MARK: Class Definition
26 |
27 | /// A window controller to override the properties of the status bar so that developers can choose their own preferences.
28 | internal class WindowViewController: UIViewController, StatusBarConfigurator {
29 |
30 | // MARK: Public Properties
31 |
32 | /// Overrides prefersStatusBarHidden.
33 | public var statusBarHidden = false {
34 | didSet {
35 | self.setNeedsStatusBarAppearanceUpdate()
36 | }
37 | }
38 |
39 | /// Overrides preferredStatusBarStyle.
40 | public var statusBarStyle = UIStatusBarStyle.default {
41 | didSet {
42 | self.setNeedsStatusBarAppearanceUpdate()
43 | }
44 | }
45 |
46 | // MARK: Properties Overriders
47 |
48 | override var prefersStatusBarHidden: Bool {
49 | get {
50 | return self.statusBarHidden
51 | }
52 | }
53 |
54 | override var preferredStatusBarStyle: UIStatusBarStyle {
55 | get {
56 | return self.statusBarStyle
57 | }
58 | }
59 |
60 | // MARK: Init Methods & Superclass Overriders
61 |
62 | override func viewDidLoad() {
63 | super.viewDidLoad()
64 |
65 | self.view.backgroundColor = .clear
66 | }
67 |
68 | override func didReceiveMemoryWarning() {
69 | super.didReceiveMemoryWarning()
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/GDPerformanceView-Swift/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 | $(MARKETING_VERSION)
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 | UIInterfaceOrientationPortraitUpsideDown
37 |
38 | UISupportedInterfaceOrientations~ipad
39 |
40 | UIInterfaceOrientationPortrait
41 | UIInterfaceOrientationPortraitUpsideDown
42 | UIInterfaceOrientationLandscapeLeft
43 | UIInterfaceOrientationLandscapeRight
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/GDPerformanceView-iOS/GDPerformanceView-iOS.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2017 Gavrilov Daniil
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
5 | // of this software and associated documentation files (the "Software"), to deal
6 | // in the Software without restriction, including without limitation the rights
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | // copies of the Software, and to permit persons to whom the Software is
9 | // furnished to do so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in
12 | // all copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | // THE SOFTWARE.
21 | //
22 |
23 | #import
24 |
25 | //! Project version number for GDPerformanceView-iOS.
26 | FOUNDATION_EXPORT double GDPerformanceView_iOSVersionNumber;
27 |
28 | //! Project version string for GDPerformanceView-iOS.
29 | FOUNDATION_EXPORT const unsigned char GDPerformanceView_iOSVersionString[];
30 |
31 | // In this header, you should import all the public headers of your framework using statements like #import
32 |
--------------------------------------------------------------------------------
/GDPerformanceView-iOS/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 | $(MARKETING_VERSION)
19 | CFBundleVersion
20 | 1
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Gavrilov Daniil
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 NON INFRINGEMENT. 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 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "GDPerformanceView-Swift",
8 | platforms: [.iOS(.v8)],
9 | products: [
10 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
11 | .library(
12 | name: "GDPerformanceView-Swift",
13 | targets: ["GDPerformanceView-Swift"]),
14 | ],
15 | dependencies: [
16 | // Dependencies declare other packages that this package depends on.
17 | // .package(url: /* package url */, from: "1.0.0"),
18 | ],
19 | targets: [
20 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
21 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
22 | .target(
23 | name: "GDPerformanceView-Swift",
24 | dependencies: [],
25 | path: "GDPerformanceView-Swift/GDPerformanceMonitoring"),
26 | ]
27 | )
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GDPerformanceView-Swift
2 | Shows FPS, CPU and memory usage, device model, app and iOS versions above the status bar and report FPS, CPU and memory usage via delegate.
3 |
4 | [](https://github.com/Carthage/Carthage)
5 | [](https://cocoapods.org/)
6 | 
7 | 
8 | 
9 | 
10 | 
11 |
12 | 
13 | 
14 | 
15 | 
16 |
17 | ## Installation
18 | Simply add GDPerformanceMonitoring folder with files to your project, or use CocoaPods.
19 |
20 | #### Carthage
21 | Create a `Cartfile` that lists the framework and run `carthage update`. Follow the [instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios) to add `$(SRCROOT)/Carthage/Build/iOS/GDPerformanceView.framework` to an iOS project.
22 |
23 | ```ruby
24 | github "dani-gavrilov/GDPerformanceView-Swift" ~> 2.1.1
25 | ```
26 | Don't forget to import GDPerformanceView by adding:
27 |
28 | ```swift
29 | import GDPerformanceView
30 | ```
31 |
32 | #### CocoaPods
33 | You can use [CocoaPods](http://cocoapods.org/) to install `GDPerformanceView` by adding it to your `Podfile`:
34 |
35 | ```ruby
36 | platform :ios, '8.0'
37 | use_frameworks!
38 |
39 | target 'project_name' do
40 | pod 'GDPerformanceView-Swift', '~> 2.1.1'
41 | end
42 | ```
43 | Don't forget to import GDPerformanceView by adding:
44 |
45 | ```swift
46 | import GDPerformanceView_Swift
47 | ```
48 |
49 | ## Usage example
50 |
51 | Simply start monitoring. Performance view will be added above the status bar automatically.
52 | Also, you can configure appearance as you like or just hide the monitoring view and use its delegate.
53 |
54 | You can find example projects [here](https://github.com/dani-gavrilov/GDPerformanceViewExamples).
55 |
56 | #### Start monitoring
57 |
58 | By default, monitoring is paused. Call the following command to start or resume monitoring:
59 |
60 | ```swift
61 | PerformanceMonitor.shared().start()
62 | ```
63 | or
64 |
65 | ```swift
66 | self.performanceView = PerformanceMonitor()
67 | self.performanceView?. start()
68 | ```
69 | This won't show the monitoring view if it was hidden previously. To show it call the following command:
70 |
71 | ```swift
72 | self.performanceView?.show()
73 | ```
74 |
75 | #### Pause monitoring
76 |
77 | Call the following command to pause monitoring:
78 |
79 | ```swift
80 | self.performanceView?.pause()
81 | ```
82 |
83 | This won't hide the monitoring view. To hide it call the following command:
84 |
85 | ```swift
86 | self.performanceView?.hide()
87 | ```
88 |
89 | #### Displayed information
90 |
91 | You can change displayed information by changing options of the performance monitor:
92 |
93 | ```swift
94 | self.performanceView?.performanceViewConfigurator.options = .all
95 | ```
96 | You can choose from:
97 |
98 | * performance - CPU usage and FPS.
99 | * memory - Memory usage.
100 | * application - Application version with build number.
101 | * device - Device model.
102 | * system - System name with version.
103 |
104 | Also you can mix them, but order doesn't matter:
105 |
106 | ```swift
107 | self.performanceView?.performanceViewConfigurator.options = [.performance, .application, .system]
108 | ```
109 | By default, set of [.performance, .application, .system] options is used.
110 |
111 | You can also add your custom information by using:
112 |
113 | ```swift
114 | self.performanceView?.performanceViewConfigurator.userInfo = .custom(string: "Launch date \(Date())")
115 | ```
116 | Keep in mind that custom string will not automatically fit the screen, use `\n` if it is too long.
117 |
118 | #### Appearance
119 |
120 | You can change monitoring view appearance by changing style of the performance monitor:
121 |
122 | Call the following command to change output information:
123 |
124 | ```swift
125 | self.performanceView?.performanceViewConfigurator.style = .dark
126 | ```
127 |
128 | You can choose from:
129 |
130 | * dark - Black background, white text.
131 | * light - White background, black text.
132 | * custom - You can set background color, border color, border width, corner radius, text color and font.
133 |
134 | By default, dark style is used.
135 |
136 | Also you can override prefersStatusBarHidden and preferredStatusBarStyle to match your expectations:
137 |
138 | ```swift
139 | self.performanceView?.statusBarConfigurator.statusBarHidden = false
140 | self.performanceView?.statusBarConfigurator.statusBarStyle = .lightContent
141 | ```
142 |
143 | #### Interactions
144 |
145 | You can interact with performance view via gesture recognizers. Add them by using:
146 |
147 | ```swift
148 | self.performanceView?.performanceViewConfigurator.interactors = [tapGesture, swipeGesture]
149 | ```
150 | If interactors is nil or empty `point(inside:with:)` of the view will return false to make all touches pass underneath. So to remove interactors just call the following command:
151 |
152 | ```swift
153 | self.performanceView?.performanceViewConfigurator.interactors = nil
154 | ```
155 | By default, interactors are nil.
156 |
157 | #### Delegate
158 |
159 | Set the delegate and implement its method:
160 |
161 | ```swift
162 | self.performanceView?.delegate = self
163 | ```
164 |
165 | ```swift
166 | func performanceMonitor(didReport performanceReport: PerformanceReport) {
167 | print(performanceReport.cpuUsage, performanceReport.fps, performanceReport.memoryUsage.used, performanceReport.memoryUsage.total)
168 | }
169 | ```
170 |
171 | ## Requirements
172 | - iOS 9.0+
173 | - xCode 12.0+
174 |
175 | ## Donations
176 |
177 | Wanna say thanks? You can do it using [Patreon](https://www.patreon.com/dani_gavrilov).
178 |
179 | ## Meta
180 |
181 | Daniil Gavrilov - [VK](https://vk.com/dani_gavrilov) - [FB](https://facebook.com/danigavrilov)
182 |
183 | I will be pleased to know that your project uses this framework. You can send a link to your project in App Store to my email - [daniilmbox@gmail.com](mailto:daniilmbox@gmail.com).
184 |
185 | ## License
186 |
187 | GDPerformanceView is available under the MIT license. See the LICENSE file for more info.
188 |
189 |
--------------------------------------------------------------------------------
/performance_view.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView-Swift/171a656040135d667f4228c3ec82f2384770d87d/performance_view.PNG
--------------------------------------------------------------------------------
/performance_view_2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView-Swift/171a656040135d667f4228c3ec82f2384770d87d/performance_view_2.PNG
--------------------------------------------------------------------------------
/performance_view_3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView-Swift/171a656040135d667f4228c3ec82f2384770d87d/performance_view_3.PNG
--------------------------------------------------------------------------------
/performance_view_4.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dani-gavrilov/GDPerformanceView-Swift/171a656040135d667f4228c3ec82f2384770d87d/performance_view_4.PNG
--------------------------------------------------------------------------------