├── .gitignore ├── .travis.yml ├── Example ├── Guldan.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Guldan-Example.xcscheme ├── Guldan.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Guldan │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── GDAppDelegate.h │ ├── GDAppDelegate.m │ ├── GDViewController.h │ ├── GDViewController.m │ ├── Guldan-Info.plist │ ├── Guldan-Prefix.pch │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── Podfile ├── Podfile.lock ├── Pods │ ├── Local Podspecs │ │ └── Guldan.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ └── project.pbxproj │ └── Target Support Files │ │ ├── Guldan │ │ ├── Guldan-Info.plist │ │ ├── Guldan-dummy.m │ │ ├── Guldan-prefix.pch │ │ ├── Guldan-umbrella.h │ │ ├── Guldan.debug.xcconfig │ │ ├── Guldan.modulemap │ │ └── Guldan.release.xcconfig │ │ ├── Pods-Guldan_Example │ │ ├── Pods-Guldan_Example-Info.plist │ │ ├── Pods-Guldan_Example-acknowledgements.markdown │ │ ├── Pods-Guldan_Example-acknowledgements.plist │ │ ├── Pods-Guldan_Example-dummy.m │ │ ├── Pods-Guldan_Example-frameworks.sh │ │ ├── Pods-Guldan_Example-umbrella.h │ │ ├── Pods-Guldan_Example.debug.xcconfig │ │ ├── Pods-Guldan_Example.modulemap │ │ └── Pods-Guldan_Example.release.xcconfig │ │ └── Pods-Guldan_Tests │ │ ├── Pods-Guldan_Tests-Info.plist │ │ ├── Pods-Guldan_Tests-acknowledgements.markdown │ │ ├── Pods-Guldan_Tests-acknowledgements.plist │ │ ├── Pods-Guldan_Tests-dummy.m │ │ ├── Pods-Guldan_Tests-umbrella.h │ │ ├── Pods-Guldan_Tests.debug.xcconfig │ │ ├── Pods-Guldan_Tests.modulemap │ │ └── Pods-Guldan_Tests.release.xcconfig └── Tests │ ├── Tests-Info.plist │ ├── Tests-Prefix.pch │ ├── Tests.m │ └── en.lproj │ └── InfoPlist.strings ├── Guldan.podspec ├── Guldan ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── GDNOCMethodTimeProfiler.h │ ├── GDNOCMethodTimeProfiler.m │ ├── GDNOCMethodTimeProfilerProtocol.h │ ├── Guldan.h │ ├── HLLFishhook.c │ ├── HLLFishhook.h │ ├── UI │ ├── GDNRecordDetailCell.h │ ├── GDNRecordDetailCell.m │ ├── GDNRecordDetailViewController.h │ ├── GDNRecordDetailViewController.m │ ├── GDNRecordHierarchyModel.h │ ├── GDNRecordHierarchyModel.m │ ├── GDNRecordModel.h │ ├── GDNRecordModel.m │ ├── GDNRecordRootViewController.h │ ├── GDNRecordRootViewController.m │ ├── GDNUIModel.h │ ├── GDNUIModel.m │ ├── UIWindow+GDN.h │ └── UIWindow+GDN.m │ ├── gdn_objc_msgSend.h │ ├── gdn_objc_msgSend.s │ ├── gdn_objc_msgSend_time_profiler.h │ └── gdn_objc_msgSend_time_profiler.m ├── Image ├── demo.png ├── sandbox.png └── xcode_devices.png ├── LICENSE ├── README.md ├── README_CN.md └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 26 | # Carthage/Checkouts 27 | 28 | Carthage/Build 29 | 30 | # We recommend against adding the Pods directory to your .gitignore. However 31 | # you should judge for yourself, the pros and cons are mentioned at: 32 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 33 | # 34 | # Note: if you ignore the Pods directory, make sure to uncomment 35 | # `pod install` in .travis.yml 36 | # 37 | # Pods/ 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/ 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/Guldan.xcworkspace -scheme Guldan-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /Example/Guldan.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 39571B71874A5F07241CDCB1 /* Pods_Guldan_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5225B8A5D3F9794568BC2562 /* Pods_Guldan_Example.framework */; }; 11 | 49C1A3FFEA4D797AC38D5FE1 /* Pods_Guldan_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 817D16C1E16CA1644F9D17B7 /* Pods_Guldan_Tests.framework */; }; 12 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 13 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; }; 14 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 15 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; }; 16 | 6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; }; 17 | 6003F59E195388D20070C39A /* GDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* GDAppDelegate.m */; }; 18 | 6003F5A7195388D20070C39A /* GDViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* GDViewController.m */; }; 19 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; }; 20 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; }; 21 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 22 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 23 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; }; 24 | 6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; }; 25 | 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; }; 26 | 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 6003F5B3195388D20070C39A /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 6003F582195388D10070C39A /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 6003F589195388D20070C39A; 35 | remoteInfo = Guldan; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 0D6CDEC5169C7A68BF01FDDC /* Pods-Guldan_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Guldan_Example.debug.xcconfig"; path = "Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example.debug.xcconfig"; sourceTree = ""; }; 41 | 2B47C49C2F4F4DB4767C63B1 /* Pods-Guldan_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Guldan_Tests.debug.xcconfig"; path = "Target Support Files/Pods-Guldan_Tests/Pods-Guldan_Tests.debug.xcconfig"; sourceTree = ""; }; 42 | 3AA2BC88BA3289BACAC12C22 /* Pods-Guldan_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Guldan_Example.release.xcconfig"; path = "Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example.release.xcconfig"; sourceTree = ""; }; 43 | 5225B8A5D3F9794568BC2562 /* Pods_Guldan_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Guldan_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 6003F58A195388D20070C39A /* Guldan_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Guldan_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 46 | 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 47 | 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 48 | 6003F595195388D20070C39A /* Guldan-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Guldan-Info.plist"; sourceTree = ""; }; 49 | 6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 50 | 6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | 6003F59B195388D20070C39A /* Guldan-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Guldan-Prefix.pch"; sourceTree = ""; }; 52 | 6003F59C195388D20070C39A /* GDAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDAppDelegate.h; sourceTree = ""; }; 53 | 6003F59D195388D20070C39A /* GDAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GDAppDelegate.m; sourceTree = ""; }; 54 | 6003F5A5195388D20070C39A /* GDViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDViewController.h; sourceTree = ""; }; 55 | 6003F5A6195388D20070C39A /* GDViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GDViewController.m; sourceTree = ""; }; 56 | 6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 57 | 6003F5AE195388D20070C39A /* Guldan_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Guldan_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 59 | 6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; 60 | 6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 61 | 6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = ""; }; 62 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = ""; }; 63 | 71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 64 | 79D495AB7B7448A0E43CFBE3 /* Pods-Guldan_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Guldan_Tests.release.xcconfig"; path = "Target Support Files/Pods-Guldan_Tests/Pods-Guldan_Tests.release.xcconfig"; sourceTree = ""; }; 65 | 817D16C1E16CA1644F9D17B7 /* Pods_Guldan_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Guldan_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 66 | 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 67 | 9C41F5576EF870F2D714584D /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 68 | ACC83FC39173CE8312930F72 /* Guldan.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Guldan.podspec; path = ../Guldan.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 69 | CBB353410A4E4AC8166BA4DC /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 6003F587195388D20070C39A /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */, 78 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, 79 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */, 80 | 39571B71874A5F07241CDCB1 /* Pods_Guldan_Example.framework in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | 6003F5AB195388D20070C39A /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */, 89 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */, 90 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */, 91 | 49C1A3FFEA4D797AC38D5FE1 /* Pods_Guldan_Tests.framework in Frameworks */, 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | /* End PBXFrameworksBuildPhase section */ 96 | 97 | /* Begin PBXGroup section */ 98 | 6003F581195388D10070C39A = { 99 | isa = PBXGroup; 100 | children = ( 101 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */, 102 | 6003F593195388D20070C39A /* Example for Guldan */, 103 | 6003F5B5195388D20070C39A /* Tests */, 104 | 6003F58C195388D20070C39A /* Frameworks */, 105 | 6003F58B195388D20070C39A /* Products */, 106 | D0658103937F9EA6AC210055 /* Pods */, 107 | ); 108 | sourceTree = ""; 109 | }; 110 | 6003F58B195388D20070C39A /* Products */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 6003F58A195388D20070C39A /* Guldan_Example.app */, 114 | 6003F5AE195388D20070C39A /* Guldan_Tests.xctest */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | 6003F58C195388D20070C39A /* Frameworks */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 6003F58D195388D20070C39A /* Foundation.framework */, 123 | 6003F58F195388D20070C39A /* CoreGraphics.framework */, 124 | 6003F591195388D20070C39A /* UIKit.framework */, 125 | 6003F5AF195388D20070C39A /* XCTest.framework */, 126 | 5225B8A5D3F9794568BC2562 /* Pods_Guldan_Example.framework */, 127 | 817D16C1E16CA1644F9D17B7 /* Pods_Guldan_Tests.framework */, 128 | ); 129 | name = Frameworks; 130 | sourceTree = ""; 131 | }; 132 | 6003F593195388D20070C39A /* Example for Guldan */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 6003F59C195388D20070C39A /* GDAppDelegate.h */, 136 | 6003F59D195388D20070C39A /* GDAppDelegate.m */, 137 | 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */, 138 | 6003F5A5195388D20070C39A /* GDViewController.h */, 139 | 6003F5A6195388D20070C39A /* GDViewController.m */, 140 | 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */, 141 | 6003F5A8195388D20070C39A /* Images.xcassets */, 142 | 6003F594195388D20070C39A /* Supporting Files */, 143 | ); 144 | name = "Example for Guldan"; 145 | path = Guldan; 146 | sourceTree = ""; 147 | }; 148 | 6003F594195388D20070C39A /* Supporting Files */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 6003F595195388D20070C39A /* Guldan-Info.plist */, 152 | 6003F596195388D20070C39A /* InfoPlist.strings */, 153 | 6003F599195388D20070C39A /* main.m */, 154 | 6003F59B195388D20070C39A /* Guldan-Prefix.pch */, 155 | ); 156 | name = "Supporting Files"; 157 | sourceTree = ""; 158 | }; 159 | 6003F5B5195388D20070C39A /* Tests */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 6003F5BB195388D20070C39A /* Tests.m */, 163 | 6003F5B6195388D20070C39A /* Supporting Files */, 164 | ); 165 | path = Tests; 166 | sourceTree = ""; 167 | }; 168 | 6003F5B6195388D20070C39A /* Supporting Files */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 6003F5B7195388D20070C39A /* Tests-Info.plist */, 172 | 6003F5B8195388D20070C39A /* InfoPlist.strings */, 173 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */, 174 | ); 175 | name = "Supporting Files"; 176 | sourceTree = ""; 177 | }; 178 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | ACC83FC39173CE8312930F72 /* Guldan.podspec */, 182 | 9C41F5576EF870F2D714584D /* README.md */, 183 | CBB353410A4E4AC8166BA4DC /* LICENSE */, 184 | ); 185 | name = "Podspec Metadata"; 186 | sourceTree = ""; 187 | }; 188 | D0658103937F9EA6AC210055 /* Pods */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 0D6CDEC5169C7A68BF01FDDC /* Pods-Guldan_Example.debug.xcconfig */, 192 | 3AA2BC88BA3289BACAC12C22 /* Pods-Guldan_Example.release.xcconfig */, 193 | 2B47C49C2F4F4DB4767C63B1 /* Pods-Guldan_Tests.debug.xcconfig */, 194 | 79D495AB7B7448A0E43CFBE3 /* Pods-Guldan_Tests.release.xcconfig */, 195 | ); 196 | path = Pods; 197 | sourceTree = ""; 198 | }; 199 | /* End PBXGroup section */ 200 | 201 | /* Begin PBXNativeTarget section */ 202 | 6003F589195388D20070C39A /* Guldan_Example */ = { 203 | isa = PBXNativeTarget; 204 | buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "Guldan_Example" */; 205 | buildPhases = ( 206 | 0BDA6F16CDE33A4D24BFACFD /* [CP] Check Pods Manifest.lock */, 207 | 6003F586195388D20070C39A /* Sources */, 208 | 6003F587195388D20070C39A /* Frameworks */, 209 | 6003F588195388D20070C39A /* Resources */, 210 | 6020DA76F4AA35F0438A7D36 /* [CP] Embed Pods Frameworks */, 211 | ); 212 | buildRules = ( 213 | ); 214 | dependencies = ( 215 | ); 216 | name = Guldan_Example; 217 | productName = Guldan; 218 | productReference = 6003F58A195388D20070C39A /* Guldan_Example.app */; 219 | productType = "com.apple.product-type.application"; 220 | }; 221 | 6003F5AD195388D20070C39A /* Guldan_Tests */ = { 222 | isa = PBXNativeTarget; 223 | buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "Guldan_Tests" */; 224 | buildPhases = ( 225 | 1864728D415D6E901BDB2396 /* [CP] Check Pods Manifest.lock */, 226 | 6003F5AA195388D20070C39A /* Sources */, 227 | 6003F5AB195388D20070C39A /* Frameworks */, 228 | 6003F5AC195388D20070C39A /* Resources */, 229 | ); 230 | buildRules = ( 231 | ); 232 | dependencies = ( 233 | 6003F5B4195388D20070C39A /* PBXTargetDependency */, 234 | ); 235 | name = Guldan_Tests; 236 | productName = GuldanTests; 237 | productReference = 6003F5AE195388D20070C39A /* Guldan_Tests.xctest */; 238 | productType = "com.apple.product-type.bundle.unit-test"; 239 | }; 240 | /* End PBXNativeTarget section */ 241 | 242 | /* Begin PBXProject section */ 243 | 6003F582195388D10070C39A /* Project object */ = { 244 | isa = PBXProject; 245 | attributes = { 246 | CLASSPREFIX = GD; 247 | LastUpgradeCheck = 0720; 248 | ORGANIZATIONNAME = Alex023; 249 | TargetAttributes = { 250 | 6003F589195388D20070C39A = { 251 | DevelopmentTeam = 946DU6K4CH; 252 | }; 253 | 6003F5AD195388D20070C39A = { 254 | TestTargetID = 6003F589195388D20070C39A; 255 | }; 256 | }; 257 | }; 258 | buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "Guldan" */; 259 | compatibilityVersion = "Xcode 3.2"; 260 | developmentRegion = English; 261 | hasScannedForEncodings = 0; 262 | knownRegions = ( 263 | English, 264 | en, 265 | Base, 266 | ); 267 | mainGroup = 6003F581195388D10070C39A; 268 | productRefGroup = 6003F58B195388D20070C39A /* Products */; 269 | projectDirPath = ""; 270 | projectRoot = ""; 271 | targets = ( 272 | 6003F589195388D20070C39A /* Guldan_Example */, 273 | 6003F5AD195388D20070C39A /* Guldan_Tests */, 274 | ); 275 | }; 276 | /* End PBXProject section */ 277 | 278 | /* Begin PBXResourcesBuildPhase section */ 279 | 6003F588195388D20070C39A /* Resources */ = { 280 | isa = PBXResourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */, 284 | 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */, 285 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */, 286 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | 6003F5AC195388D20070C39A /* Resources */ = { 291 | isa = PBXResourcesBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */, 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | /* End PBXResourcesBuildPhase section */ 299 | 300 | /* Begin PBXShellScriptBuildPhase section */ 301 | 0BDA6F16CDE33A4D24BFACFD /* [CP] Check Pods Manifest.lock */ = { 302 | isa = PBXShellScriptBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | ); 306 | inputFileListPaths = ( 307 | ); 308 | inputPaths = ( 309 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 310 | "${PODS_ROOT}/Manifest.lock", 311 | ); 312 | name = "[CP] Check Pods Manifest.lock"; 313 | outputFileListPaths = ( 314 | ); 315 | outputPaths = ( 316 | "$(DERIVED_FILE_DIR)/Pods-Guldan_Example-checkManifestLockResult.txt", 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | shellPath = /bin/sh; 320 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 321 | showEnvVarsInLog = 0; 322 | }; 323 | 1864728D415D6E901BDB2396 /* [CP] Check Pods Manifest.lock */ = { 324 | isa = PBXShellScriptBuildPhase; 325 | buildActionMask = 2147483647; 326 | files = ( 327 | ); 328 | inputFileListPaths = ( 329 | ); 330 | inputPaths = ( 331 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 332 | "${PODS_ROOT}/Manifest.lock", 333 | ); 334 | name = "[CP] Check Pods Manifest.lock"; 335 | outputFileListPaths = ( 336 | ); 337 | outputPaths = ( 338 | "$(DERIVED_FILE_DIR)/Pods-Guldan_Tests-checkManifestLockResult.txt", 339 | ); 340 | runOnlyForDeploymentPostprocessing = 0; 341 | shellPath = /bin/sh; 342 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 343 | showEnvVarsInLog = 0; 344 | }; 345 | 6020DA76F4AA35F0438A7D36 /* [CP] Embed Pods Frameworks */ = { 346 | isa = PBXShellScriptBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | ); 350 | inputPaths = ( 351 | "${PODS_ROOT}/Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example-frameworks.sh", 352 | "${BUILT_PRODUCTS_DIR}/Guldan/Guldan.framework", 353 | ); 354 | name = "[CP] Embed Pods Frameworks"; 355 | outputPaths = ( 356 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Guldan.framework", 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | shellPath = /bin/sh; 360 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example-frameworks.sh\"\n"; 361 | showEnvVarsInLog = 0; 362 | }; 363 | /* End PBXShellScriptBuildPhase section */ 364 | 365 | /* Begin PBXSourcesBuildPhase section */ 366 | 6003F586195388D20070C39A /* Sources */ = { 367 | isa = PBXSourcesBuildPhase; 368 | buildActionMask = 2147483647; 369 | files = ( 370 | 6003F59E195388D20070C39A /* GDAppDelegate.m in Sources */, 371 | 6003F5A7195388D20070C39A /* GDViewController.m in Sources */, 372 | 6003F59A195388D20070C39A /* main.m in Sources */, 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | 6003F5AA195388D20070C39A /* Sources */ = { 377 | isa = PBXSourcesBuildPhase; 378 | buildActionMask = 2147483647; 379 | files = ( 380 | 6003F5BC195388D20070C39A /* Tests.m in Sources */, 381 | ); 382 | runOnlyForDeploymentPostprocessing = 0; 383 | }; 384 | /* End PBXSourcesBuildPhase section */ 385 | 386 | /* Begin PBXTargetDependency section */ 387 | 6003F5B4195388D20070C39A /* PBXTargetDependency */ = { 388 | isa = PBXTargetDependency; 389 | target = 6003F589195388D20070C39A /* Guldan_Example */; 390 | targetProxy = 6003F5B3195388D20070C39A /* PBXContainerItemProxy */; 391 | }; 392 | /* End PBXTargetDependency section */ 393 | 394 | /* Begin PBXVariantGroup section */ 395 | 6003F596195388D20070C39A /* InfoPlist.strings */ = { 396 | isa = PBXVariantGroup; 397 | children = ( 398 | 6003F597195388D20070C39A /* en */, 399 | ); 400 | name = InfoPlist.strings; 401 | sourceTree = ""; 402 | }; 403 | 6003F5B8195388D20070C39A /* InfoPlist.strings */ = { 404 | isa = PBXVariantGroup; 405 | children = ( 406 | 6003F5B9195388D20070C39A /* en */, 407 | ); 408 | name = InfoPlist.strings; 409 | sourceTree = ""; 410 | }; 411 | 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */ = { 412 | isa = PBXVariantGroup; 413 | children = ( 414 | 71719F9E1E33DC2100824A3D /* Base */, 415 | ); 416 | name = LaunchScreen.storyboard; 417 | sourceTree = ""; 418 | }; 419 | /* End PBXVariantGroup section */ 420 | 421 | /* Begin XCBuildConfiguration section */ 422 | 6003F5BD195388D20070C39A /* Debug */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | ALWAYS_SEARCH_USER_PATHS = NO; 426 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 427 | CLANG_CXX_LIBRARY = "libc++"; 428 | CLANG_ENABLE_MODULES = YES; 429 | CLANG_ENABLE_OBJC_ARC = YES; 430 | CLANG_WARN_BOOL_CONVERSION = YES; 431 | CLANG_WARN_CONSTANT_CONVERSION = YES; 432 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 433 | CLANG_WARN_EMPTY_BODY = YES; 434 | CLANG_WARN_ENUM_CONVERSION = YES; 435 | CLANG_WARN_INT_CONVERSION = YES; 436 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 437 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 438 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 439 | COPY_PHASE_STRIP = NO; 440 | ENABLE_TESTABILITY = YES; 441 | GCC_C_LANGUAGE_STANDARD = gnu11; 442 | GCC_DYNAMIC_NO_PIC = NO; 443 | GCC_INPUT_FILETYPE = automatic; 444 | GCC_OPTIMIZATION_LEVEL = 0; 445 | GCC_PREPROCESSOR_DEFINITIONS = ( 446 | "DEBUG=1", 447 | "$(inherited)", 448 | ); 449 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 450 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 451 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 452 | GCC_WARN_UNDECLARED_SELECTOR = YES; 453 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 454 | GCC_WARN_UNUSED_FUNCTION = YES; 455 | GCC_WARN_UNUSED_VARIABLE = YES; 456 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 457 | ONLY_ACTIVE_ARCH = YES; 458 | OTHER_LDFLAGS = ""; 459 | SDKROOT = iphoneos; 460 | TARGETED_DEVICE_FAMILY = "1,2"; 461 | }; 462 | name = Debug; 463 | }; 464 | 6003F5BE195388D20070C39A /* Release */ = { 465 | isa = XCBuildConfiguration; 466 | buildSettings = { 467 | ALWAYS_SEARCH_USER_PATHS = NO; 468 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 469 | CLANG_CXX_LIBRARY = "libc++"; 470 | CLANG_ENABLE_MODULES = YES; 471 | CLANG_ENABLE_OBJC_ARC = YES; 472 | CLANG_WARN_BOOL_CONVERSION = YES; 473 | CLANG_WARN_CONSTANT_CONVERSION = YES; 474 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 475 | CLANG_WARN_EMPTY_BODY = YES; 476 | CLANG_WARN_ENUM_CONVERSION = YES; 477 | CLANG_WARN_INT_CONVERSION = YES; 478 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 479 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 480 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 481 | COPY_PHASE_STRIP = YES; 482 | ENABLE_NS_ASSERTIONS = NO; 483 | GCC_C_LANGUAGE_STANDARD = gnu11; 484 | GCC_INPUT_FILETYPE = automatic; 485 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 486 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 487 | GCC_WARN_UNDECLARED_SELECTOR = YES; 488 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 489 | GCC_WARN_UNUSED_FUNCTION = YES; 490 | GCC_WARN_UNUSED_VARIABLE = YES; 491 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 492 | OTHER_LDFLAGS = ""; 493 | SDKROOT = iphoneos; 494 | TARGETED_DEVICE_FAMILY = "1,2"; 495 | VALIDATE_PRODUCT = YES; 496 | }; 497 | name = Release; 498 | }; 499 | 6003F5C0195388D20070C39A /* Debug */ = { 500 | isa = XCBuildConfiguration; 501 | baseConfigurationReference = 0D6CDEC5169C7A68BF01FDDC /* Pods-Guldan_Example.debug.xcconfig */; 502 | buildSettings = { 503 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 504 | DEVELOPMENT_TEAM = 946DU6K4CH; 505 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 506 | GCC_PREFIX_HEADER = "Guldan/Guldan-Prefix.pch"; 507 | INFOPLIST_FILE = "Guldan/Guldan-Info.plist"; 508 | MODULE_NAME = ExampleApp; 509 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; 510 | PRODUCT_NAME = "$(TARGET_NAME)"; 511 | SWIFT_VERSION = 4.0; 512 | WRAPPER_EXTENSION = app; 513 | }; 514 | name = Debug; 515 | }; 516 | 6003F5C1195388D20070C39A /* Release */ = { 517 | isa = XCBuildConfiguration; 518 | baseConfigurationReference = 3AA2BC88BA3289BACAC12C22 /* Pods-Guldan_Example.release.xcconfig */; 519 | buildSettings = { 520 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 521 | DEVELOPMENT_TEAM = 946DU6K4CH; 522 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 523 | GCC_PREFIX_HEADER = "Guldan/Guldan-Prefix.pch"; 524 | INFOPLIST_FILE = "Guldan/Guldan-Info.plist"; 525 | MODULE_NAME = ExampleApp; 526 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; 527 | PRODUCT_NAME = "$(TARGET_NAME)"; 528 | SWIFT_VERSION = 4.0; 529 | WRAPPER_EXTENSION = app; 530 | }; 531 | name = Release; 532 | }; 533 | 6003F5C3195388D20070C39A /* Debug */ = { 534 | isa = XCBuildConfiguration; 535 | baseConfigurationReference = 2B47C49C2F4F4DB4767C63B1 /* Pods-Guldan_Tests.debug.xcconfig */; 536 | buildSettings = { 537 | BUNDLE_LOADER = "$(TEST_HOST)"; 538 | FRAMEWORK_SEARCH_PATHS = ( 539 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 540 | "$(inherited)", 541 | "$(DEVELOPER_FRAMEWORKS_DIR)", 542 | ); 543 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 544 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 545 | GCC_PREPROCESSOR_DEFINITIONS = ( 546 | "DEBUG=1", 547 | "$(inherited)", 548 | ); 549 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 550 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; 551 | PRODUCT_NAME = "$(TARGET_NAME)"; 552 | SWIFT_VERSION = 4.0; 553 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Guldan_Example.app/Guldan_Example"; 554 | WRAPPER_EXTENSION = xctest; 555 | }; 556 | name = Debug; 557 | }; 558 | 6003F5C4195388D20070C39A /* Release */ = { 559 | isa = XCBuildConfiguration; 560 | baseConfigurationReference = 79D495AB7B7448A0E43CFBE3 /* Pods-Guldan_Tests.release.xcconfig */; 561 | buildSettings = { 562 | BUNDLE_LOADER = "$(TEST_HOST)"; 563 | FRAMEWORK_SEARCH_PATHS = ( 564 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 565 | "$(inherited)", 566 | "$(DEVELOPER_FRAMEWORKS_DIR)", 567 | ); 568 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 569 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 570 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 571 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; 572 | PRODUCT_NAME = "$(TARGET_NAME)"; 573 | SWIFT_VERSION = 4.0; 574 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Guldan_Example.app/Guldan_Example"; 575 | WRAPPER_EXTENSION = xctest; 576 | }; 577 | name = Release; 578 | }; 579 | /* End XCBuildConfiguration section */ 580 | 581 | /* Begin XCConfigurationList section */ 582 | 6003F585195388D10070C39A /* Build configuration list for PBXProject "Guldan" */ = { 583 | isa = XCConfigurationList; 584 | buildConfigurations = ( 585 | 6003F5BD195388D20070C39A /* Debug */, 586 | 6003F5BE195388D20070C39A /* Release */, 587 | ); 588 | defaultConfigurationIsVisible = 0; 589 | defaultConfigurationName = Release; 590 | }; 591 | 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "Guldan_Example" */ = { 592 | isa = XCConfigurationList; 593 | buildConfigurations = ( 594 | 6003F5C0195388D20070C39A /* Debug */, 595 | 6003F5C1195388D20070C39A /* Release */, 596 | ); 597 | defaultConfigurationIsVisible = 0; 598 | defaultConfigurationName = Release; 599 | }; 600 | 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "Guldan_Tests" */ = { 601 | isa = XCConfigurationList; 602 | buildConfigurations = ( 603 | 6003F5C3195388D20070C39A /* Debug */, 604 | 6003F5C4195388D20070C39A /* Release */, 605 | ); 606 | defaultConfigurationIsVisible = 0; 607 | defaultConfigurationName = Release; 608 | }; 609 | /* End XCConfigurationList section */ 610 | }; 611 | rootObject = 6003F582195388D10070C39A /* Project object */; 612 | } 613 | -------------------------------------------------------------------------------- /Example/Guldan.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Guldan.xcodeproj/xcshareddata/xcschemes/Guldan-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 64 | 70 | 71 | 72 | 73 | 79 | 81 | 87 | 88 | 89 | 90 | 92 | 93 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Example/Guldan.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Guldan.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Guldan/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 | -------------------------------------------------------------------------------- /Example/Guldan/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 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Example/Guldan/GDAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDAppDelegate.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 11/11/2021. 6 | // Copyright (c) 2021 Alex023. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface GDAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/Guldan/GDAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDAppDelegate.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 11/11/2021. 6 | // Copyright (c) 2021 Alex023. All rights reserved. 7 | // 8 | 9 | #import "GDAppDelegate.h" 10 | #import "GDNOCMethodTimeProfiler.h" 11 | 12 | @implementation GDAppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 15 | { 16 | // Override point for customization after application launch. 17 | [GDNOCMethodTimeProfiler start]; 18 | [self testDelegate]; 19 | return YES; 20 | } 21 | 22 | - (void)testDelegate 23 | { 24 | clock_t start = clock(); 25 | [self delegateM1]; 26 | [self delegateM2]; 27 | clock_t end = clock(); 28 | double cost = (double)(end - start) / CLOCKS_PER_SEC; 29 | NSLog(@"cost:%f", cost); 30 | 31 | } 32 | 33 | - (void)delegateM1 { 34 | sleep(2); 35 | dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ 36 | 37 | [self delegateM3]; 38 | }); 39 | } 40 | 41 | - (void)delegateM2 { 42 | // dispatch_async(dispatch_get_main_queue(), ^{ 43 | // for (int i = 0; i < 100000; i++) { 44 | // UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; 45 | // [self.window addSubview:v]; 46 | // [v removeFromSuperview]; 47 | // } 48 | // }); 49 | for (int i = 0; i < 10000; i++) { 50 | NSLog(@"%d", i * 2); 51 | } 52 | } 53 | 54 | - (void)delegateM3 { 55 | for (int i = 0; i < 10000; i++) { 56 | NSLog(@"%d", i * 2); 57 | } 58 | } 59 | 60 | - (void)applicationWillResignActive:(UIApplication *)application 61 | { 62 | // 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. 63 | // 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. 64 | } 65 | 66 | - (void)applicationDidEnterBackground:(UIApplication *)application 67 | { 68 | // 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. 69 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 70 | } 71 | 72 | - (void)applicationWillEnterForeground:(UIApplication *)application 73 | { 74 | // 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. 75 | } 76 | 77 | - (void)applicationDidBecomeActive:(UIApplication *)application 78 | { 79 | // 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. 80 | } 81 | 82 | - (void)applicationWillTerminate:(UIApplication *)application 83 | { 84 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 85 | } 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /Example/Guldan/GDViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDViewController.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 11/11/2021. 6 | // Copyright (c) 2021 Alex023. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface GDViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/Guldan/GDViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDViewController.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 11/11/2021. 6 | // Copyright (c) 2021 Alex023. All rights reserved. 7 | // 8 | 9 | #import "GDViewController.h" 10 | #import "GDNOCMethodTimeProfiler.h" 11 | 12 | @interface GDViewController () 13 | 14 | @end 15 | 16 | @implementation GDViewController 17 | 18 | - (void)viewDidLoad 19 | { 20 | [super viewDidLoad]; 21 | // Do any additional setup after loading the view, typically from a nib. 22 | 23 | [self testM]; 24 | [GDNOCMethodTimeProfiler stop]; 25 | 26 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 27 | [GDNOCMethodTimeProfiler handleRecordsWithComplete:^(NSArray * _Nonnull filePaths) { 28 | 29 | }]; 30 | }); 31 | } 32 | 33 | - (void)testM 34 | { 35 | clock_t start = clock(); 36 | [self m1]; 37 | [self m2]; 38 | clock_t end = clock(); 39 | double cost = (double)(end - start) / CLOCKS_PER_SEC; 40 | NSLog(@"cost:%f", cost); 41 | 42 | } 43 | 44 | - (void)m1 { 45 | sleep(2); 46 | [self m3]; 47 | [self m3]; 48 | } 49 | 50 | - (void)m2 { 51 | dispatch_async(dispatch_get_main_queue(), ^{ 52 | NSLog(@"1"); 53 | NSLog(@"1"); 54 | NSLog(@"1"); 55 | NSLog(@"1"); 56 | 57 | NSLog(@"1"); 58 | }); 59 | } 60 | 61 | - (void)m3 { 62 | for (int i = 0; i < 10000; i++) { 63 | NSLog(@"%d", i); 64 | } 65 | } 66 | 67 | - (void)didReceiveMemoryWarning 68 | { 69 | [super didReceiveMemoryWarning]; 70 | // Dispose of any resources that can be recreated. 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /Example/Guldan/Guldan-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/Guldan/Guldan-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/Guldan/Images.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 | } 99 | -------------------------------------------------------------------------------- /Example/Guldan/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Guldan/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 11/11/2021. 6 | // Copyright (c) 2021 Alex023. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "GDAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([GDAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | source 'ssh://git@gitlab.huolala.cn:56358/group-wp-sdk/hll-wp-specs-ios.git' 4 | source 'https://cdn.cocoapods.org/' 5 | 6 | platform :ios, '9.0' 7 | 8 | target 'Guldan_Example' do 9 | pod 'Guldan', :path => '../' 10 | 11 | target 'Guldan_Tests' do 12 | inherit! :search_paths 13 | 14 | 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Guldan (0.1.0) 3 | 4 | DEPENDENCIES: 5 | - Guldan (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | Guldan: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | Guldan: 55207a0bed3b8f977c512ae56918409392f448c9 13 | 14 | PODFILE CHECKSUM: 93cd923fedb0f6b46eb0bf883fb2c40d29273c96 15 | 16 | COCOAPODS: 1.10.1 17 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/Guldan.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Guldan", 3 | "version": "0.1.0", 4 | "summary": "OC Method Time Cost Tool", 5 | "description": "HUOLALA OC Method Cost Time Profiler", 6 | "homepage": "https://xxx.com", 7 | "license": { 8 | "type": "MIT", 9 | "file": "LICENSE" 10 | }, 11 | "authors": { 12 | "货拉拉": "货拉拉" 13 | }, 14 | "source": { 15 | "git": "", 16 | "tag": "0.1.0" 17 | }, 18 | "platforms": { 19 | "ios": "9.0" 20 | }, 21 | "source_files": "Guldan/Classes/**/*" 22 | } 23 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Guldan (0.1.0) 3 | 4 | DEPENDENCIES: 5 | - Guldan (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | Guldan: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | Guldan: 55207a0bed3b8f977c512ae56918409392f448c9 13 | 14 | PODFILE CHECKSUM: 93cd923fedb0f6b46eb0bf883fb2c40d29273c96 15 | 16 | COCOAPODS: 1.10.1 17 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 152084562CAC1DEC53142EBA10738631 /* Guldan-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B8379F6C2120A0DCF97A72275842571 /* Guldan-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 15EDBD0999672FDEC1BB71BC0E03808A /* gdn_objc_msgSend_time_profiler.h in Headers */ = {isa = PBXBuildFile; fileRef = E674A38B0A64D7510DE12A615193D72A /* gdn_objc_msgSend_time_profiler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | 1AA7E929E90207056545A1F998C4A511 /* UIWindow+GDN.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A2D2B0F0B25F866DEB5FD0C4EB2334A /* UIWindow+GDN.m */; }; 13 | 214CCDBBC704B73852B35F1C981C4556 /* Pods-Guldan_Tests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 019B6B62D4A6DDC25B79875E7A4B28A7 /* Pods-Guldan_Tests-dummy.m */; }; 14 | 2763B6215BFB46A0C2E8661623F6E1E0 /* GDNOCMethodTimeProfilerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = E226B288B295FD15C8A25CB04449E7EA /* GDNOCMethodTimeProfilerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | 30C9917141E601D2D37A92925A905371 /* Pods-Guldan_Example-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E7EC6AD7A33AB68613324EA4A9F4A9F /* Pods-Guldan_Example-dummy.m */; }; 16 | 45F8B8DA56FC3697C05A356F4AAB2C28 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; 17 | 4D00A45BDB95072BBD318C0614C95BFD /* GDNRecordDetailViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = B3CF0C1D167134BC38DB4E3DA4BA9CED /* GDNRecordDetailViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18 | 4FFB9A61546E3F804C57512D4307A559 /* GDNRecordRootViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 79F654A218469A0692FF81D3FD6C1E33 /* GDNRecordRootViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | 6067957D881CFB72E62981024D898048 /* GDNRecordDetailCell.m in Sources */ = {isa = PBXBuildFile; fileRef = AD85EC4EE2B38700675C071A68C9CE72 /* GDNRecordDetailCell.m */; }; 20 | 693F11307E3B30ACFFC80C4C71BEF62D /* Pods-Guldan_Example-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A36DB4D3448E268D52CE0CCE3C2EED51 /* Pods-Guldan_Example-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 21 | 7FFDE26D6D0C00305616DEA1270771DE /* Guldan-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C50967208315F102D6E0914D443F9D0D /* Guldan-dummy.m */; }; 22 | 854584D123451F1AB3812AACBA6127AB /* GDNOCMethodTimeProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 79828FDC05396947A308AEFCAC52979B /* GDNOCMethodTimeProfiler.m */; }; 23 | 8DD6EC8B016C15EA1384AFD18ACA9467 /* HLLFishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 0EE98F25F600677CD2B9682303C591D3 /* HLLFishhook.h */; settings = {ATTRIBUTES = (Public, ); }; }; 24 | A2A97B55278D30D05160BFBECBCCE6FD /* GDNUIModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 902B7E810F54EB2D542AD97A5D240ABE /* GDNUIModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25 | A83F652BF729BDA6E20FB8BB509D14DC /* GDNUIModel.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1A99956DFC08F1EE16C791CE6D63BD /* GDNUIModel.m */; }; 26 | B3F06B09B7E928DD3A5DD3DDFC271D94 /* GDNRecordHierarchyModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F66F5CFB739465B258F539BDCB50B41 /* GDNRecordHierarchyModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 27 | BA78B2628119CA1DCD43483F88AAA5CB /* UIWindow+GDN.h in Headers */ = {isa = PBXBuildFile; fileRef = C41B2595CA882201645C9FB80BB88F07 /* UIWindow+GDN.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | C32DB0CE4ADE182E4A2562632FADBEB6 /* GDNOCMethodTimeProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 50079B26CA2CAA4E7717EDF29F97D361 /* GDNOCMethodTimeProfiler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29 | C751784FC17F1A1B9752BF3FCCA76957 /* GDNRecordModel.h in Headers */ = {isa = PBXBuildFile; fileRef = B6B1E3187D8E35BA91296B06A2F3C3D8 /* GDNRecordModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30 | C8AFEDFD3867828DB1096067B9209675 /* Pods-Guldan_Tests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F47FAB4133CB8C7A362BCEEC6CD58A4 /* Pods-Guldan_Tests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 31 | CC0F9B3C8D7E8D1BE033192F38489722 /* GDNRecordModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DAD6385622D56CDAE19230CEBB99AAF /* GDNRecordModel.m */; }; 32 | D1A083F3615645ABAD4051E055AC4D72 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; 33 | D22CE00D94627EE8C2BBAA7ED2DDF002 /* GDNRecordHierarchyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 21D1F210A32A1C1C7645F18E1BF44619 /* GDNRecordHierarchyModel.m */; }; 34 | D4E0B70E9DC6BC7B27E831A0E3320234 /* HLLFishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 7E5A8FF5A8EDBD65C7C3F636A55F6ECC /* HLLFishhook.c */; }; 35 | D58C1FF73DDE9769F61EC3E70473C7E9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; 36 | D8084212F32A47BD631A902F51F5A15E /* gdn_objc_msgSend_time_profiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 70661D405F8D296C1B651ABC139C821E /* gdn_objc_msgSend_time_profiler.m */; }; 37 | DBE86477907A567CDCE3B062EB452E27 /* GDNRecordDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D5E83535D3D23DBAEDA84A4B5ADA6A9 /* GDNRecordDetailViewController.m */; }; 38 | DDEB6E04FD4BA6DB72F5D56A5EFFD623 /* gdn_objc_msgSend.s in Sources */ = {isa = PBXBuildFile; fileRef = 1EE0E49B7CCAC00AFC14FD683CF05579 /* gdn_objc_msgSend.s */; }; 39 | E0DFC527862CB314892BDE90B44F968E /* gdn_objc_msgSend.h in Headers */ = {isa = PBXBuildFile; fileRef = 27DA21D5DC0C797BBD9AD82C1B7BA603 /* gdn_objc_msgSend.h */; settings = {ATTRIBUTES = (Public, ); }; }; 40 | F6E5444CA707345B665A8A39079CF2A4 /* GDNRecordRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F1175B2E72F5AEA07DD328EE9A206BF /* GDNRecordRootViewController.m */; }; 41 | F84AAE24ACDCB30AA3F36635B50F65D8 /* Guldan.h in Headers */ = {isa = PBXBuildFile; fileRef = 31BAA0D809651017BE6707B5A6698846 /* Guldan.h */; settings = {ATTRIBUTES = (Public, ); }; }; 42 | FD52B5DFFA75835BE2C69ABF945C5A18 /* GDNRecordDetailCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 85DA38270FEEBC747D6F9E6821963628 /* GDNRecordDetailCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; 43 | /* End PBXBuildFile section */ 44 | 45 | /* Begin PBXContainerItemProxy section */ 46 | 27B7B3A14F62C5D4DB70B88FD7ECE2E0 /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = B46A651FE22D8CC5CEC85CBCD2E74CEC; 51 | remoteInfo = "Pods-Guldan_Example"; 52 | }; 53 | 3E73BAA00345831EA3C278AEC35787DB /* PBXContainerItemProxy */ = { 54 | isa = PBXContainerItemProxy; 55 | containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; 56 | proxyType = 1; 57 | remoteGlobalIDString = 0DD5ED1A29984177DF7C725984A634F1; 58 | remoteInfo = Guldan; 59 | }; 60 | /* End PBXContainerItemProxy section */ 61 | 62 | /* Begin PBXFileReference section */ 63 | 019B6B62D4A6DDC25B79875E7A4B28A7 /* Pods-Guldan_Tests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Guldan_Tests-dummy.m"; sourceTree = ""; }; 64 | 0EE98F25F600677CD2B9682303C591D3 /* HLLFishhook.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HLLFishhook.h; path = Guldan/Classes/HLLFishhook.h; sourceTree = ""; }; 65 | 1EE0E49B7CCAC00AFC14FD683CF05579 /* gdn_objc_msgSend.s */ = {isa = PBXFileReference; includeInIndex = 1; name = gdn_objc_msgSend.s; path = Guldan/Classes/gdn_objc_msgSend.s; sourceTree = ""; }; 66 | 1F47FAB4133CB8C7A362BCEEC6CD58A4 /* Pods-Guldan_Tests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Guldan_Tests-umbrella.h"; sourceTree = ""; }; 67 | 21D1F210A32A1C1C7645F18E1BF44619 /* GDNRecordHierarchyModel.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = GDNRecordHierarchyModel.m; sourceTree = ""; }; 68 | 27DA21D5DC0C797BBD9AD82C1B7BA603 /* gdn_objc_msgSend.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = gdn_objc_msgSend.h; path = Guldan/Classes/gdn_objc_msgSend.h; sourceTree = ""; }; 69 | 2EBC88786004F7DC3AC3A28F5B7E26D5 /* Guldan-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Guldan-Info.plist"; sourceTree = ""; }; 70 | 31BAA0D809651017BE6707B5A6698846 /* Guldan.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Guldan.h; path = Guldan/Classes/Guldan.h; sourceTree = ""; }; 71 | 344D2F429C1C9DDD07623B20717A9E22 /* Pods-Guldan_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Guldan_Tests.debug.xcconfig"; sourceTree = ""; }; 72 | 3A2D2B0F0B25F866DEB5FD0C4EB2334A /* UIWindow+GDN.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "UIWindow+GDN.m"; sourceTree = ""; }; 73 | 3B4F25693CAA240D2F9812652AFB65A4 /* Pods-Guldan_Tests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Guldan_Tests-Info.plist"; sourceTree = ""; }; 74 | 3C597D6DB5BDAFE6684599F8F380596F /* Pods-Guldan_Example.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Guldan_Example.modulemap"; sourceTree = ""; }; 75 | 3D5E83535D3D23DBAEDA84A4B5ADA6A9 /* GDNRecordDetailViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = GDNRecordDetailViewController.m; sourceTree = ""; }; 76 | 3DB8D0CBBA254549F5C65EB76E8A7C44 /* Guldan-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Guldan-prefix.pch"; sourceTree = ""; }; 77 | 3EF0C8932439425E7357A09E7DCABDAB /* Guldan.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = Guldan.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 78 | 3EFA0451D705080C65A708695C8FC28D /* Pods-Guldan_Example-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Guldan_Example-Info.plist"; sourceTree = ""; }; 79 | 463FAC86701EADB05CECD15C87D857D2 /* Pods_Guldan_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Guldan_Tests.framework; path = "Pods-Guldan_Tests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | 4DAD6385622D56CDAE19230CEBB99AAF /* GDNRecordModel.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = GDNRecordModel.m; sourceTree = ""; }; 81 | 50079B26CA2CAA4E7717EDF29F97D361 /* GDNOCMethodTimeProfiler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDNOCMethodTimeProfiler.h; path = Guldan/Classes/GDNOCMethodTimeProfiler.h; sourceTree = ""; }; 82 | 5F1175B2E72F5AEA07DD328EE9A206BF /* GDNRecordRootViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = GDNRecordRootViewController.m; sourceTree = ""; }; 83 | 608B599BC6570A69C6DC67105F385883 /* Pods-Guldan_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Guldan_Example.debug.xcconfig"; sourceTree = ""; }; 84 | 625E9EA2F204A821418ED12ECEAEFCDF /* Pods-Guldan_Example-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Guldan_Example-acknowledgements.markdown"; sourceTree = ""; }; 85 | 6B8379F6C2120A0DCF97A72275842571 /* Guldan-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Guldan-umbrella.h"; sourceTree = ""; }; 86 | 6E7EC6AD7A33AB68613324EA4A9F4A9F /* Pods-Guldan_Example-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Guldan_Example-dummy.m"; sourceTree = ""; }; 87 | 70661D405F8D296C1B651ABC139C821E /* gdn_objc_msgSend_time_profiler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = gdn_objc_msgSend_time_profiler.m; path = Guldan/Classes/gdn_objc_msgSend_time_profiler.m; sourceTree = ""; }; 88 | 71263FE83A792883268EDD7A5360C194 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; path = README.md; sourceTree = ""; }; 89 | 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 90 | 79828FDC05396947A308AEFCAC52979B /* GDNOCMethodTimeProfiler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDNOCMethodTimeProfiler.m; path = Guldan/Classes/GDNOCMethodTimeProfiler.m; sourceTree = ""; }; 91 | 79F654A218469A0692FF81D3FD6C1E33 /* GDNRecordRootViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GDNRecordRootViewController.h; sourceTree = ""; }; 92 | 7D52DA981ACEA9B1C5EFB8D8DE49E80F /* Guldan.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Guldan.release.xcconfig; sourceTree = ""; }; 93 | 7E5A8FF5A8EDBD65C7C3F636A55F6ECC /* HLLFishhook.c */ = {isa = PBXFileReference; includeInIndex = 1; name = HLLFishhook.c; path = Guldan/Classes/HLLFishhook.c; sourceTree = ""; }; 94 | 85DA38270FEEBC747D6F9E6821963628 /* GDNRecordDetailCell.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GDNRecordDetailCell.h; sourceTree = ""; }; 95 | 8678A8DD6C384D7281DFD172975831CD /* Pods-Guldan_Example-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Guldan_Example-acknowledgements.plist"; sourceTree = ""; }; 96 | 8E0F236EE64AEED647D7BB2A62445D54 /* Pods-Guldan_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Guldan_Tests.release.xcconfig"; sourceTree = ""; }; 97 | 8F698A7D41AFC5A47704B78BA5E09F81 /* Guldan.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Guldan.framework; path = Guldan.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 98 | 902B7E810F54EB2D542AD97A5D240ABE /* GDNUIModel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GDNUIModel.h; sourceTree = ""; }; 99 | 93097FE174B4ED9F20DD9677312DE3D0 /* Guldan.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Guldan.modulemap; sourceTree = ""; }; 100 | 94E0DFBC4C04253969D9E9073B361CE0 /* Pods-Guldan_Example-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Guldan_Example-frameworks.sh"; sourceTree = ""; }; 101 | 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 102 | 9F66F5CFB739465B258F539BDCB50B41 /* GDNRecordHierarchyModel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GDNRecordHierarchyModel.h; sourceTree = ""; }; 103 | A36DB4D3448E268D52CE0CCE3C2EED51 /* Pods-Guldan_Example-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Guldan_Example-umbrella.h"; sourceTree = ""; }; 104 | A5B2730D5089F712AB176E17551BB659 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; path = LICENSE; sourceTree = ""; }; 105 | A6D6834880A46C86198282CFE787533F /* Pods-Guldan_Tests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Guldan_Tests-acknowledgements.plist"; sourceTree = ""; }; 106 | AD85EC4EE2B38700675C071A68C9CE72 /* GDNRecordDetailCell.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = GDNRecordDetailCell.m; sourceTree = ""; }; 107 | AEC7843ABF876424A238295D19C9F50A /* Pods_Guldan_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Guldan_Example.framework; path = "Pods-Guldan_Example.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 108 | B3CF0C1D167134BC38DB4E3DA4BA9CED /* GDNRecordDetailViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GDNRecordDetailViewController.h; sourceTree = ""; }; 109 | B6B1E3187D8E35BA91296B06A2F3C3D8 /* GDNRecordModel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = GDNRecordModel.h; sourceTree = ""; }; 110 | C41B2595CA882201645C9FB80BB88F07 /* UIWindow+GDN.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "UIWindow+GDN.h"; sourceTree = ""; }; 111 | C50967208315F102D6E0914D443F9D0D /* Guldan-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Guldan-dummy.m"; sourceTree = ""; }; 112 | C8F3D160B3F88E704C4EDFDAD896F1AC /* Guldan.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Guldan.debug.xcconfig; sourceTree = ""; }; 113 | CD1CF3FE0E66C88D1222FE09689F04F6 /* Pods-Guldan_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Guldan_Example.release.xcconfig"; sourceTree = ""; }; 114 | E226B288B295FD15C8A25CB04449E7EA /* GDNOCMethodTimeProfilerProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDNOCMethodTimeProfilerProtocol.h; path = Guldan/Classes/GDNOCMethodTimeProfilerProtocol.h; sourceTree = ""; }; 115 | E674A38B0A64D7510DE12A615193D72A /* gdn_objc_msgSend_time_profiler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = gdn_objc_msgSend_time_profiler.h; path = Guldan/Classes/gdn_objc_msgSend_time_profiler.h; sourceTree = ""; }; 116 | EFCCDB33517BA5393B311C632F1C9530 /* Pods-Guldan_Tests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Guldan_Tests-acknowledgements.markdown"; sourceTree = ""; }; 117 | F594FEA4B989BA5ECF4D55E700D60F06 /* Pods-Guldan_Tests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Guldan_Tests.modulemap"; sourceTree = ""; }; 118 | FB1A99956DFC08F1EE16C791CE6D63BD /* GDNUIModel.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = GDNUIModel.m; sourceTree = ""; }; 119 | /* End PBXFileReference section */ 120 | 121 | /* Begin PBXFrameworksBuildPhase section */ 122 | 130C247E52EC1F1139976C78B9360FF6 /* Frameworks */ = { 123 | isa = PBXFrameworksBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | D1A083F3615645ABAD4051E055AC4D72 /* Foundation.framework in Frameworks */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | 2757CE5769592622B7E7CD082F71B8F9 /* Frameworks */ = { 131 | isa = PBXFrameworksBuildPhase; 132 | buildActionMask = 2147483647; 133 | files = ( 134 | 45F8B8DA56FC3697C05A356F4AAB2C28 /* Foundation.framework in Frameworks */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | 531D66199678DF88C9058BE203AA8D14 /* Frameworks */ = { 139 | isa = PBXFrameworksBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | D58C1FF73DDE9769F61EC3E70473C7E9 /* Foundation.framework in Frameworks */, 143 | ); 144 | runOnlyForDeploymentPostprocessing = 0; 145 | }; 146 | /* End PBXFrameworksBuildPhase section */ 147 | 148 | /* Begin PBXGroup section */ 149 | 1AD6B8CBA93399717387A53E588D33DC /* Targets Support Files */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 73DD9A9F84EA2F667B9B1CD8B564E366 /* Pods-Guldan_Example */, 153 | AA79AE41B4B9E691CA5048AA89603249 /* Pods-Guldan_Tests */, 154 | ); 155 | name = "Targets Support Files"; 156 | sourceTree = ""; 157 | }; 158 | 39C728A0B16981F05BE8169A1F39B5D3 /* Products */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 8F698A7D41AFC5A47704B78BA5E09F81 /* Guldan.framework */, 162 | AEC7843ABF876424A238295D19C9F50A /* Pods_Guldan_Example.framework */, 163 | 463FAC86701EADB05CECD15C87D857D2 /* Pods_Guldan_Tests.framework */, 164 | ); 165 | name = Products; 166 | sourceTree = ""; 167 | }; 168 | 578452D2E740E91742655AC8F1636D1F /* iOS */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */, 172 | ); 173 | name = iOS; 174 | sourceTree = ""; 175 | }; 176 | 73DD9A9F84EA2F667B9B1CD8B564E366 /* Pods-Guldan_Example */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 3C597D6DB5BDAFE6684599F8F380596F /* Pods-Guldan_Example.modulemap */, 180 | 625E9EA2F204A821418ED12ECEAEFCDF /* Pods-Guldan_Example-acknowledgements.markdown */, 181 | 8678A8DD6C384D7281DFD172975831CD /* Pods-Guldan_Example-acknowledgements.plist */, 182 | 6E7EC6AD7A33AB68613324EA4A9F4A9F /* Pods-Guldan_Example-dummy.m */, 183 | 94E0DFBC4C04253969D9E9073B361CE0 /* Pods-Guldan_Example-frameworks.sh */, 184 | 3EFA0451D705080C65A708695C8FC28D /* Pods-Guldan_Example-Info.plist */, 185 | A36DB4D3448E268D52CE0CCE3C2EED51 /* Pods-Guldan_Example-umbrella.h */, 186 | 608B599BC6570A69C6DC67105F385883 /* Pods-Guldan_Example.debug.xcconfig */, 187 | CD1CF3FE0E66C88D1222FE09689F04F6 /* Pods-Guldan_Example.release.xcconfig */, 188 | ); 189 | name = "Pods-Guldan_Example"; 190 | path = "Target Support Files/Pods-Guldan_Example"; 191 | sourceTree = ""; 192 | }; 193 | 77B7B67262619032AC5A7DF1293B0DA8 /* UI */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 85DA38270FEEBC747D6F9E6821963628 /* GDNRecordDetailCell.h */, 197 | AD85EC4EE2B38700675C071A68C9CE72 /* GDNRecordDetailCell.m */, 198 | B3CF0C1D167134BC38DB4E3DA4BA9CED /* GDNRecordDetailViewController.h */, 199 | 3D5E83535D3D23DBAEDA84A4B5ADA6A9 /* GDNRecordDetailViewController.m */, 200 | 9F66F5CFB739465B258F539BDCB50B41 /* GDNRecordHierarchyModel.h */, 201 | 21D1F210A32A1C1C7645F18E1BF44619 /* GDNRecordHierarchyModel.m */, 202 | B6B1E3187D8E35BA91296B06A2F3C3D8 /* GDNRecordModel.h */, 203 | 4DAD6385622D56CDAE19230CEBB99AAF /* GDNRecordModel.m */, 204 | 79F654A218469A0692FF81D3FD6C1E33 /* GDNRecordRootViewController.h */, 205 | 5F1175B2E72F5AEA07DD328EE9A206BF /* GDNRecordRootViewController.m */, 206 | 902B7E810F54EB2D542AD97A5D240ABE /* GDNUIModel.h */, 207 | FB1A99956DFC08F1EE16C791CE6D63BD /* GDNUIModel.m */, 208 | C41B2595CA882201645C9FB80BB88F07 /* UIWindow+GDN.h */, 209 | 3A2D2B0F0B25F866DEB5FD0C4EB2334A /* UIWindow+GDN.m */, 210 | ); 211 | name = UI; 212 | path = Guldan/Classes/UI; 213 | sourceTree = ""; 214 | }; 215 | 921867D4358AFA9E7A1CB7AFA2F806F0 /* Pod */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | 3EF0C8932439425E7357A09E7DCABDAB /* Guldan.podspec */, 219 | A5B2730D5089F712AB176E17551BB659 /* LICENSE */, 220 | 71263FE83A792883268EDD7A5360C194 /* README.md */, 221 | ); 222 | name = Pod; 223 | sourceTree = ""; 224 | }; 225 | AA79AE41B4B9E691CA5048AA89603249 /* Pods-Guldan_Tests */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | F594FEA4B989BA5ECF4D55E700D60F06 /* Pods-Guldan_Tests.modulemap */, 229 | EFCCDB33517BA5393B311C632F1C9530 /* Pods-Guldan_Tests-acknowledgements.markdown */, 230 | A6D6834880A46C86198282CFE787533F /* Pods-Guldan_Tests-acknowledgements.plist */, 231 | 019B6B62D4A6DDC25B79875E7A4B28A7 /* Pods-Guldan_Tests-dummy.m */, 232 | 3B4F25693CAA240D2F9812652AFB65A4 /* Pods-Guldan_Tests-Info.plist */, 233 | 1F47FAB4133CB8C7A362BCEEC6CD58A4 /* Pods-Guldan_Tests-umbrella.h */, 234 | 344D2F429C1C9DDD07623B20717A9E22 /* Pods-Guldan_Tests.debug.xcconfig */, 235 | 8E0F236EE64AEED647D7BB2A62445D54 /* Pods-Guldan_Tests.release.xcconfig */, 236 | ); 237 | name = "Pods-Guldan_Tests"; 238 | path = "Target Support Files/Pods-Guldan_Tests"; 239 | sourceTree = ""; 240 | }; 241 | AD9232E7EE8C6C4E79029652A186FA48 /* Guldan */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | 27DA21D5DC0C797BBD9AD82C1B7BA603 /* gdn_objc_msgSend.h */, 245 | 1EE0E49B7CCAC00AFC14FD683CF05579 /* gdn_objc_msgSend.s */, 246 | E674A38B0A64D7510DE12A615193D72A /* gdn_objc_msgSend_time_profiler.h */, 247 | 70661D405F8D296C1B651ABC139C821E /* gdn_objc_msgSend_time_profiler.m */, 248 | 50079B26CA2CAA4E7717EDF29F97D361 /* GDNOCMethodTimeProfiler.h */, 249 | 79828FDC05396947A308AEFCAC52979B /* GDNOCMethodTimeProfiler.m */, 250 | E226B288B295FD15C8A25CB04449E7EA /* GDNOCMethodTimeProfilerProtocol.h */, 251 | 31BAA0D809651017BE6707B5A6698846 /* Guldan.h */, 252 | 7E5A8FF5A8EDBD65C7C3F636A55F6ECC /* HLLFishhook.c */, 253 | 0EE98F25F600677CD2B9682303C591D3 /* HLLFishhook.h */, 254 | 921867D4358AFA9E7A1CB7AFA2F806F0 /* Pod */, 255 | C1D806696DE8CB74C60D6F7E63ACCAA7 /* Support Files */, 256 | 77B7B67262619032AC5A7DF1293B0DA8 /* UI */, 257 | ); 258 | name = Guldan; 259 | path = ../..; 260 | sourceTree = ""; 261 | }; 262 | B71A56962D1D833730406CE54F4BA361 /* Development Pods */ = { 263 | isa = PBXGroup; 264 | children = ( 265 | AD9232E7EE8C6C4E79029652A186FA48 /* Guldan */, 266 | ); 267 | name = "Development Pods"; 268 | sourceTree = ""; 269 | }; 270 | C1D806696DE8CB74C60D6F7E63ACCAA7 /* Support Files */ = { 271 | isa = PBXGroup; 272 | children = ( 273 | 93097FE174B4ED9F20DD9677312DE3D0 /* Guldan.modulemap */, 274 | C50967208315F102D6E0914D443F9D0D /* Guldan-dummy.m */, 275 | 2EBC88786004F7DC3AC3A28F5B7E26D5 /* Guldan-Info.plist */, 276 | 3DB8D0CBBA254549F5C65EB76E8A7C44 /* Guldan-prefix.pch */, 277 | 6B8379F6C2120A0DCF97A72275842571 /* Guldan-umbrella.h */, 278 | C8F3D160B3F88E704C4EDFDAD896F1AC /* Guldan.debug.xcconfig */, 279 | 7D52DA981ACEA9B1C5EFB8D8DE49E80F /* Guldan.release.xcconfig */, 280 | ); 281 | name = "Support Files"; 282 | path = "Example/Pods/Target Support Files/Guldan"; 283 | sourceTree = ""; 284 | }; 285 | CF1408CF629C7361332E53B88F7BD30C = { 286 | isa = PBXGroup; 287 | children = ( 288 | 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, 289 | B71A56962D1D833730406CE54F4BA361 /* Development Pods */, 290 | D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */, 291 | 39C728A0B16981F05BE8169A1F39B5D3 /* Products */, 292 | 1AD6B8CBA93399717387A53E588D33DC /* Targets Support Files */, 293 | ); 294 | sourceTree = ""; 295 | }; 296 | D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */ = { 297 | isa = PBXGroup; 298 | children = ( 299 | 578452D2E740E91742655AC8F1636D1F /* iOS */, 300 | ); 301 | name = Frameworks; 302 | sourceTree = ""; 303 | }; 304 | /* End PBXGroup section */ 305 | 306 | /* Begin PBXHeadersBuildPhase section */ 307 | 528565850A5C45F375C7BC12A34D5CCD /* Headers */ = { 308 | isa = PBXHeadersBuildPhase; 309 | buildActionMask = 2147483647; 310 | files = ( 311 | E0DFC527862CB314892BDE90B44F968E /* gdn_objc_msgSend.h in Headers */, 312 | 15EDBD0999672FDEC1BB71BC0E03808A /* gdn_objc_msgSend_time_profiler.h in Headers */, 313 | C32DB0CE4ADE182E4A2562632FADBEB6 /* GDNOCMethodTimeProfiler.h in Headers */, 314 | 2763B6215BFB46A0C2E8661623F6E1E0 /* GDNOCMethodTimeProfilerProtocol.h in Headers */, 315 | FD52B5DFFA75835BE2C69ABF945C5A18 /* GDNRecordDetailCell.h in Headers */, 316 | 4D00A45BDB95072BBD318C0614C95BFD /* GDNRecordDetailViewController.h in Headers */, 317 | B3F06B09B7E928DD3A5DD3DDFC271D94 /* GDNRecordHierarchyModel.h in Headers */, 318 | C751784FC17F1A1B9752BF3FCCA76957 /* GDNRecordModel.h in Headers */, 319 | 4FFB9A61546E3F804C57512D4307A559 /* GDNRecordRootViewController.h in Headers */, 320 | A2A97B55278D30D05160BFBECBCCE6FD /* GDNUIModel.h in Headers */, 321 | 152084562CAC1DEC53142EBA10738631 /* Guldan-umbrella.h in Headers */, 322 | F84AAE24ACDCB30AA3F36635B50F65D8 /* Guldan.h in Headers */, 323 | 8DD6EC8B016C15EA1384AFD18ACA9467 /* HLLFishhook.h in Headers */, 324 | BA78B2628119CA1DCD43483F88AAA5CB /* UIWindow+GDN.h in Headers */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | 69D2304CF179FB47C4A334A6B572BA5F /* Headers */ = { 329 | isa = PBXHeadersBuildPhase; 330 | buildActionMask = 2147483647; 331 | files = ( 332 | C8AFEDFD3867828DB1096067B9209675 /* Pods-Guldan_Tests-umbrella.h in Headers */, 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | A348525386CDB88BE7B3A44C5B00AE88 /* Headers */ = { 337 | isa = PBXHeadersBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | 693F11307E3B30ACFFC80C4C71BEF62D /* Pods-Guldan_Example-umbrella.h in Headers */, 341 | ); 342 | runOnlyForDeploymentPostprocessing = 0; 343 | }; 344 | /* End PBXHeadersBuildPhase section */ 345 | 346 | /* Begin PBXNativeTarget section */ 347 | 0DD5ED1A29984177DF7C725984A634F1 /* Guldan */ = { 348 | isa = PBXNativeTarget; 349 | buildConfigurationList = 502C0665BC4A58FEB5EDEF2E878A4D68 /* Build configuration list for PBXNativeTarget "Guldan" */; 350 | buildPhases = ( 351 | 528565850A5C45F375C7BC12A34D5CCD /* Headers */, 352 | C99CD1BFAD6015BBBAD910DF94196622 /* Sources */, 353 | 2757CE5769592622B7E7CD082F71B8F9 /* Frameworks */, 354 | 93B1DF18B53B46F62608E8DB5802E365 /* Resources */, 355 | ); 356 | buildRules = ( 357 | ); 358 | dependencies = ( 359 | ); 360 | name = Guldan; 361 | productName = Guldan; 362 | productReference = 8F698A7D41AFC5A47704B78BA5E09F81 /* Guldan.framework */; 363 | productType = "com.apple.product-type.framework"; 364 | }; 365 | 48110B7C835CDD1FBBB0B59037899D36 /* Pods-Guldan_Tests */ = { 366 | isa = PBXNativeTarget; 367 | buildConfigurationList = 9F5ED331F2C3059A2B6912113F7D73E7 /* Build configuration list for PBXNativeTarget "Pods-Guldan_Tests" */; 368 | buildPhases = ( 369 | 69D2304CF179FB47C4A334A6B572BA5F /* Headers */, 370 | 710E5971CE532745C9A345429651B550 /* Sources */, 371 | 130C247E52EC1F1139976C78B9360FF6 /* Frameworks */, 372 | 01E5E7C99124F5D77EB319BD0112F246 /* Resources */, 373 | ); 374 | buildRules = ( 375 | ); 376 | dependencies = ( 377 | 97524AD3B43E7852EC3685507D8CB43B /* PBXTargetDependency */, 378 | ); 379 | name = "Pods-Guldan_Tests"; 380 | productName = "Pods-Guldan_Tests"; 381 | productReference = 463FAC86701EADB05CECD15C87D857D2 /* Pods_Guldan_Tests.framework */; 382 | productType = "com.apple.product-type.framework"; 383 | }; 384 | B46A651FE22D8CC5CEC85CBCD2E74CEC /* Pods-Guldan_Example */ = { 385 | isa = PBXNativeTarget; 386 | buildConfigurationList = 9770BAC72DCD03015EC7EE461A54202F /* Build configuration list for PBXNativeTarget "Pods-Guldan_Example" */; 387 | buildPhases = ( 388 | A348525386CDB88BE7B3A44C5B00AE88 /* Headers */, 389 | DB7497B5296F5EF0C043780F66E7B430 /* Sources */, 390 | 531D66199678DF88C9058BE203AA8D14 /* Frameworks */, 391 | 03F8A08FBCCC618FDC19705C60EBBB81 /* Resources */, 392 | ); 393 | buildRules = ( 394 | ); 395 | dependencies = ( 396 | F4429326FB09D275A448C6BFA5BEBAE8 /* PBXTargetDependency */, 397 | ); 398 | name = "Pods-Guldan_Example"; 399 | productName = "Pods-Guldan_Example"; 400 | productReference = AEC7843ABF876424A238295D19C9F50A /* Pods_Guldan_Example.framework */; 401 | productType = "com.apple.product-type.framework"; 402 | }; 403 | /* End PBXNativeTarget section */ 404 | 405 | /* Begin PBXProject section */ 406 | BFDFE7DC352907FC980B868725387E98 /* Project object */ = { 407 | isa = PBXProject; 408 | attributes = { 409 | LastSwiftUpdateCheck = 1100; 410 | LastUpgradeCheck = 1100; 411 | }; 412 | buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; 413 | compatibilityVersion = "Xcode 3.2"; 414 | developmentRegion = en; 415 | hasScannedForEncodings = 0; 416 | knownRegions = ( 417 | en, 418 | Base, 419 | ); 420 | mainGroup = CF1408CF629C7361332E53B88F7BD30C; 421 | productRefGroup = 39C728A0B16981F05BE8169A1F39B5D3 /* Products */; 422 | projectDirPath = ""; 423 | projectRoot = ""; 424 | targets = ( 425 | 0DD5ED1A29984177DF7C725984A634F1 /* Guldan */, 426 | B46A651FE22D8CC5CEC85CBCD2E74CEC /* Pods-Guldan_Example */, 427 | 48110B7C835CDD1FBBB0B59037899D36 /* Pods-Guldan_Tests */, 428 | ); 429 | }; 430 | /* End PBXProject section */ 431 | 432 | /* Begin PBXResourcesBuildPhase section */ 433 | 01E5E7C99124F5D77EB319BD0112F246 /* Resources */ = { 434 | isa = PBXResourcesBuildPhase; 435 | buildActionMask = 2147483647; 436 | files = ( 437 | ); 438 | runOnlyForDeploymentPostprocessing = 0; 439 | }; 440 | 03F8A08FBCCC618FDC19705C60EBBB81 /* Resources */ = { 441 | isa = PBXResourcesBuildPhase; 442 | buildActionMask = 2147483647; 443 | files = ( 444 | ); 445 | runOnlyForDeploymentPostprocessing = 0; 446 | }; 447 | 93B1DF18B53B46F62608E8DB5802E365 /* Resources */ = { 448 | isa = PBXResourcesBuildPhase; 449 | buildActionMask = 2147483647; 450 | files = ( 451 | ); 452 | runOnlyForDeploymentPostprocessing = 0; 453 | }; 454 | /* End PBXResourcesBuildPhase section */ 455 | 456 | /* Begin PBXSourcesBuildPhase section */ 457 | 710E5971CE532745C9A345429651B550 /* Sources */ = { 458 | isa = PBXSourcesBuildPhase; 459 | buildActionMask = 2147483647; 460 | files = ( 461 | 214CCDBBC704B73852B35F1C981C4556 /* Pods-Guldan_Tests-dummy.m in Sources */, 462 | ); 463 | runOnlyForDeploymentPostprocessing = 0; 464 | }; 465 | C99CD1BFAD6015BBBAD910DF94196622 /* Sources */ = { 466 | isa = PBXSourcesBuildPhase; 467 | buildActionMask = 2147483647; 468 | files = ( 469 | DDEB6E04FD4BA6DB72F5D56A5EFFD623 /* gdn_objc_msgSend.s in Sources */, 470 | D8084212F32A47BD631A902F51F5A15E /* gdn_objc_msgSend_time_profiler.m in Sources */, 471 | 854584D123451F1AB3812AACBA6127AB /* GDNOCMethodTimeProfiler.m in Sources */, 472 | 6067957D881CFB72E62981024D898048 /* GDNRecordDetailCell.m in Sources */, 473 | DBE86477907A567CDCE3B062EB452E27 /* GDNRecordDetailViewController.m in Sources */, 474 | D22CE00D94627EE8C2BBAA7ED2DDF002 /* GDNRecordHierarchyModel.m in Sources */, 475 | CC0F9B3C8D7E8D1BE033192F38489722 /* GDNRecordModel.m in Sources */, 476 | F6E5444CA707345B665A8A39079CF2A4 /* GDNRecordRootViewController.m in Sources */, 477 | A83F652BF729BDA6E20FB8BB509D14DC /* GDNUIModel.m in Sources */, 478 | 7FFDE26D6D0C00305616DEA1270771DE /* Guldan-dummy.m in Sources */, 479 | D4E0B70E9DC6BC7B27E831A0E3320234 /* HLLFishhook.c in Sources */, 480 | 1AA7E929E90207056545A1F998C4A511 /* UIWindow+GDN.m in Sources */, 481 | ); 482 | runOnlyForDeploymentPostprocessing = 0; 483 | }; 484 | DB7497B5296F5EF0C043780F66E7B430 /* Sources */ = { 485 | isa = PBXSourcesBuildPhase; 486 | buildActionMask = 2147483647; 487 | files = ( 488 | 30C9917141E601D2D37A92925A905371 /* Pods-Guldan_Example-dummy.m in Sources */, 489 | ); 490 | runOnlyForDeploymentPostprocessing = 0; 491 | }; 492 | /* End PBXSourcesBuildPhase section */ 493 | 494 | /* Begin PBXTargetDependency section */ 495 | 97524AD3B43E7852EC3685507D8CB43B /* PBXTargetDependency */ = { 496 | isa = PBXTargetDependency; 497 | name = "Pods-Guldan_Example"; 498 | target = B46A651FE22D8CC5CEC85CBCD2E74CEC /* Pods-Guldan_Example */; 499 | targetProxy = 27B7B3A14F62C5D4DB70B88FD7ECE2E0 /* PBXContainerItemProxy */; 500 | }; 501 | F4429326FB09D275A448C6BFA5BEBAE8 /* PBXTargetDependency */ = { 502 | isa = PBXTargetDependency; 503 | name = Guldan; 504 | target = 0DD5ED1A29984177DF7C725984A634F1 /* Guldan */; 505 | targetProxy = 3E73BAA00345831EA3C278AEC35787DB /* PBXContainerItemProxy */; 506 | }; 507 | /* End PBXTargetDependency section */ 508 | 509 | /* Begin XCBuildConfiguration section */ 510 | 25AD9454612BF454A1E3DC4CD4FA8C6D /* Debug */ = { 511 | isa = XCBuildConfiguration; 512 | buildSettings = { 513 | ALWAYS_SEARCH_USER_PATHS = NO; 514 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 515 | CLANG_ANALYZER_NONNULL = YES; 516 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 517 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 518 | CLANG_CXX_LIBRARY = "libc++"; 519 | CLANG_ENABLE_MODULES = YES; 520 | CLANG_ENABLE_OBJC_ARC = YES; 521 | CLANG_ENABLE_OBJC_WEAK = YES; 522 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 523 | CLANG_WARN_BOOL_CONVERSION = YES; 524 | CLANG_WARN_COMMA = YES; 525 | CLANG_WARN_CONSTANT_CONVERSION = YES; 526 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 527 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 528 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 529 | CLANG_WARN_EMPTY_BODY = YES; 530 | CLANG_WARN_ENUM_CONVERSION = YES; 531 | CLANG_WARN_INFINITE_RECURSION = YES; 532 | CLANG_WARN_INT_CONVERSION = YES; 533 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 534 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 535 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 536 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 537 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 538 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 539 | CLANG_WARN_STRICT_PROTOTYPES = YES; 540 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 541 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 542 | CLANG_WARN_UNREACHABLE_CODE = YES; 543 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 544 | COPY_PHASE_STRIP = NO; 545 | DEBUG_INFORMATION_FORMAT = dwarf; 546 | ENABLE_STRICT_OBJC_MSGSEND = YES; 547 | ENABLE_TESTABILITY = YES; 548 | GCC_C_LANGUAGE_STANDARD = gnu11; 549 | GCC_DYNAMIC_NO_PIC = NO; 550 | GCC_NO_COMMON_BLOCKS = YES; 551 | GCC_OPTIMIZATION_LEVEL = 0; 552 | GCC_PREPROCESSOR_DEFINITIONS = ( 553 | "POD_CONFIGURATION_DEBUG=1", 554 | "DEBUG=1", 555 | "$(inherited)", 556 | ); 557 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 558 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 559 | GCC_WARN_UNDECLARED_SELECTOR = YES; 560 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 561 | GCC_WARN_UNUSED_FUNCTION = YES; 562 | GCC_WARN_UNUSED_VARIABLE = YES; 563 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 564 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 565 | MTL_FAST_MATH = YES; 566 | ONLY_ACTIVE_ARCH = YES; 567 | PRODUCT_NAME = "$(TARGET_NAME)"; 568 | STRIP_INSTALLED_PRODUCT = NO; 569 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 570 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 571 | SWIFT_VERSION = 5.0; 572 | SYMROOT = "${SRCROOT}/../build"; 573 | }; 574 | name = Debug; 575 | }; 576 | 83D8FFF9A5613DB8B19DFB312A888A6B /* Debug */ = { 577 | isa = XCBuildConfiguration; 578 | baseConfigurationReference = C8F3D160B3F88E704C4EDFDAD896F1AC /* Guldan.debug.xcconfig */; 579 | buildSettings = { 580 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 581 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 582 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 583 | CURRENT_PROJECT_VERSION = 1; 584 | DEFINES_MODULE = YES; 585 | DYLIB_COMPATIBILITY_VERSION = 1; 586 | DYLIB_CURRENT_VERSION = 1; 587 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 588 | GCC_PREFIX_HEADER = "Target Support Files/Guldan/Guldan-prefix.pch"; 589 | INFOPLIST_FILE = "Target Support Files/Guldan/Guldan-Info.plist"; 590 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 591 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 592 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 593 | MODULEMAP_FILE = "Target Support Files/Guldan/Guldan.modulemap"; 594 | PRODUCT_MODULE_NAME = Guldan; 595 | PRODUCT_NAME = Guldan; 596 | SDKROOT = iphoneos; 597 | SKIP_INSTALL = YES; 598 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; 599 | SWIFT_VERSION = 4.0; 600 | TARGETED_DEVICE_FAMILY = "1,2"; 601 | VERSIONING_SYSTEM = "apple-generic"; 602 | VERSION_INFO_PREFIX = ""; 603 | }; 604 | name = Debug; 605 | }; 606 | 8C4D54CF447212AD773C06735C82D274 /* Debug */ = { 607 | isa = XCBuildConfiguration; 608 | baseConfigurationReference = 344D2F429C1C9DDD07623B20717A9E22 /* Pods-Guldan_Tests.debug.xcconfig */; 609 | buildSettings = { 610 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 611 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 612 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 613 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 614 | CURRENT_PROJECT_VERSION = 1; 615 | DEFINES_MODULE = YES; 616 | DYLIB_COMPATIBILITY_VERSION = 1; 617 | DYLIB_CURRENT_VERSION = 1; 618 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 619 | INFOPLIST_FILE = "Target Support Files/Pods-Guldan_Tests/Pods-Guldan_Tests-Info.plist"; 620 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 621 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 622 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 623 | MACH_O_TYPE = staticlib; 624 | MODULEMAP_FILE = "Target Support Files/Pods-Guldan_Tests/Pods-Guldan_Tests.modulemap"; 625 | OTHER_LDFLAGS = ""; 626 | OTHER_LIBTOOLFLAGS = ""; 627 | PODS_ROOT = "$(SRCROOT)"; 628 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 629 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 630 | SDKROOT = iphoneos; 631 | SKIP_INSTALL = YES; 632 | TARGETED_DEVICE_FAMILY = "1,2"; 633 | VERSIONING_SYSTEM = "apple-generic"; 634 | VERSION_INFO_PREFIX = ""; 635 | }; 636 | name = Debug; 637 | }; 638 | A953593D97A219588D079AEC71E9D939 /* Release */ = { 639 | isa = XCBuildConfiguration; 640 | baseConfigurationReference = 8E0F236EE64AEED647D7BB2A62445D54 /* Pods-Guldan_Tests.release.xcconfig */; 641 | buildSettings = { 642 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 643 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 644 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 645 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 646 | CURRENT_PROJECT_VERSION = 1; 647 | DEFINES_MODULE = YES; 648 | DYLIB_COMPATIBILITY_VERSION = 1; 649 | DYLIB_CURRENT_VERSION = 1; 650 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 651 | INFOPLIST_FILE = "Target Support Files/Pods-Guldan_Tests/Pods-Guldan_Tests-Info.plist"; 652 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 653 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 654 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 655 | MACH_O_TYPE = staticlib; 656 | MODULEMAP_FILE = "Target Support Files/Pods-Guldan_Tests/Pods-Guldan_Tests.modulemap"; 657 | OTHER_LDFLAGS = ""; 658 | OTHER_LIBTOOLFLAGS = ""; 659 | PODS_ROOT = "$(SRCROOT)"; 660 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 661 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 662 | SDKROOT = iphoneos; 663 | SKIP_INSTALL = YES; 664 | TARGETED_DEVICE_FAMILY = "1,2"; 665 | VALIDATE_PRODUCT = YES; 666 | VERSIONING_SYSTEM = "apple-generic"; 667 | VERSION_INFO_PREFIX = ""; 668 | }; 669 | name = Release; 670 | }; 671 | C3C8BC435DEE9B532A2AF8A91E5D971C /* Debug */ = { 672 | isa = XCBuildConfiguration; 673 | baseConfigurationReference = 608B599BC6570A69C6DC67105F385883 /* Pods-Guldan_Example.debug.xcconfig */; 674 | buildSettings = { 675 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 676 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 677 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 678 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 679 | CURRENT_PROJECT_VERSION = 1; 680 | DEFINES_MODULE = YES; 681 | DYLIB_COMPATIBILITY_VERSION = 1; 682 | DYLIB_CURRENT_VERSION = 1; 683 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 684 | INFOPLIST_FILE = "Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example-Info.plist"; 685 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 686 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 687 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 688 | MACH_O_TYPE = staticlib; 689 | MODULEMAP_FILE = "Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example.modulemap"; 690 | OTHER_LDFLAGS = ""; 691 | OTHER_LIBTOOLFLAGS = ""; 692 | PODS_ROOT = "$(SRCROOT)"; 693 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 694 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 695 | SDKROOT = iphoneos; 696 | SKIP_INSTALL = YES; 697 | TARGETED_DEVICE_FAMILY = "1,2"; 698 | VERSIONING_SYSTEM = "apple-generic"; 699 | VERSION_INFO_PREFIX = ""; 700 | }; 701 | name = Debug; 702 | }; 703 | CA547D2C7E9A8A153DC2B27FBE00B112 /* Release */ = { 704 | isa = XCBuildConfiguration; 705 | buildSettings = { 706 | ALWAYS_SEARCH_USER_PATHS = NO; 707 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 708 | CLANG_ANALYZER_NONNULL = YES; 709 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 710 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 711 | CLANG_CXX_LIBRARY = "libc++"; 712 | CLANG_ENABLE_MODULES = YES; 713 | CLANG_ENABLE_OBJC_ARC = YES; 714 | CLANG_ENABLE_OBJC_WEAK = YES; 715 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 716 | CLANG_WARN_BOOL_CONVERSION = YES; 717 | CLANG_WARN_COMMA = YES; 718 | CLANG_WARN_CONSTANT_CONVERSION = YES; 719 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 720 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 721 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 722 | CLANG_WARN_EMPTY_BODY = YES; 723 | CLANG_WARN_ENUM_CONVERSION = YES; 724 | CLANG_WARN_INFINITE_RECURSION = YES; 725 | CLANG_WARN_INT_CONVERSION = YES; 726 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 727 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 728 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 729 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 730 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 731 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 732 | CLANG_WARN_STRICT_PROTOTYPES = YES; 733 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 734 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 735 | CLANG_WARN_UNREACHABLE_CODE = YES; 736 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 737 | COPY_PHASE_STRIP = NO; 738 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 739 | ENABLE_NS_ASSERTIONS = NO; 740 | ENABLE_STRICT_OBJC_MSGSEND = YES; 741 | GCC_C_LANGUAGE_STANDARD = gnu11; 742 | GCC_NO_COMMON_BLOCKS = YES; 743 | GCC_PREPROCESSOR_DEFINITIONS = ( 744 | "POD_CONFIGURATION_RELEASE=1", 745 | "$(inherited)", 746 | ); 747 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 748 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 749 | GCC_WARN_UNDECLARED_SELECTOR = YES; 750 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 751 | GCC_WARN_UNUSED_FUNCTION = YES; 752 | GCC_WARN_UNUSED_VARIABLE = YES; 753 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 754 | MTL_ENABLE_DEBUG_INFO = NO; 755 | MTL_FAST_MATH = YES; 756 | PRODUCT_NAME = "$(TARGET_NAME)"; 757 | STRIP_INSTALLED_PRODUCT = NO; 758 | SWIFT_COMPILATION_MODE = wholemodule; 759 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 760 | SWIFT_VERSION = 5.0; 761 | SYMROOT = "${SRCROOT}/../build"; 762 | }; 763 | name = Release; 764 | }; 765 | D0B62F01E58FF1DB0116146C73A8491A /* Release */ = { 766 | isa = XCBuildConfiguration; 767 | baseConfigurationReference = 7D52DA981ACEA9B1C5EFB8D8DE49E80F /* Guldan.release.xcconfig */; 768 | buildSettings = { 769 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 770 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 771 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 772 | CURRENT_PROJECT_VERSION = 1; 773 | DEFINES_MODULE = YES; 774 | DYLIB_COMPATIBILITY_VERSION = 1; 775 | DYLIB_CURRENT_VERSION = 1; 776 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 777 | GCC_PREFIX_HEADER = "Target Support Files/Guldan/Guldan-prefix.pch"; 778 | INFOPLIST_FILE = "Target Support Files/Guldan/Guldan-Info.plist"; 779 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 780 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 781 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 782 | MODULEMAP_FILE = "Target Support Files/Guldan/Guldan.modulemap"; 783 | PRODUCT_MODULE_NAME = Guldan; 784 | PRODUCT_NAME = Guldan; 785 | SDKROOT = iphoneos; 786 | SKIP_INSTALL = YES; 787 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; 788 | SWIFT_VERSION = 4.0; 789 | TARGETED_DEVICE_FAMILY = "1,2"; 790 | VALIDATE_PRODUCT = YES; 791 | VERSIONING_SYSTEM = "apple-generic"; 792 | VERSION_INFO_PREFIX = ""; 793 | }; 794 | name = Release; 795 | }; 796 | DD59172261DD227E6E35B87F78F6AA83 /* Release */ = { 797 | isa = XCBuildConfiguration; 798 | baseConfigurationReference = CD1CF3FE0E66C88D1222FE09689F04F6 /* Pods-Guldan_Example.release.xcconfig */; 799 | buildSettings = { 800 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; 801 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 802 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 803 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 804 | CURRENT_PROJECT_VERSION = 1; 805 | DEFINES_MODULE = YES; 806 | DYLIB_COMPATIBILITY_VERSION = 1; 807 | DYLIB_CURRENT_VERSION = 1; 808 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 809 | INFOPLIST_FILE = "Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example-Info.plist"; 810 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 811 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 812 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 813 | MACH_O_TYPE = staticlib; 814 | MODULEMAP_FILE = "Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example.modulemap"; 815 | OTHER_LDFLAGS = ""; 816 | OTHER_LIBTOOLFLAGS = ""; 817 | PODS_ROOT = "$(SRCROOT)"; 818 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 819 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 820 | SDKROOT = iphoneos; 821 | SKIP_INSTALL = YES; 822 | TARGETED_DEVICE_FAMILY = "1,2"; 823 | VALIDATE_PRODUCT = YES; 824 | VERSIONING_SYSTEM = "apple-generic"; 825 | VERSION_INFO_PREFIX = ""; 826 | }; 827 | name = Release; 828 | }; 829 | /* End XCBuildConfiguration section */ 830 | 831 | /* Begin XCConfigurationList section */ 832 | 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { 833 | isa = XCConfigurationList; 834 | buildConfigurations = ( 835 | 25AD9454612BF454A1E3DC4CD4FA8C6D /* Debug */, 836 | CA547D2C7E9A8A153DC2B27FBE00B112 /* Release */, 837 | ); 838 | defaultConfigurationIsVisible = 0; 839 | defaultConfigurationName = Release; 840 | }; 841 | 502C0665BC4A58FEB5EDEF2E878A4D68 /* Build configuration list for PBXNativeTarget "Guldan" */ = { 842 | isa = XCConfigurationList; 843 | buildConfigurations = ( 844 | 83D8FFF9A5613DB8B19DFB312A888A6B /* Debug */, 845 | D0B62F01E58FF1DB0116146C73A8491A /* Release */, 846 | ); 847 | defaultConfigurationIsVisible = 0; 848 | defaultConfigurationName = Release; 849 | }; 850 | 9770BAC72DCD03015EC7EE461A54202F /* Build configuration list for PBXNativeTarget "Pods-Guldan_Example" */ = { 851 | isa = XCConfigurationList; 852 | buildConfigurations = ( 853 | C3C8BC435DEE9B532A2AF8A91E5D971C /* Debug */, 854 | DD59172261DD227E6E35B87F78F6AA83 /* Release */, 855 | ); 856 | defaultConfigurationIsVisible = 0; 857 | defaultConfigurationName = Release; 858 | }; 859 | 9F5ED331F2C3059A2B6912113F7D73E7 /* Build configuration list for PBXNativeTarget "Pods-Guldan_Tests" */ = { 860 | isa = XCConfigurationList; 861 | buildConfigurations = ( 862 | 8C4D54CF447212AD773C06735C82D274 /* Debug */, 863 | A953593D97A219588D079AEC71E9D939 /* Release */, 864 | ); 865 | defaultConfigurationIsVisible = 0; 866 | defaultConfigurationName = Release; 867 | }; 868 | /* End XCConfigurationList section */ 869 | }; 870 | rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; 871 | } 872 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Guldan/Guldan-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 | 0.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Guldan/Guldan-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Guldan : NSObject 3 | @end 4 | @implementation PodsDummy_Guldan 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Guldan/Guldan-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/Guldan/Guldan-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 | #import "GDNOCMethodTimeProfiler.h" 14 | #import "GDNOCMethodTimeProfilerProtocol.h" 15 | #import "gdn_objc_msgSend.h" 16 | #import "gdn_objc_msgSend_time_profiler.h" 17 | #import "Guldan.h" 18 | #import "HLLFishhook.h" 19 | #import "GDNRecordDetailCell.h" 20 | #import "GDNRecordDetailViewController.h" 21 | #import "GDNRecordHierarchyModel.h" 22 | #import "GDNRecordModel.h" 23 | #import "GDNRecordRootViewController.h" 24 | #import "GDNUIModel.h" 25 | #import "UIWindow+GDN.h" 26 | 27 | FOUNDATION_EXPORT double GuldanVersionNumber; 28 | FOUNDATION_EXPORT const unsigned char GuldanVersionString[]; 29 | 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Guldan/Guldan.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Guldan 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 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/Guldan/Guldan.modulemap: -------------------------------------------------------------------------------- 1 | framework module Guldan { 2 | umbrella header "Guldan-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Guldan/Guldan.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Guldan 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 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/Pods-Guldan_Example/Pods-Guldan_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-Guldan_Example/Pods-Guldan_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Guldan 5 | 6 | Copyright (c) 2021 Alex023 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Example/Pods-Guldan_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 | Copyright (c) 2021 Alex023 <alex023.wu@huolala.cn> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | Guldan 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_Guldan_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_Guldan_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Example/Pods-Guldan_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 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" 117 | fi 118 | fi 119 | } 120 | 121 | # Used as a return value for each invocation of `strip_invalid_archs` function. 122 | STRIP_BINARY_RETVAL=0 123 | 124 | # Strip invalid architectures 125 | strip_invalid_archs() { 126 | binary="$1" 127 | warn_missing_arch=${2:-true} 128 | # Get architectures for current target binary 129 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 130 | # Intersect them with the architectures we are building for 131 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 132 | # If there are no archs supported by this binary then warn the user 133 | if [[ -z "$intersected_archs" ]]; then 134 | if [[ "$warn_missing_arch" == "true" ]]; then 135 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 136 | fi 137 | STRIP_BINARY_RETVAL=1 138 | return 139 | fi 140 | stripped="" 141 | for arch in $binary_archs; do 142 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 143 | # Strip non-valid architectures in-place 144 | lipo -remove "$arch" -output "$binary" "$binary" 145 | stripped="$stripped $arch" 146 | fi 147 | done 148 | if [[ "$stripped" ]]; then 149 | echo "Stripped $binary of architectures:$stripped" 150 | fi 151 | STRIP_BINARY_RETVAL=0 152 | } 153 | 154 | # Copies the bcsymbolmap files of a vendored framework 155 | install_bcsymbolmap() { 156 | local bcsymbolmap_path="$1" 157 | local destination="${BUILT_PRODUCTS_DIR}" 158 | 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}"" 159 | 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 | } 161 | 162 | # Signs a framework with the provided identity 163 | code_sign_if_enabled() { 164 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 165 | # Use the current code_sign_identity 166 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 167 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 168 | 169 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 170 | code_sign_cmd="$code_sign_cmd &" 171 | fi 172 | echo "$code_sign_cmd" 173 | eval "$code_sign_cmd" 174 | fi 175 | } 176 | 177 | if [[ "$CONFIGURATION" == "Debug" ]]; then 178 | install_framework "${BUILT_PRODUCTS_DIR}/Guldan/Guldan.framework" 179 | fi 180 | if [[ "$CONFIGURATION" == "Release" ]]; then 181 | install_framework "${BUILT_PRODUCTS_DIR}/Guldan/Guldan.framework" 182 | fi 183 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 184 | wait 185 | fi 186 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Example/Pods-Guldan_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_Guldan_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_Guldan_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Guldan" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Guldan/Guldan.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "Guldan" 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 10 | PODS_ROOT = ${SRCROOT}/Pods 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_Guldan_Example { 2 | umbrella header "Pods-Guldan_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Example/Pods-Guldan_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Guldan" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Guldan/Guldan.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "Guldan" 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 10 | PODS_ROOT = ${SRCROOT}/Pods 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Tests/Pods-Guldan_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-Guldan_Tests/Pods-Guldan_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-Guldan_Tests/Pods-Guldan_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-Guldan_Tests/Pods-Guldan_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_Guldan_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_Guldan_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Tests/Pods-Guldan_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_Guldan_TestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_Guldan_TestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Tests/Pods-Guldan_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Guldan" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Guldan/Guldan.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "Guldan" 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-Guldan_Tests/Pods-Guldan_Tests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_Guldan_Tests { 2 | umbrella header "Pods-Guldan_Tests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-Guldan_Tests/Pods-Guldan_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Guldan" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Guldan/Guldan.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "Guldan" 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/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 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // GuldanTests.m 3 | // GuldanTests 4 | // 5 | // Created by Alex023 on 11/11/2021. 6 | // Copyright (c) 2021 Alex023. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Guldan.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint Guldan.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'Guldan' 11 | s.version = '0.1.0' 12 | s.summary = 'OC Method Time Cost Tool' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = 'HUOLALA OC Method Cost Time Profiler' 21 | 22 | s.homepage = 'https://xxx.com' 23 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 24 | s.license = { :type => 'MIT', :file => 'LICENSE' } 25 | s.author = { '货拉拉' => '货拉拉' } 26 | s.source = { :git => '', :tag => s.version.to_s } 27 | # s.social_media_url = 'https://twitter.com/' 28 | 29 | s.ios.deployment_target = '9.0' 30 | 31 | s.source_files = 'Guldan/Classes/**/*' 32 | end 33 | -------------------------------------------------------------------------------- /Guldan/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuolalaTech/hll-wp-guldan-ios/0e0b539a62288b7397b2652217ccb11b33952959/Guldan/Assets/.gitkeep -------------------------------------------------------------------------------- /Guldan/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuolalaTech/hll-wp-guldan-ios/0e0b539a62288b7397b2652217ccb11b33952959/Guldan/Classes/.gitkeep -------------------------------------------------------------------------------- /Guldan/Classes/GDNOCMethodTimeProfiler.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDNOCMethodTimeProfiler.h 3 | // Pods 4 | // 5 | // Created by Alex023 on 2021/11/15. 6 | // 7 | 8 | #import 9 | #import "GDNOCMethodTimeProfilerProtocol.h" 10 | @class GDNUIModel; 11 | 12 | FOUNDATION_EXPORT NSNotificationName _Nonnull const GDNRecordsDataDidReadyNotification; 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | @interface GDNOCMethodTimeProfiler : NSObject 17 | 18 | /// 启动 19 | + (void)start; 20 | 21 | /// 结束 22 | + (void)stop; 23 | 24 | + (NSMutableArray *)modelsArr; 25 | + (void)handleRecordsWithComplete:(void (^)(NSArray *filePaths))onComplete; 26 | 27 | @end 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /Guldan/Classes/GDNOCMethodTimeProfiler.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDNOCMethodTimeProfiler.m 3 | // Pods 4 | // 5 | // Created by Alex023 on 2021/11/15. 6 | // 7 | 8 | #import "GDNOCMethodTimeProfiler.h" 9 | #import "gdn_objc_msgSend_time_profiler.h" 10 | #import "GDNUIModel.h" 11 | #import "GDNRecordHierarchyModel.h" 12 | 13 | NSNotificationName const GDNRecordsDataDidReadyNotification = @"gdn.records.data.did.ready"; 14 | 15 | @interface GDNOCMethodTimeProfiler () 16 | @property (nonatomic, strong)NSMutableArray *modelArr; 17 | @end 18 | 19 | @implementation GDNOCMethodTimeProfiler 20 | 21 | + (instancetype)defaultProfiler { 22 | static dispatch_once_t onceToken; 23 | static id sharedInstance; 24 | dispatch_once(&onceToken, ^{ 25 | sharedInstance = [[self alloc] init]; 26 | }); 27 | return sharedInstance; 28 | } 29 | 30 | + (void)start { 31 | [[GDNOCMethodTimeProfiler defaultProfiler] startProfiler]; 32 | } 33 | 34 | + (void)stop { 35 | [[GDNOCMethodTimeProfiler defaultProfiler] stopProfiler]; 36 | } 37 | 38 | + (NSMutableArray *)modelsArr { 39 | return [GDNOCMethodTimeProfiler defaultProfiler].modelArr; 40 | } 41 | 42 | + (void)handleRecordsWithComplete:(void (^)(NSArray *filePaths))onComplete { 43 | [[GDNOCMethodTimeProfiler defaultProfiler] handleRecordsWithComplete:onComplete]; 44 | } 45 | 46 | #pragma mark - Private 47 | 48 | - (void)startProfiler { 49 | #if defined(__arm64__) 50 | static dispatch_once_t onceToken; 51 | dispatch_once(&onceToken, ^{ 52 | gdn_timeProfilerPreprocess(); 53 | }); 54 | gdn_timeProfilerStart(YES, YES); 55 | #endif 56 | } 57 | 58 | - (void)stopProfiler { 59 | #if defined(__arm64__) 60 | gdn_timeProfilerStop(); 61 | #endif 62 | } 63 | 64 | - (void)handleRecordsWithComplete:(void (^)(NSArray *filePaths))onComplete { 65 | #if defined(__arm64__) 66 | if (!onComplete) { 67 | return; 68 | } 69 | gdn_handleRecordsWithComplete(^(NSArray *filePaths1) { 70 | onComplete(filePaths1); 71 | }, ^(NSArray *allMethodRecords) { 72 | GDNUIModel *model = [[GDNUIModel alloc] init]; 73 | NSArray *records = [[NSArray alloc] initWithArray:allMethodRecords copyItems:YES]; 74 | model.sequentialMethodRecord = records; 75 | model.costTimeSortMethodRecord = [self sortRecordByCostTime:records]; 76 | model.callCountSortMethodRecord = [self sortRecordByCallCount:records]; 77 | 78 | dispatch_async(dispatch_get_main_queue(), ^{ 79 | [self.modelArr addObject:model]; 80 | [[NSNotificationCenter defaultCenter] postNotificationName:GDNRecordsDataDidReadyNotification object:nil]; 81 | }); 82 | }); 83 | #endif 84 | } 85 | 86 | - (NSArray *)sortRecordByCostTime:(NSArray *)arr { 87 | NSArray *sortArr = [arr sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { 88 | GDNRecordHierarchyModel *model1 = (GDNRecordHierarchyModel *)obj1; 89 | GDNRecordHierarchyModel *model2 = (GDNRecordHierarchyModel *)obj2; 90 | if (model1.rootMethod.costTime > model2.rootMethod.costTime) { 91 | return NSOrderedAscending; 92 | } 93 | return NSOrderedDescending; 94 | }]; 95 | for (GDNRecordHierarchyModel *model in sortArr) { 96 | model.isExpand = NO; 97 | } 98 | return sortArr; 99 | } 100 | 101 | 102 | - (NSArray *)sortRecordByCallCount:(NSArray *)arr { 103 | NSMutableArray *arrM = [NSMutableArray array]; 104 | for (GDNRecordHierarchyModel *model in arr) { 105 | [self addRecord:model.rootMethod to:arrM]; 106 | if ([model.subMethods isKindOfClass:NSArray.class]) { 107 | for (GDNRecordModel *recoreModel in model.subMethods) { 108 | [self addRecord:recoreModel to:arrM]; 109 | } 110 | } 111 | } 112 | 113 | NSArray *sortArr = [arrM sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { 114 | GDNRecordModel *model1 = (GDNRecordModel *)obj1; 115 | GDNRecordModel *model2 = (GDNRecordModel *)obj2; 116 | if (model1.callCount > model2.callCount) { 117 | return NSOrderedAscending; 118 | } 119 | return NSOrderedDescending; 120 | }]; 121 | return sortArr; 122 | } 123 | 124 | - (void)addRecord:(GDNRecordModel *)model to:(NSMutableArray *)arr { 125 | for (int i = 0; i < arr.count; i++) { 126 | GDNRecordModel *temp = arr[i]; 127 | if ([temp isEqualRecordModel:model]) { 128 | temp.callCount++; 129 | return; 130 | } 131 | } 132 | model.callCount = 1; 133 | [arr addObject:model]; 134 | } 135 | 136 | - (NSMutableArray *)modelArr { 137 | if (!_modelArr) { 138 | _modelArr = [NSMutableArray array]; 139 | } 140 | return _modelArr; 141 | } 142 | 143 | @end 144 | -------------------------------------------------------------------------------- /Guldan/Classes/GDNOCMethodTimeProfilerProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDNOCMethodTimeProfilerProtocol.h 3 | // Pods 4 | // 5 | // Created by Alex023 on 2021/11/15. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol GDNOCMethodTimeProfilerProtocol 13 | 14 | @required 15 | 16 | - (void)startProfiler; 17 | 18 | - (void)stopProfiler; 19 | 20 | - (void)handleRecordsWithComplete:(void (^)(NSArray *filePaths))onComplete; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /Guldan/Classes/Guldan.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guldan.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2021/11/11. 6 | // 7 | 8 | #ifndef Guldan_h 9 | #define Guldan_h 10 | 11 | 12 | #endif /* Guldan_h */ 13 | -------------------------------------------------------------------------------- /Guldan/Classes/HLLFishhook.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #include "HLLFishhook.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #ifdef __LP64__ 40 | typedef struct mach_header_64 mach_header_t; 41 | typedef struct segment_command_64 segment_command_t; 42 | typedef struct section_64 section_t; 43 | typedef struct nlist_64 nlist_t; 44 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 45 | #else 46 | typedef struct mach_header mach_header_t; 47 | typedef struct segment_command segment_command_t; 48 | typedef struct section section_t; 49 | typedef struct nlist nlist_t; 50 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT 51 | #endif 52 | 53 | #ifndef SEG_DATA_CONST 54 | #define SEG_DATA_CONST "__DATA_CONST" 55 | #endif 56 | 57 | #ifndef SEG_AUTH_CONST 58 | #define SEG_AUTH_CONST "__AUTH_CONST" 59 | #endif 60 | 61 | struct rebindings_entry { 62 | struct rebinding *rebindings; 63 | size_t rebindings_nel; 64 | struct rebindings_entry *next; 65 | }; 66 | 67 | static struct rebindings_entry *_rebindings_head; 68 | 69 | static int prepend_rebindings(struct rebindings_entry **rebindings_head, 70 | struct rebinding rebindings[], 71 | size_t nel) { 72 | struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); 73 | if (!new_entry) { 74 | return -1; 75 | } 76 | new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); 77 | if (!new_entry->rebindings) { 78 | free(new_entry); 79 | return -1; 80 | } 81 | memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); 82 | new_entry->rebindings_nel = nel; 83 | new_entry->next = *rebindings_head; 84 | *rebindings_head = new_entry; 85 | return 0; 86 | } 87 | 88 | static vm_prot_t get_protection(void *sectionStart) { 89 | mach_port_t task = mach_task_self(); 90 | vm_size_t size = 0; 91 | vm_address_t address = (vm_address_t)sectionStart; 92 | memory_object_name_t object; 93 | #if __LP64__ 94 | mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; 95 | vm_region_basic_info_data_64_t info; 96 | kern_return_t info_ret = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object); 97 | #else 98 | mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT; 99 | vm_region_basic_info_data_t info; 100 | kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object); 101 | #endif 102 | if (info_ret == KERN_SUCCESS) { 103 | return info.protection; 104 | } else { 105 | return VM_PROT_READ; 106 | } 107 | } 108 | 109 | static void perform_rebinding_with_section(struct rebindings_entry *rebindings, 110 | section_t *section, 111 | intptr_t slide, 112 | nlist_t *symtab, 113 | char *strtab, 114 | uint32_t *indirect_symtab) { 115 | uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; 116 | void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); 117 | for (uint i = 0; i < section->size / sizeof(void *); i++) { 118 | uint32_t symtab_index = indirect_symbol_indices[i]; 119 | if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || 120 | symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { 121 | continue; 122 | } 123 | uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; 124 | char *symbol_name = strtab + strtab_offset; 125 | bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; 126 | struct rebindings_entry *cur = rebindings; 127 | while (cur) { 128 | for (uint j = 0; j < cur->rebindings_nel; j++) { 129 | if (symbol_name_longer_than_1 && 130 | strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { 131 | if (cur->rebindings[j].replaced != NULL && 132 | indirect_symbol_bindings[i] != cur->rebindings[j].replacement) { 133 | *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; 134 | } 135 | // 写入时判断内存地址是否可写 136 | bool is_prot_changed = false; 137 | void **address_to_write = indirect_symbol_bindings + i; 138 | vm_prot_t prot = get_protection(address_to_write); 139 | if ((prot & VM_PROT_WRITE) == 0) { 140 | is_prot_changed = true; 141 | kern_return_t success = vm_protect(mach_task_self(), (vm_address_t)address_to_write, sizeof(void *), false, prot | VM_PROT_WRITE); 142 | if (success != KERN_SUCCESS) { 143 | // 添加写权限失败, 不进行 hook 144 | goto symbol_loop; 145 | } 146 | } 147 | indirect_symbol_bindings[i] = cur->rebindings[j].replacement; 148 | // 恢复内存权限 149 | if (is_prot_changed) { 150 | vm_protect(mach_task_self(), (vm_address_t)address_to_write, sizeof(void *), false, prot); 151 | } 152 | goto symbol_loop; 153 | } 154 | } 155 | cur = cur->next; 156 | } 157 | symbol_loop:; 158 | } 159 | } 160 | 161 | // Address Sanitizer 等工具的动态库中会使用 dyld interposing 方式 hook, 如果 fishhok hook 这些库会导致循环调用 162 | #if DEBUG || TEST 163 | #ifndef SEC_INTERPOSE 164 | #define SEC_INTERPOSE "__interpose" 165 | #endif 166 | static bool has_interpose(const struct mach_header *header) { 167 | segment_command_t *cur_seg_cmd; 168 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); 169 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 170 | cur_seg_cmd = (segment_command_t *)cur; 171 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 172 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) { 173 | section_t *sect = (section_t *)(cur + sizeof(segment_command_t)) + j; 174 | if (strcmp(sect->sectname, SEC_INTERPOSE) == 0) { 175 | return true; 176 | } 177 | } 178 | } 179 | } 180 | return false; 181 | } 182 | #endif 183 | 184 | static void rebind_symbols_for_image(struct rebindings_entry *rebindings, 185 | const struct mach_header *header, 186 | intptr_t slide) { 187 | Dl_info info; 188 | if (dladdr(header, &info) == 0) { 189 | return; 190 | } 191 | 192 | #if DEBUG || TEST 193 | if (has_interpose(header)) { 194 | return; 195 | } 196 | #endif 197 | 198 | segment_command_t *cur_seg_cmd; 199 | segment_command_t *linkedit_segment = NULL; 200 | struct symtab_command* symtab_cmd = NULL; 201 | struct dysymtab_command* dysymtab_cmd = NULL; 202 | 203 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); 204 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 205 | cur_seg_cmd = (segment_command_t *)cur; 206 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 207 | if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { 208 | linkedit_segment = cur_seg_cmd; 209 | } 210 | } else if (cur_seg_cmd->cmd == LC_SYMTAB) { 211 | symtab_cmd = (struct symtab_command*)cur_seg_cmd; 212 | } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { 213 | dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; 214 | } 215 | } 216 | 217 | if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || 218 | !dysymtab_cmd->nindirectsyms) { 219 | return; 220 | } 221 | 222 | // Find base symbol/string table addresses 223 | uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; 224 | nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); 225 | char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); 226 | 227 | // Get indirect symbol table (array of uint32_t indices into symbol table) 228 | uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); 229 | 230 | cur = (uintptr_t)header + sizeof(mach_header_t); 231 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 232 | cur_seg_cmd = (segment_command_t *)cur; 233 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 234 | if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && 235 | strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0 && 236 | strcmp(cur_seg_cmd->segname, SEG_AUTH_CONST) != 0) { 237 | continue; 238 | } 239 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) { 240 | section_t *sect = 241 | (section_t *)(cur + sizeof(segment_command_t)) + j; 242 | if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { 243 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 244 | } 245 | if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { 246 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 247 | } 248 | } 249 | } 250 | } 251 | } 252 | 253 | static void _rebind_symbols_for_image(const struct mach_header *header, 254 | intptr_t slide) { 255 | rebind_symbols_for_image(_rebindings_head, header, slide); 256 | } 257 | 258 | int rebind_symbols_image(void *header, 259 | intptr_t slide, 260 | struct rebinding rebindings[], 261 | size_t rebindings_nel) { 262 | struct rebindings_entry *rebindings_head = NULL; 263 | int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); 264 | rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); 265 | if (rebindings_head) { 266 | free(rebindings_head->rebindings); 267 | } 268 | free(rebindings_head); 269 | return retval; 270 | } 271 | 272 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { 273 | int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); 274 | if (retval < 0) { 275 | return retval; 276 | } 277 | // If this was the first call, register callback for image additions (which is also invoked for 278 | // existing images, otherwise, just run on existing images 279 | if (!_rebindings_head->next) { 280 | _dyld_register_func_for_add_image(_rebind_symbols_for_image); 281 | } else { 282 | uint32_t c = _dyld_image_count(); 283 | for (uint32_t i = 0; i < c; i++) { 284 | _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); 285 | } 286 | } 287 | return retval; 288 | } 289 | -------------------------------------------------------------------------------- /Guldan/Classes/HLLFishhook.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #ifndef HLLFishhook_h 25 | #define HLLFishhook_h 26 | 27 | #include 28 | #include 29 | 30 | #if !defined(FISHHOOK_EXPORT) 31 | #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) 32 | #else 33 | #define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif //__cplusplus 39 | 40 | /* 41 | * A structure representing a particular intended rebinding from a symbol 42 | * name to its replacement 43 | */ 44 | struct rebinding { 45 | const char *name; 46 | void *replacement; 47 | void **replaced; 48 | }; 49 | 50 | /* 51 | * For each rebinding in rebindings, rebinds references to external, indirect 52 | * symbols with the specified name to instead point at replacement for each 53 | * image in the calling process as well as for all future images that are loaded 54 | * by the process. If rebind_functions is called more than once, the symbols to 55 | * rebind are added to the existing list of rebindings, and if a given symbol 56 | * is rebound more than once, the later rebinding will take precedence. 57 | */ 58 | //FISHHOOK_VISIBILITY 这里手动注释,否则在没有定义FISHHOOK_EXPORT时隐藏该接口,导致符号找不到 59 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); 60 | 61 | /* 62 | * Rebinds as above, but only in the specified image. The header should point 63 | * to the mach-o header, the slide should be the slide offset. Others as above. 64 | */ 65 | //FISHHOOK_VISIBILITY 这里手动注释,否则在没有定义FISHHOOK_EXPORT时隐藏该接口,导致符号找不到 66 | int rebind_symbols_image(void *header, 67 | intptr_t slide, 68 | struct rebinding rebindings[], 69 | size_t rebindings_nel); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif //__cplusplus 74 | 75 | #endif /* HLLFishhook_h */ 76 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordDetailCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordDetailCell.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import 9 | @class GDNRecordDetailCell; 10 | @class GDNRecordModel; 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol GDNRecordDetailCellDelegate 15 | 16 | - (void)recordCell:(GDNRecordDetailCell *)cell clickExpandWithSection:(NSInteger)section; 17 | 18 | @end 19 | 20 | @interface GDNRecordDetailCell : UITableViewCell 21 | 22 | @property (nonatomic, weak) id delegate; 23 | 24 | - (void)bindRecordModel:(GDNRecordModel *)model 25 | isHiddenExpandBtn:(BOOL)isHidden 26 | isExpand:(BOOL)isExpand 27 | section:(NSInteger)section 28 | isCallCountType:(BOOL)isCallCountType; 29 | @end 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordDetailCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordDetailCell.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import "GDNRecordDetailCell.h" 9 | #import "GDNRecordModel.h" 10 | #include 11 | 12 | #define kDepthLabelWidth 30 13 | #define kTimeLabelWidth 70 14 | #define kMethodLabelWidth 500 15 | 16 | @interface GDNRecordDetailCell () 17 | { 18 | NSInteger _section; 19 | } 20 | 21 | @property (nonatomic, strong)UILabel *depthLabel; 22 | @property (nonatomic, strong)UILabel *timeLabel; 23 | @property (nonatomic, strong)UILabel *methodLabel; 24 | @property (nonatomic, strong)UIButton *expandBtn; 25 | @property (nonatomic, strong)UILabel *callCountLabel; 26 | @end 27 | 28 | @implementation GDNRecordDetailCell 29 | 30 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 31 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 32 | self.selectionStyle = UITableViewCellSelectionStyleNone; 33 | [self.contentView addSubview:self.depthLabel]; 34 | [self.contentView addSubview:[self LineView:CGRectMake(kDepthLabelWidth + 2, 0, 2, 18)]]; 35 | [self.contentView addSubview:self.timeLabel]; 36 | [self.contentView addSubview:[self LineView:CGRectMake(CGRectGetMaxX(self.timeLabel.frame) + 2, 0, 2, 18)]]; 37 | [self.contentView addSubview:self.expandBtn]; 38 | [self.contentView addSubview:self.callCountLabel]; 39 | [self.contentView addSubview:[self LineView:CGRectMake(CGRectGetMaxX(self.callCountLabel.frame) + 2, 0, 2, 18)]]; 40 | [self.contentView addSubview:self.methodLabel]; 41 | } 42 | return self; 43 | } 44 | 45 | - (UIView *)LineView:(CGRect)rect { 46 | UIView *line = [[UIView alloc] initWithFrame:rect]; 47 | line.backgroundColor = [UIColor grayColor]; 48 | return line; 49 | } 50 | 51 | - (void)bindRecordModel:(GDNRecordModel *)model isHiddenExpandBtn:(BOOL)isHidden isExpand:(BOOL)isExpand section:(NSInteger)section isCallCountType:(BOOL)isCallCountType { 52 | _section = section; 53 | self.expandBtn.hidden = isHidden; 54 | if (!self.expandBtn.hidden) { 55 | self.expandBtn.selected = isExpand; 56 | } 57 | self.depthLabel.text = [NSString stringWithFormat:@"%d", model.depth]; 58 | self.timeLabel.text = [NSString stringWithFormat:@"%lgms", model.costTime/1000.0]; 59 | self.callCountLabel.hidden = !isCallCountType; 60 | if (isCallCountType) { 61 | self.callCountLabel.text = [NSString stringWithFormat:@"%d", model.callCount]; 62 | } 63 | 64 | NSMutableString *methodStr = [NSMutableString string]; 65 | if (model.depth>0 && !isCallCountType) { 66 | [methodStr appendString:[[NSString string] stringByPaddingToLength:model.depth withString:@"  " startingAtIndex:0]]; 67 | } 68 | if (class_isMetaClass(model.cls)) { 69 | [methodStr appendString:@"+"]; 70 | } 71 | else 72 | { 73 | [methodStr appendString:@"-"]; 74 | } 75 | [methodStr appendString:[NSString stringWithFormat:@"[%@ %@]", NSStringFromClass(model.cls), NSStringFromSelector(model.sel)]]; 76 | 77 | self.methodLabel.text = methodStr; 78 | } 79 | 80 | - (void)clickExpandBtn:(UIButton *)btn { 81 | if ([self.delegate respondsToSelector:@selector(recordCell:clickExpandWithSection:)]) { 82 | [self.delegate recordCell:self clickExpandWithSection:_section]; 83 | } 84 | } 85 | 86 | #pragma mark - get method 87 | 88 | - (UILabel *)depthLabel { 89 | if (!_depthLabel) { 90 | _depthLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, kDepthLabelWidth, 18)]; 91 | _depthLabel.textAlignment = NSTextAlignmentCenter; 92 | _depthLabel.font = [UIFont systemFontOfSize:12]; 93 | } 94 | return _depthLabel; 95 | } 96 | 97 | - (UILabel *)timeLabel { 98 | if (!_timeLabel) { 99 | 100 | _timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(kDepthLabelWidth + 6, 0, kTimeLabelWidth, 18)]; 101 | _timeLabel.textAlignment = NSTextAlignmentRight; 102 | _timeLabel.font = [UIFont systemFontOfSize:12]; 103 | } 104 | return _timeLabel; 105 | } 106 | 107 | - (UILabel *)methodLabel { 108 | if (!_methodLabel) { 109 | _methodLabel = [[UILabel alloc] initWithFrame:CGRectMake(kDepthLabelWidth+kTimeLabelWidth + 18 + 26, 0, kMethodLabelWidth, 18)]; 110 | _methodLabel.font = [UIFont systemFontOfSize:12]; 111 | } 112 | return _methodLabel; 113 | } 114 | 115 | - (UIButton *)expandBtn { 116 | if (!_expandBtn) { 117 | _expandBtn = [[UIButton alloc] initWithFrame:CGRectMake(kDepthLabelWidth+kTimeLabelWidth + 16, 0, 18, 18)]; 118 | [_expandBtn setBackgroundImage:[UIImage imageNamed:@"TPNOExpandIcon"] forState:UIControlStateNormal]; 119 | [_expandBtn setBackgroundImage:[UIImage imageNamed:@"TPExpandIcon"] forState:UIControlStateSelected]; 120 | [_expandBtn addTarget:self action:@selector(clickExpandBtn:) forControlEvents:UIControlEventTouchUpInside]; 121 | _expandBtn.hidden = YES; 122 | } 123 | return _expandBtn; 124 | } 125 | 126 | - (UILabel *)callCountLabel { 127 | if (!_callCountLabel) { 128 | _callCountLabel = [[UILabel alloc] initWithFrame:CGRectMake(kDepthLabelWidth+kTimeLabelWidth + 12, 0, 26, 18)]; 129 | _callCountLabel.textAlignment = NSTextAlignmentCenter; 130 | _callCountLabel.font = [UIFont systemFontOfSize:12]; 131 | _callCountLabel.hidden = YES; 132 | } 133 | return _callCountLabel; 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordDetailViewController.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import 9 | @class GDNUIModel; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface GDNRecordDetailViewController : UIViewController 14 | - (instancetype)initWithModel:(GDNUIModel *)model; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordDetailViewController.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import "GDNRecordDetailViewController.h" 9 | #import "GDNRecordDetailCell.h" 10 | #import "GDNRecordHierarchyModel.h" 11 | #import "GDNUIModel.h" 12 | 13 | typedef NS_ENUM(NSInteger, TPTableType) { 14 | tableTypeSequential, 15 | tableTypecostTime, 16 | tableTypeCallCount, 17 | }; 18 | 19 | static CGFloat GDNScrollWidth = 600; 20 | static CGFloat GDNHeaderHight = 140; 21 | 22 | @interface GDNRecordDetailViewController () 23 | 24 | @property (nonatomic, strong) UIButton *RecordBtn; 25 | @property (nonatomic, strong) UIButton *costTimeSortBtn; 26 | @property (nonatomic, strong) UIButton *callCountSortBtn; 27 | @property (nonatomic, strong) UIButton *popVCBtn; 28 | @property (nonatomic, strong) UILabel *titleLabel; 29 | @property (nonatomic, strong) UITableView *tpTableView; 30 | @property (nonatomic, strong) UILabel *tableHeaderViewLabel; 31 | @property (nonatomic, strong) UIScrollView *tpScrollView; 32 | @property (nonatomic, copy) NSArray *sequentialMethodRecord; 33 | @property (nonatomic, copy) NSArray *costTimeSortMethodRecord; 34 | @property (nonatomic, copy) NSArray *callCountSortMethodRecord; 35 | @property (nonatomic, assign) TPTableType tpTableType; 36 | 37 | @end 38 | 39 | @implementation GDNRecordDetailViewController 40 | 41 | - (instancetype)initWithModel:(GDNUIModel *)model { 42 | self = [super init]; 43 | if (self) { 44 | self.sequentialMethodRecord = model.sequentialMethodRecord; 45 | self.costTimeSortMethodRecord = model.costTimeSortMethodRecord; 46 | self.callCountSortMethodRecord = model.callCountSortMethodRecord; 47 | self.titleLabel.text = @"详情"; 48 | } 49 | return self; 50 | } 51 | 52 | - (void)viewDidLoad { 53 | [super viewDidLoad]; 54 | self.view.backgroundColor = [UIColor whiteColor]; 55 | [self.view addSubview:self.titleLabel]; 56 | [self.view addSubview:self.RecordBtn]; 57 | [self.view addSubview:self.costTimeSortBtn]; 58 | [self.view addSubview:self.callCountSortBtn]; 59 | [self.view addSubview:self.popVCBtn]; 60 | [self.view addSubview:self.tpScrollView]; 61 | [self.tpScrollView addSubview:self.tableHeaderViewLabel]; 62 | [self.tpScrollView addSubview:self.tpTableView]; 63 | // Do any additional setup after loading the view. 64 | [self clickRecordBtn]; 65 | } 66 | 67 | - (void)clickPopVCBtn:(UIButton *)btn { 68 | [self dismissViewControllerAnimated:YES completion:nil]; 69 | } 70 | 71 | #pragma mark - TPRecordCellDelegate 72 | 73 | - (void)recordCell:(GDNRecordDetailCell *)cell clickExpandWithSection:(NSInteger)section { 74 | NSIndexSet *indexSet; 75 | GDNRecordHierarchyModel *model; 76 | switch (self.tpTableType) { 77 | case tableTypeSequential: 78 | model = self.sequentialMethodRecord[section]; 79 | break; 80 | case tableTypecostTime: 81 | model = self.costTimeSortMethodRecord[section]; 82 | break; 83 | 84 | default: 85 | break; 86 | } 87 | model.isExpand = !model.isExpand; 88 | indexSet=[[NSIndexSet alloc] initWithIndex:section]; 89 | [self.tpTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic]; 90 | } 91 | 92 | #pragma mark - UITableViewDataSource 93 | 94 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 95 | if (self.tpTableType == tableTypeSequential) { 96 | return self.sequentialMethodRecord.count; 97 | } 98 | else if (self.tpTableType == tableTypecostTime) 99 | { 100 | return self.costTimeSortMethodRecord.count; 101 | } 102 | return 1; 103 | } 104 | 105 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 106 | if (self.tpTableType == tableTypeSequential) { 107 | GDNRecordHierarchyModel *model = self.sequentialMethodRecord[section]; 108 | if (model.isExpand && [model.subMethods isKindOfClass:NSArray.class]) { 109 | return model.subMethods.count+1; 110 | } 111 | } 112 | else if (self.tpTableType == tableTypecostTime) 113 | { 114 | GDNRecordHierarchyModel *model = self.costTimeSortMethodRecord[section]; 115 | if (model.isExpand && [model.subMethods isKindOfClass:NSArray.class]) { 116 | return model.subMethods.count+1; 117 | } 118 | } 119 | else 120 | { 121 | return self.callCountSortMethodRecord.count; 122 | } 123 | return 1; 124 | } 125 | 126 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 127 | static NSString *GDNRecordCellId = @"GDNRecordDetailCell_reuseIdentifier"; 128 | GDNRecordDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:GDNRecordCellId]; 129 | if (!cell) { 130 | cell = [[GDNRecordDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:GDNRecordCellId]; 131 | } 132 | GDNRecordHierarchyModel *model; 133 | GDNRecordModel *recordModel; 134 | BOOL isShowExpandBtn; 135 | switch (self.tpTableType) { 136 | case tableTypeSequential: 137 | model = self.sequentialMethodRecord[indexPath.section]; 138 | recordModel = [model getRecordModel:indexPath.row]; 139 | isShowExpandBtn = indexPath.row == 0 && [model.subMethods isKindOfClass:NSArray.class] && model.subMethods.count > 0; 140 | cell.delegate = self; 141 | [cell bindRecordModel:recordModel isHiddenExpandBtn:!isShowExpandBtn isExpand:model.isExpand section:indexPath.section isCallCountType:NO]; 142 | break; 143 | case tableTypecostTime: 144 | model = self.costTimeSortMethodRecord[indexPath.section]; 145 | recordModel = [model getRecordModel:indexPath.row]; 146 | isShowExpandBtn = indexPath.row == 0 && [model.subMethods isKindOfClass:NSArray.class] && model.subMethods.count > 0; 147 | cell.delegate = self; 148 | [cell bindRecordModel:recordModel isHiddenExpandBtn:!isShowExpandBtn isExpand:model.isExpand section:indexPath.section isCallCountType:NO]; 149 | break; 150 | case tableTypeCallCount: 151 | recordModel = self.callCountSortMethodRecord[indexPath.row]; 152 | [cell bindRecordModel:recordModel isHiddenExpandBtn:YES isExpand:YES section:indexPath.section isCallCountType:YES]; 153 | break; 154 | 155 | default: 156 | break; 157 | } 158 | return cell; 159 | } 160 | 161 | #pragma mark - Btn click method 162 | 163 | - (void)clickRecordBtn { 164 | self.costTimeSortBtn.selected = NO; 165 | self.callCountSortBtn.selected = NO; 166 | if (!self.RecordBtn.selected) { 167 | self.RecordBtn.selected = YES; 168 | self.tpTableType = tableTypeSequential; 169 | [self.tpTableView reloadData]; 170 | } 171 | } 172 | 173 | - (void)clickCostTimeSortBtn { 174 | self.RecordBtn.selected = NO; 175 | self.callCountSortBtn.selected = NO; 176 | if (!self.costTimeSortBtn.selected) { 177 | self.costTimeSortBtn.selected = YES; 178 | self.tpTableType = tableTypecostTime; 179 | [self.tpTableView reloadData]; 180 | } 181 | } 182 | 183 | - (void)clickCallCountSortBtn { 184 | self.costTimeSortBtn.selected = NO; 185 | self.RecordBtn.selected = NO; 186 | if (!self.callCountSortBtn.selected) { 187 | self.callCountSortBtn.selected = YES; 188 | self.tpTableType = tableTypeCallCount; 189 | [self.tpTableView reloadData]; 190 | } 191 | } 192 | 193 | 194 | #pragma mark - get&set method 195 | 196 | - (UIScrollView *)tpScrollView { 197 | if (!_tpScrollView) { 198 | _tpScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, GDNHeaderHight, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - GDNHeaderHight)]; 199 | _tpScrollView.showsHorizontalScrollIndicator = YES; 200 | _tpScrollView.alwaysBounceHorizontal = YES; 201 | _tpScrollView.contentSize = CGSizeMake(GDNScrollWidth, 0); 202 | } 203 | return _tpScrollView; 204 | } 205 | 206 | - (UITableView *)tpTableView { 207 | if (!_tpTableView) { 208 | _tpTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 30, GDNScrollWidth, [UIScreen mainScreen].bounds.size.height - GDNHeaderHight - 30) style:UITableViewStylePlain]; 209 | _tpTableView.bounces = NO; 210 | _tpTableView.dataSource = self; 211 | _tpTableView.rowHeight = 18; 212 | _tpTableView.separatorStyle = UITableViewCellSeparatorStyleNone; 213 | } 214 | return _tpTableView; 215 | } 216 | 217 | - (UIButton *)getTPBtnWithFrame:(CGRect)rect title:(NSString *)title sel:(SEL)sel { 218 | UIButton *btn = [[UIButton alloc] initWithFrame:rect]; 219 | btn.layer.cornerRadius = 2; 220 | btn.layer.borderWidth = 1; 221 | btn.layer.borderColor = [UIColor blackColor].CGColor; 222 | [btn setTitle:title forState:UIControlStateNormal]; 223 | [btn setBackgroundImage:[self imageWithColor:[UIColor colorWithRed:127/255.0 green:179/255.0 blue:219/255.0 alpha:1]] forState:UIControlStateSelected]; 224 | btn.titleLabel.font = [UIFont systemFontOfSize:10]; 225 | [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 226 | [btn addTarget:self action:sel forControlEvents:UIControlEventTouchUpInside]; 227 | return btn; 228 | } 229 | 230 | - (UIImage *)imageWithColor:(UIColor *)color { 231 | CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); 232 | UIGraphicsBeginImageContext(rect.size); 233 | CGContextRef context = UIGraphicsGetCurrentContext(); 234 | CGContextSetFillColorWithColor(context, [color CGColor]); 235 | CGContextFillRect(context, rect); 236 | UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); 237 | UIGraphicsEndImageContext(); 238 | return theImage; 239 | } 240 | 241 | - (UIButton *)RecordBtn { 242 | if (!_RecordBtn) { 243 | _RecordBtn = [self getTPBtnWithFrame:CGRectMake(5, 105, 60, 30) title:@"调用时间" sel:@selector(clickRecordBtn)]; 244 | } 245 | return _RecordBtn; 246 | } 247 | 248 | - (UIButton *)costTimeSortBtn { 249 | if (!_costTimeSortBtn) { 250 | _costTimeSortBtn = [self getTPBtnWithFrame:CGRectMake(70, 105, 60, 30) title:@"最耗时" sel:@selector(clickCostTimeSortBtn)]; 251 | } 252 | return _costTimeSortBtn; 253 | } 254 | 255 | - (UIButton *)callCountSortBtn { 256 | if (!_callCountSortBtn) { 257 | _callCountSortBtn = [self getTPBtnWithFrame:CGRectMake(135, 105, 60, 30) title:@"调用次数" sel:@selector(clickCallCountSortBtn)]; 258 | } 259 | return _callCountSortBtn; 260 | } 261 | 262 | - (UIButton *)popVCBtn { 263 | if (!_popVCBtn) { 264 | _popVCBtn = [self getTPBtnWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - 50, 105, 40, 30) title:@"返回" sel:@selector(clickPopVCBtn:)]; 265 | } 266 | return _popVCBtn; 267 | } 268 | 269 | - (UILabel *)titleLabel { 270 | if (!_titleLabel) { 271 | _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 50, [UIScreen mainScreen].bounds.size.width, 50)]; 272 | _titleLabel.textAlignment = NSTextAlignmentCenter; 273 | _titleLabel.font = [UIFont boldSystemFontOfSize:25]; 274 | } 275 | return _titleLabel; 276 | } 277 | 278 | - (UILabel *)tableHeaderViewLabel { 279 | if (!_tableHeaderViewLabel) { 280 | _tableHeaderViewLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, GDNScrollWidth, 30)]; 281 | _tableHeaderViewLabel.font = [UIFont systemFontOfSize:15]; 282 | _tableHeaderViewLabel.backgroundColor = [UIColor colorWithRed:219.0/255 green:219.0/255 blue:219.0/255 alpha:1]; 283 | } 284 | return _tableHeaderViewLabel; 285 | } 286 | 287 | - (void)setTpTableType:(TPTableType)tpTableType { 288 | if (_tpTableType!=tpTableType) { 289 | if (tpTableType==tableTypeCallCount) { 290 | self.tableHeaderViewLabel.text = @"深度 耗时 次数 方法名"; 291 | } else { 292 | self.tableHeaderViewLabel.text = @"深度 耗时 方法名"; 293 | } 294 | _tpTableType = tpTableType; 295 | } 296 | } 297 | 298 | @end 299 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordHierarchyModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordHierarchyModel.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import 9 | #import "GDNRecordModel.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface GDNRecordHierarchyModel : NSObject 14 | @property (nonatomic, strong) GDNRecordModel *rootMethod; 15 | @property (nonatomic, copy) NSArray *subMethods; 16 | @property (nonatomic, assign) BOOL isExpand; //是否展开所有的子函数 17 | 18 | - (instancetype)initWithRecordModels:(NSArray *)recordModels; 19 | - (GDNRecordModel *)getRecordModel:(NSInteger)index; 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordHierarchyModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordHierarchyModel.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import "GDNRecordHierarchyModel.h" 9 | 10 | @implementation GDNRecordHierarchyModel 11 | 12 | - (instancetype)initWithRecordModels:(NSArray *)recordModels { 13 | self = [super init]; 14 | if (self) { 15 | if ([recordModels isKindOfClass:NSArray.class] && recordModels.count > 0) { 16 | self.rootMethod = recordModels[0]; 17 | self.isExpand = YES; 18 | if (recordModels.count > 1) { 19 | self.subMethods = [recordModels subarrayWithRange:NSMakeRange(1, recordModels.count-1)]; 20 | } 21 | } 22 | } 23 | return self; 24 | } 25 | 26 | - (GDNRecordModel *)getRecordModel:(NSInteger)index { 27 | if (index==0) { 28 | return self.rootMethod; 29 | } 30 | return self.subMethods[index-1]; 31 | } 32 | 33 | - (id)copyWithZone:(NSZone *)zone { 34 | GDNRecordHierarchyModel *model = [[[self class] allocWithZone:zone] init]; 35 | model.rootMethod = self.rootMethod; 36 | model.subMethods = self.subMethods; 37 | model.isExpand = self.isExpand; 38 | return model; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordModel.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface GDNRecordModel : NSObject 13 | 14 | @property (nonatomic, strong) Class cls; 15 | @property (nonatomic) SEL sel; 16 | @property (nonatomic, assign) uint64_t costTime; //单位:纳秒(百万分之一秒) 17 | @property (nonatomic, assign) int depth; 18 | 19 | // 辅助堆栈排序 20 | @property (nonatomic, assign) int total; 21 | 22 | //call 次数 23 | @property (nonatomic, assign) int callCount; 24 | 25 | - (instancetype)initWithCls:(Class)cls sel:(SEL)sel time:(uint64_t)costTime depth:(int)depth total:(int)total; 26 | 27 | - (BOOL)isEqualRecordModel:(GDNRecordModel *)model; 28 | 29 | @end 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordModel.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import "GDNRecordModel.h" 9 | 10 | @implementation GDNRecordModel 11 | 12 | - (instancetype)initWithCls:(Class)cls sel:(SEL)sel time:(uint64_t)costTime depth:(int)depth total:(int)total { 13 | self = [super init]; 14 | if (self) { 15 | self.callCount = 0; 16 | self.cls = cls; 17 | self.sel = sel; 18 | self.costTime = costTime; 19 | self.depth = depth; 20 | self.total = total; 21 | } 22 | return self; 23 | } 24 | 25 | - (id)copyWithZone:(NSZone *)zone { 26 | GDNRecordModel *model = [[[self class] allocWithZone:zone] init]; 27 | model.cls = self.cls; 28 | model.sel = self.sel; 29 | model.costTime = self.costTime; 30 | model.depth = self.depth; 31 | model.total = self.total; 32 | model.callCount = self.callCount; 33 | return model; 34 | } 35 | 36 | - (BOOL)isEqualRecordModel:(GDNRecordModel *)model { 37 | if ([self.cls isEqual:model.cls] && self.sel == model.sel) { 38 | return YES; 39 | } 40 | return NO; 41 | } 42 | @end 43 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordRootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordRootViewController.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface GDNRecordRootViewController : UIViewController 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNRecordRootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDNRecordRootViewController.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import "GDNRecordRootViewController.h" 9 | #import "GDNOCMethodTimeProfiler.h" 10 | #import "GDNUIModel.h" 11 | #import "GDNRecordDetailViewController.h" 12 | 13 | @interface GDNRecordRootViewController () 14 | 15 | @property (nonatomic, strong) UITableView *tableview; 16 | @property (nonatomic, strong) UIButton *closeBtn; 17 | @property (nonatomic, copy) NSArray *modelData; 18 | @property (nonatomic, strong) UILabel *titleLabel; 19 | 20 | @end 21 | 22 | @implementation GDNRecordRootViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | self.view.backgroundColor = [UIColor whiteColor]; 27 | [self.view addSubview:self.closeBtn]; 28 | [self.view addSubview:self.tableview]; 29 | [self.view addSubview:self.titleLabel]; 30 | // Do any additional setup after loading the view. 31 | [self reloadTableview]; 32 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadTableview) name:GDNRecordsDataDidReadyNotification object:nil]; 33 | } 34 | 35 | - (void)reloadTableview { 36 | _modelData = [GDNOCMethodTimeProfiler modelsArr]; 37 | [self.tableview reloadData]; 38 | } 39 | 40 | - (void)dealloc { 41 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 42 | } 43 | 44 | #pragma mark - UITableViewDelegate / UITableViewDataSource 45 | 46 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 47 | return 1; 48 | } 49 | 50 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 51 | return _modelData.count; 52 | } 53 | 54 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 55 | static NSString *cellId = @"TPMainTableViewCellID"; 56 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId]; 57 | if (!cell) { 58 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId]; 59 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 60 | UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 36, [UIScreen mainScreen].bounds.size.width, 1)]; 61 | line.backgroundColor = [UIColor grayColor]; 62 | [cell.contentView addSubview:line]; 63 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 64 | } 65 | cell.textLabel.text = [NSString stringWithFormat:@"耗时详情 - %ld", indexPath.row]; 66 | return cell; 67 | } 68 | 69 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 70 | return @"Thread: main-thread"; 71 | } 72 | 73 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 74 | if (indexPath.row < _modelData.count) { 75 | GDNUIModel *model = _modelData[indexPath.row]; 76 | GDNRecordDetailViewController *vc = [[GDNRecordDetailViewController alloc] initWithModel:model]; 77 | vc.modalPresentationStyle = UIModalPresentationFullScreen; 78 | [self presentViewController:vc animated:YES completion:nil]; 79 | } 80 | } 81 | 82 | #pragma mark - private 83 | 84 | - (void)clickCloseBtn:(UIButton *)btn { 85 | [self dismissViewControllerAnimated:YES completion:nil]; 86 | } 87 | 88 | - (UIButton *)getTPBtnWithFrame:(CGRect)rect title:(NSString *)title sel:(SEL)sel { 89 | UIButton *btn = [[UIButton alloc] initWithFrame:rect]; 90 | btn.layer.cornerRadius = 2; 91 | btn.layer.borderWidth = 1; 92 | btn.layer.borderColor = [UIColor blackColor].CGColor; 93 | [btn setTitle:title forState:UIControlStateNormal]; 94 | [btn setBackgroundImage:[self imageWithColor:[UIColor colorWithRed:127/255.0 green:179/255.0 blue:219/255.0 alpha:1]] forState:UIControlStateSelected]; 95 | btn.titleLabel.font = [UIFont systemFontOfSize:10]; 96 | [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 97 | [btn addTarget:self action:sel forControlEvents:UIControlEventTouchUpInside]; 98 | return btn; 99 | } 100 | 101 | - (UIImage *)imageWithColor:(UIColor *)color { 102 | CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); 103 | UIGraphicsBeginImageContext(rect.size); 104 | CGContextRef context = UIGraphicsGetCurrentContext(); 105 | CGContextSetFillColorWithColor(context, [color CGColor]); 106 | CGContextFillRect(context, rect); 107 | UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); 108 | UIGraphicsEndImageContext(); 109 | return theImage; 110 | } 111 | 112 | #pragma mark - get&set method 113 | 114 | - (UITableView *)tableview { 115 | if (!_tableview) { 116 | _tableview = [[UITableView alloc] initWithFrame:CGRectMake(0, 100, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 100) style:UITableViewStylePlain]; 117 | _tableview.bounces = NO; 118 | _tableview.dataSource = self; 119 | _tableview.delegate = self; 120 | _tableview.rowHeight = 38; 121 | _tableview.sectionHeaderHeight = 50; 122 | _tableview.separatorStyle = UITableViewCellSeparatorStyleNone; 123 | } 124 | return _tableview; 125 | } 126 | 127 | - (UIButton *)closeBtn { 128 | if (!_closeBtn) { 129 | _closeBtn = [self getTPBtnWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - 50, 65, 40, 30) title:@"关闭" sel:@selector(clickCloseBtn:)]; 130 | } 131 | return _closeBtn; 132 | } 133 | 134 | - (UILabel *)titleLabel { 135 | if (!_titleLabel) { 136 | _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 55, [UIScreen mainScreen].bounds.size.width - 120, 50)]; 137 | _titleLabel.textAlignment = NSTextAlignmentCenter; 138 | _titleLabel.font = [UIFont boldSystemFontOfSize:25]; 139 | _titleLabel.text = @"TimeProfiler"; 140 | } 141 | return _titleLabel; 142 | } 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNUIModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDNUIModel.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface GDNUIModel : NSObject 13 | @property (nonatomic, copy) NSArray *sequentialMethodRecord; 14 | @property (nonatomic, copy) NSArray *costTimeSortMethodRecord; 15 | @property (nonatomic, copy) NSArray *callCountSortMethodRecord; 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/GDNUIModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // GDNUIModel.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import "GDNUIModel.h" 9 | 10 | @implementation GDNUIModel 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/UIWindow+GDN.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIWindow+GDN.h 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface UIWindow (GDN) 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Guldan/Classes/UI/UIWindow+GDN.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIWindow+GDN.m 3 | // Guldan 4 | // 5 | // Created by Alex023 on 2022/4/30. 6 | // 7 | 8 | #import "UIWindow+GDN.h" 9 | #import "GDNRecordRootViewController.h" 10 | 11 | @implementation UIWindow (GDN) 12 | 13 | - (BOOL)canBecomeFirstResponder { 14 | return YES; 15 | } 16 | 17 | - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { 18 | 19 | } 20 | 21 | - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { 22 | GDNRecordRootViewController *vc = [[GDNRecordRootViewController alloc] init]; 23 | vc.modalPresentationStyle = UIModalPresentationFullScreen; 24 | [self.rootViewController presentViewController:vc animated:YES completion:nil]; 25 | } 26 | 27 | - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event { 28 | 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Guldan/Classes/gdn_objc_msgSend.h: -------------------------------------------------------------------------------- 1 | // 2 | // gdn_objc_msgSend_h.h 3 | // Pods 4 | // 5 | // Created by Alex023 on 2021/11/15. 6 | // 7 | 8 | #ifndef gdn_objc_msgSend_h 9 | #define gdn_objc_msgSend_h 10 | 11 | __attribute__((naked)) 12 | id gdn_objc_msgSend(id self, SEL _cmd, ...); 13 | 14 | #endif /* Header_h */ 15 | -------------------------------------------------------------------------------- /Guldan/Classes/gdn_objc_msgSend.s: -------------------------------------------------------------------------------- 1 | // 2 | // gdn_objc_msgSend.s 3 | // Pods 4 | // 5 | // Created by Alex023 on 2021/11/15. 6 | // 7 | 8 | #if defined(__arm64__) 9 | .text 10 | 11 | .align 4 12 | 13 | /** 14 | * store registers 15 | **/ 16 | .macro GDN_STORE_REGISTERS 17 | 18 | stp fp, lr, [sp, #-0x10]! 19 | mov fp, sp 20 | sub sp, sp, #(10*8 + 8*16) 21 | stp x0, x1, [sp, #(8*16+0*8)] 22 | stp x2, x3, [sp, #(8*16+2*8)] 23 | stp x4, x5, [sp, #(8*16+4*8)] 24 | stp x6, x7, [sp, #(8*16+6*8)] 25 | str x8, [sp, #(8*16+8*8)] 26 | 27 | .endm 28 | 29 | /** 30 | * load registers 31 | **/ 32 | .macro GDN_LOAD_REGISTERS 33 | 34 | ldp x0, x1, [sp, #(8*16+0*8)] 35 | ldp x2, x3, [sp, #(8*16+2*8)] 36 | ldp x4, x5, [sp, #(8*16+4*8)] 37 | ldp x6, x7, [sp, #(8*16+6*8)] 38 | ldr x8, [sp, #(8*16+8*8)] 39 | mov sp, fp 40 | ldp fp, lr, [sp], #0x10 41 | 42 | .endm 43 | 44 | .globl _gdn_objc_msgSend 45 | _gdn_objc_msgSend: 46 | 47 | GDN_STORE_REGISTERS 48 | bl _needs_profiler 49 | cbnz x0, GDN_NEEDS_PROFILER 50 | 51 | GDN_LOAD_REGISTERS 52 | adrp x9, _origin_objc_msgSend@PAGE 53 | add x9, x9, _origin_objc_msgSend@PAGEOFF 54 | ldr x9, [x9] 55 | br x9 56 | 57 | GDN_NEEDS_PROFILER: 58 | ldp x0, x1, [fp, #-0x50] 59 | ldr x2, [fp, #0x8] 60 | bl _pre_objc_msgSend 61 | 62 | GDN_LOAD_REGISTERS 63 | adrp x9, _origin_objc_msgSend@PAGE 64 | add x9, x9, _origin_objc_msgSend@PAGEOFF 65 | ldr x9, [x9] 66 | blr x9 67 | 68 | GDN_STORE_REGISTERS 69 | bl _post_objc_msgSend 70 | mov x9, x0 71 | GDN_LOAD_REGISTERS 72 | // 恢复lr 73 | mov lr, x9 74 | ret 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /Guldan/Classes/gdn_objc_msgSend_time_profiler.h: -------------------------------------------------------------------------------- 1 | // 2 | // gdn_objc_msgSend_time_profiler.h 3 | // Pods 4 | // 5 | // Created by Alex023 on 2021/11/15. 6 | // 7 | 8 | #ifndef gdn_objc_msgSend_time_profiler_h 9 | #define gdn_objc_msgSend_time_profiler_h 10 | 11 | #if defined(__arm64__) 12 | 13 | #import 14 | 15 | typedef void(^GDNProductFilesBlock)(NSArray *filePaths); 16 | typedef void(^GDNMainThreadMethodRecords)(NSArray *allMethodRecords); 17 | 18 | /// 预处理 19 | void gdn_timeProfilerPreprocess(void); 20 | 21 | /// 启动耗时分析 22 | /// @param traceChildThread 是否trace子线程的方法执行 23 | /// @param traceSystemOnMainThread 是否trace主线程中的系统方法 24 | void gdn_timeProfilerStart(bool traceChildThread, bool traceSystemOnMainThread); 25 | 26 | /// 停止耗时分析 27 | void gdn_timeProfilerStop(void); 28 | 29 | /// 方法耗时阈值 30 | /// @param threshold 默认100ms 31 | void gdn_setTimeThreshold(uint64_t threshold); 32 | 33 | void gdn_handleRecordsWithComplete(GDNProductFilesBlock onFiles, GDNMainThreadMethodRecords onRecords); 34 | 35 | 36 | #endif // __arm64__ 37 | #endif /* gdn_objc_msgSend_time_profiler_h */ 38 | -------------------------------------------------------------------------------- /Guldan/Classes/gdn_objc_msgSend_time_profiler.m: -------------------------------------------------------------------------------- 1 | // 2 | // gdn_objc_msgSend_time_profiler.m 3 | // Pods 4 | // 5 | // Created by Alex023 on 2021/11/15. 6 | // 7 | 8 | #if defined(__arm64__) 9 | 10 | #import "gdn_objc_msgSend_time_profiler.h" 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #include 20 | #import "HLLFishhook.h" 21 | #import "gdn_objc_msgSend.h" 22 | #import "GDNRecordModel.h" 23 | #import "GDNRecordHierarchyModel.h" 24 | #import 25 | 26 | #define STACK_ENTRY_SIZE 800000 27 | #define MSG_SEND_INFO_SIZE 50 28 | #define GDN_MAX_THREAD_ID 400000 29 | 30 | id (*origin_objc_msgSend)(id self, SEL _cmd, ...); 31 | 32 | #pragma mark - Struct Define 33 | typedef struct { 34 | void *cls; 35 | char *cmd; 36 | double start_time; 37 | double consume_time; 38 | double shallow_consume_time; 39 | unsigned long stack_depth; 40 | } gdn_stack_entry_t; 41 | 42 | typedef struct { 43 | void *cls; 44 | char *cmd; 45 | double start_time; 46 | void *lr; 47 | double total_consume_time; 48 | } gdn_msgsend_info_t; 49 | 50 | typedef struct { 51 | unsigned int stack_depth; 52 | unsigned int stack_entry_count; 53 | unsigned int stack_entry_count_max; 54 | gdn_stack_entry_t stackEntries[STACK_ENTRY_SIZE]; 55 | gdn_msgsend_info_t msgsendInfos[MSG_SEND_INFO_SIZE]; 56 | } gdn_thread_info_t; 57 | 58 | gdn_thread_info_t *g_mainThreadInfo; 59 | static void *g_main_thread_get_class_result; 60 | 61 | void *g_classAddressMin; 62 | void *g_classAddressMax; 63 | 64 | static gdn_thread_info_t **g_threadInfos; 65 | static unsigned int g_mainThreadID; 66 | static bool g_trace_enabled = false; 67 | static bool g_traceChildThread = false; 68 | static bool g_traceSystemOnMainThread = false; 69 | static uint64_t g_timeThreshold = 100; //unit:ms 70 | 71 | double currentTimestamp(void) { 72 | static double timeCoefficient; 73 | static double baseTimestamp; 74 | static dispatch_once_t onceToken; 75 | dispatch_once(&onceToken, ^{ 76 | mach_timebase_info_data_t s_timebase_info; 77 | mach_timebase_info(&s_timebase_info); 78 | timeCoefficient = 1.0 * s_timebase_info.numer / (1e9 * s_timebase_info.denom); 79 | baseTimestamp = mach_absolute_time() * timeCoefficient; 80 | }); 81 | return mach_absolute_time() * timeCoefficient - baseTimestamp; 82 | } 83 | 84 | NSUInteger findStartDepthIndex(NSUInteger start, NSArray *arr) { 85 | NSUInteger index = start; 86 | if (arr.count > index) { 87 | GDNRecordModel *model = arr[index]; 88 | int minDepth = model.depth; 89 | int minTotal = model.total; 90 | for (NSUInteger i = index+1; i < arr.count; i++) { 91 | GDNRecordModel *tmp = arr[i]; 92 | if (tmp.depth < minDepth || (tmp.depth == minDepth && tmp.total < minTotal)) { 93 | minDepth = tmp.depth; 94 | minTotal = tmp.total; 95 | index = i; 96 | } 97 | } 98 | } 99 | return index; 100 | } 101 | 102 | NSArray *recursive_getRecord(NSMutableArray *arr) { 103 | if ([arr isKindOfClass:NSArray.class] && arr.count > 0) { 104 | BOOL isValid = YES; 105 | NSMutableArray *recordArr = [NSMutableArray array]; 106 | NSMutableArray *splitArr = [NSMutableArray array]; 107 | NSUInteger index = findStartDepthIndex(0, arr); 108 | if (index > 0) { 109 | [splitArr addObject:[NSMutableArray array]]; 110 | for (int i = 0; i < index; i++) { 111 | [[splitArr lastObject] addObject:arr[i]]; 112 | } 113 | } 114 | GDNRecordModel *model = arr[index]; 115 | [recordArr addObject:model]; 116 | [arr removeObjectAtIndex:index]; 117 | int startDepth = model.depth; 118 | int startTotal = model.total; 119 | for (NSUInteger i = index; i < arr.count; ) { 120 | model = arr[i]; 121 | if (model.total == startTotal && model.depth - 1 == startDepth) { 122 | [recordArr addObject:model]; 123 | [arr removeObjectAtIndex:i]; 124 | startDepth++; 125 | isValid = YES; 126 | } else { 127 | if (isValid) { 128 | isValid = NO; 129 | [splitArr addObject:[NSMutableArray array]]; 130 | } 131 | [[splitArr lastObject] addObject:model]; 132 | i++; 133 | } 134 | 135 | } 136 | 137 | for (NSUInteger i = splitArr.count; i > 0; i--) { 138 | NSMutableArray *sArr = splitArr[i - 1]; 139 | [recordArr addObjectsFromArray:recursive_getRecord(sArr)]; 140 | } 141 | return recordArr; 142 | } 143 | return @[]; 144 | } 145 | 146 | void setRecordDicWithRecord(NSMutableArray *arr, gdn_stack_entry_t stackEntry) { 147 | if ([arr isKindOfClass:NSMutableArray.class]) { 148 | int total = 1; 149 | for (NSUInteger i = 0; i < arr.count; i++) 150 | { 151 | GDNRecordModel *model = arr[i]; 152 | if (model.depth == stackEntry.stack_depth) { 153 | total = model.total + 1; 154 | break; 155 | } 156 | } 157 | GDNRecordModel *model = [[GDNRecordModel alloc] initWithCls:(__bridge Class _Nullable)stackEntry.cls sel:(SEL)stackEntry.cmd time:stackEntry.consume_time * 1e6 depth:(int)stackEntry.stack_depth total:total]; 158 | [arr insertObject:model atIndex:0]; 159 | } 160 | } 161 | 162 | #pragma mark - Core 163 | 164 | gdn_thread_info_t *get_thread_info(unsigned int thread_id) { 165 | assert(thread_id < GDN_MAX_THREAD_ID); 166 | gdn_thread_info_t *threadInfo = g_threadInfos[thread_id]; 167 | if (threadInfo == NULL) { 168 | threadInfo = (gdn_thread_info_t *)calloc(1, sizeof(gdn_thread_info_t)); 169 | threadInfo->stack_entry_count_max = STACK_ENTRY_SIZE; 170 | threadInfo->stack_depth = 0; 171 | threadInfo->stack_entry_count = 0; 172 | g_threadInfos[thread_id] = threadInfo; 173 | } 174 | return threadInfo; 175 | } 176 | 177 | void pre_objc_msgSend(void *obj, char *cmd, void *lr) { 178 | gdn_thread_info_t *threadInfo = NULL; 179 | unsigned int currentStackDepth = 0; 180 | if (pthread_main_np()) { 181 | threadInfo = g_mainThreadInfo; 182 | currentStackDepth = threadInfo->stack_depth; 183 | threadInfo->msgsendInfos[currentStackDepth] = ((gdn_msgsend_info_t){g_main_thread_get_class_result, cmd, currentTimestamp(), lr, 0}); 184 | } else { 185 | unsigned int thread_id = pthread_mach_thread_np(pthread_self()); 186 | threadInfo = get_thread_info(thread_id); 187 | currentStackDepth = threadInfo->stack_depth; 188 | threadInfo->msgsendInfos[currentStackDepth] = (gdn_msgsend_info_t){(__bridge void *)object_getClass((__bridge id)obj), cmd, currentTimestamp(), lr, 0}; 189 | } 190 | threadInfo->stack_depth = currentStackDepth + 1; 191 | } 192 | 193 | void *post_objc_msgSend(void) { 194 | gdn_thread_info_t *threadInfo = NULL; 195 | if (pthread_main_np()) { 196 | threadInfo = g_mainThreadInfo; 197 | } else { 198 | unsigned int thread_id = pthread_mach_thread_np(pthread_self()); 199 | threadInfo = get_thread_info(thread_id); 200 | } 201 | 202 | threadInfo->stack_depth -= 1; 203 | int currentStackDepth = threadInfo->stack_depth; 204 | gdn_msgsend_info_t *msgsendInfo = &threadInfo->msgsendInfos[currentStackDepth]; 205 | 206 | if (threadInfo->stack_entry_count < threadInfo->stack_entry_count_max && g_trace_enabled) { 207 | double consume_time = currentTimestamp() - msgsendInfo->start_time; 208 | int lastStackDepth = currentStackDepth - 1; 209 | if (lastStackDepth >= 0) { 210 | gdn_msgsend_info_t *last_msgsendInfo = &threadInfo->msgsendInfos[lastStackDepth]; 211 | last_msgsendInfo->total_consume_time += consume_time; 212 | } 213 | double shallow_consume_time = consume_time - msgsendInfo->total_consume_time; 214 | if (pthread_main_np()) { 215 | if (consume_time * 1e6 > g_timeThreshold) { 216 | threadInfo->stackEntries[threadInfo->stack_entry_count] = ((gdn_stack_entry_t){msgsendInfo->cls, msgsendInfo->cmd, msgsendInfo->start_time, consume_time, currentStackDepth, shallow_consume_time}); 217 | threadInfo->stack_entry_count++; 218 | } 219 | } else { 220 | threadInfo->stackEntries[threadInfo->stack_entry_count] = ((gdn_stack_entry_t){msgsendInfo->cls, msgsendInfo->cmd, msgsendInfo->start_time, consume_time, currentStackDepth, shallow_consume_time}); 221 | threadInfo->stack_entry_count++; 222 | } 223 | } 224 | return msgsendInfo->lr; 225 | } 226 | 227 | static void * g_NSObjectAddress; 228 | bool needs_profiler(void *obj) { 229 | if (!g_trace_enabled) { 230 | return false; 231 | } 232 | void *class_address = (__bridge void *)object_getClass((__bridge id)obj); 233 | if (pthread_main_np()) { 234 | g_main_thread_get_class_result = class_address; 235 | if (g_traceSystemOnMainThread) { 236 | return true; 237 | } 238 | } else { 239 | if (!g_traceChildThread) { 240 | return false; 241 | } 242 | } 243 | 244 | // 非系统库 245 | while (class_address != nil && class_address != g_NSObjectAddress) { 246 | if (class_address >= g_classAddressMin && class_address <= g_classAddressMax) { 247 | return true; 248 | } 249 | class_address = (__bridge void *)class_getSuperclass((__bridge Class _Nullable)(class_address)); 250 | } 251 | 252 | return false; 253 | } 254 | 255 | #pragma mark - Public 256 | void gdn_timeProfilerPreprocess() { 257 | assert(pthread_main_np()); 258 | g_NSObjectAddress = (__bridge void *)(objc_getClass("NSObject")); 259 | g_threadInfos = (gdn_thread_info_t **)calloc(GDN_MAX_THREAD_ID, sizeof(gdn_thread_info_t *)); 260 | g_mainThreadID = pthread_mach_thread_np(pthread_self()); 261 | g_mainThreadInfo = get_thread_info(g_mainThreadID); 262 | 263 | // 只处理非系统库区间 264 | const char *exeImage = [[NSBundle mainBundle].executablePath UTF8String]; 265 | unsigned int count = 0; 266 | const char **classNames = objc_copyClassNamesForImage(exeImage, &count); 267 | g_classAddressMin = (__bridge void *)objc_getClass(classNames[0]); 268 | g_classAddressMax = (__bridge void *)objc_getClass(classNames[count - 1]); 269 | free(classNames); 270 | 271 | rebind_symbols((struct rebinding[1]){{"objc_msgSend", (void *)gdn_objc_msgSend, (void **)&origin_objc_msgSend}}, 1); 272 | } 273 | 274 | void gdn_timeProfilerStart(bool traceChildThread, bool traceSystemOnMainThread) { 275 | assert(pthread_main_np()); 276 | g_trace_enabled = true; 277 | g_traceChildThread = traceChildThread; 278 | g_traceSystemOnMainThread = traceSystemOnMainThread; 279 | } 280 | 281 | void gdn_timeProfilerStop() { 282 | g_trace_enabled = false; 283 | } 284 | 285 | void gdn_setTimeThreshold(uint64_t threshold) { 286 | g_timeThreshold = threshold; 287 | } 288 | 289 | void gdn_handleRecordsWithComplete(GDNProductFilesBlock onFiles, GDNMainThreadMethodRecords onRecords) { 290 | NSString *userRootDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; 291 | NSMutableArray *tmpFilePaths = [NSMutableArray array]; 292 | 293 | for (int threadId = 0; threadId < GDN_MAX_THREAD_ID; threadId++) { 294 | gdn_thread_info_t *threadInfo = g_threadInfos[threadId]; 295 | if (!threadInfo || threadInfo->stack_entry_count_max != STACK_ENTRY_SIZE) { 296 | continue; 297 | } 298 | 299 | NSMutableData *dataM = [NSMutableData data]; 300 | BOOL isMainThread = (threadId == g_mainThreadID); 301 | NSString *threadName = isMainThread ? @"mainthread" : [NSString stringWithFormat:@"childthread_%d", threadId]; 302 | unsigned int recordsCount = threadInfo->stack_entry_count; 303 | 304 | if (isMainThread) { 305 | NSMutableArray *allMethodRecords = [NSMutableArray array]; 306 | unsigned int ii = 0, jj; 307 | while (ii < recordsCount) { 308 | @autoreleasepool { 309 | NSMutableArray *methodRecord = [NSMutableArray array]; 310 | for (jj = ii; jj < recordsCount; jj++) { 311 | gdn_stack_entry_t stackEntry = threadInfo->stackEntries[jj]; 312 | setRecordDicWithRecord(methodRecord, stackEntry); 313 | if (stackEntry.stack_depth == 0 || jj == recordsCount - 1) { 314 | NSArray *recordModels = recursive_getRecord(methodRecord); 315 | if (recordModels.count > 0) { 316 | GDNRecordHierarchyModel *model = [[GDNRecordHierarchyModel alloc] initWithRecordModels:recordModels]; 317 | [allMethodRecords addObject:model]; 318 | } 319 | //退出循环 320 | break; 321 | } 322 | } 323 | ii = jj + 1; 324 | } 325 | } 326 | if (onRecords) { 327 | onRecords(allMethodRecords); 328 | } 329 | } 330 | 331 | for (unsigned int i = 0; i < recordsCount; i++) { 332 | @autoreleasepool { 333 | gdn_stack_entry_t stackEntry = threadInfo->stackEntries[i]; 334 | Class cls = (__bridge Class _Nullable)(stackEntry.cls); 335 | BOOL isClassMethod = class_isMetaClass(cls); 336 | const char *className = class_getName(cls); 337 | char *selName = stackEntry.cmd; 338 | 339 | if (cls && strlen(className) > 0 && strlen(selName) > 0) { 340 | NSDictionary *start_piece = @{ 341 | @"name" : [NSString stringWithFormat:@"%@[%s %s]",(isClassMethod ? @"+" : @"-"), className, selName], 342 | @"cat": @"PERF", 343 | @"ph": @"B", 344 | @"pid": @0, 345 | @"tid": @(threadId), 346 | @"ts" : @(stackEntry.start_time * 1e6), 347 | @"args" : @{ 348 | @"stack_depth": @(stackEntry.stack_depth), 349 | @"shallow_consume": @(stackEntry.shallow_consume_time * 1e6), 350 | @"tname" : threadName, 351 | @"consume" : @(stackEntry.consume_time * 1e6) 352 | } 353 | }; 354 | NSDictionary *end_piece = @{ 355 | @"ph": @"E", 356 | @"pid": @0, 357 | @"tid": @(threadId), 358 | @"ts" : @((stackEntry.start_time + stackEntry.consume_time) * 1e6), 359 | }; 360 | NSData *start_pieceData = [NSJSONSerialization dataWithJSONObject:start_piece 361 | options:NSJSONWritingPrettyPrinted 362 | error:nil]; 363 | NSData *end_pieceData = [NSJSONSerialization dataWithJSONObject:end_piece 364 | options:NSJSONWritingPrettyPrinted 365 | error:nil]; 366 | if (i == 0) { 367 | [dataM appendData:[@"[" dataUsingEncoding:NSUTF8StringEncoding]]; 368 | } 369 | [dataM appendData:start_pieceData]; 370 | [dataM appendData:[@"," dataUsingEncoding:NSUTF8StringEncoding]]; 371 | [dataM appendData:end_pieceData]; 372 | if (i != recordsCount - 1) { 373 | [dataM appendData:[@"," dataUsingEncoding:NSUTF8StringEncoding]]; 374 | } 375 | if (i == recordsCount - 1) { 376 | [dataM appendData:[@"]" dataUsingEncoding:NSUTF8StringEncoding]]; 377 | } 378 | } 379 | } 380 | } 381 | 382 | 383 | NSString *productName = [NSString stringWithFormat:@"oc_method_cost_%@", threadName]; 384 | NSString *productPath = [userRootDir stringByAppendingPathComponent:productName]; 385 | [tmpFilePaths addObject:productPath]; 386 | [[NSFileManager defaultManager] createFileAtPath:productPath 387 | contents:dataM 388 | attributes:nil]; 389 | threadInfo->stack_entry_count = 0; 390 | threadInfo->stack_depth = 0; 391 | if (!isMainThread) { 392 | free(threadInfo); 393 | g_threadInfos[threadId] = NULL; 394 | } 395 | } 396 | if (onFiles) { 397 | onFiles(tmpFilePaths); 398 | } 399 | } 400 | 401 | #endif // __arm64__ 402 | 403 | -------------------------------------------------------------------------------- /Image/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuolalaTech/hll-wp-guldan-ios/0e0b539a62288b7397b2652217ccb11b33952959/Image/demo.png -------------------------------------------------------------------------------- /Image/sandbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuolalaTech/hll-wp-guldan-ios/0e0b539a62288b7397b2652217ccb11b33952959/Image/sandbox.png -------------------------------------------------------------------------------- /Image/xcode_devices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HuolalaTech/hll-wp-guldan-ios/0e0b539a62288b7397b2652217ccb11b33952959/Image/xcode_devices.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Alex023 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![license](https://img.shields.io/hexpm/l/plug.svg) 2 | ![Pod Version](https://img.shields.io/badge/pod-v1.0.0-green.svg) 3 | ![Platform](https://img.shields.io/badge/platform-iOS-blue.svg) 4 | ![Language](https://img.shields.io/badge/language-ObjectC-green.svg) 5 | 6 | --- 7 | ## Introduce 8 | 9 | guldan is an open source time-consuming analysis tool for iOS Objective-C method. It can facilitate development/testing students to quickly obtain the cost time of all OC methods within a certain period of time when the APP is running, and supports visualization. see more: [juejin paper](https://juejin.cn/post/7134877291716280328/) 10 | ## Compare 11 | |scheme compare |advantage | shortcomint 12 | |--|:-------------------------:|:-------------------------: 13 | | static instrumentation|The entry edge and exit edge of the function can be overwritten, and the entire execution process of the function can be covered | Negative impact on package volume; cannot be applied to closed source libraries; high access cost 14 | |Messier|Analysis product visualization, with time series | Relying on third-party maintenance, some iOS systems cannot be applied 15 | | Xcode Instruments | Powerful functions and support for sub-thread analysis | High cost of use; unsustainable analysis results; does not support timing 16 | | our scheme | Low invasiveness, high performance, low cost of use, visualization | Does not support simulators, only for OC methods time-consuming 17 | 18 | 19 | ## Features 20 | - Low intrusion: Hook objc_megSend is used to collect time-consuming data without intrusion to business target code; 21 | - High performance: The core code is implemented in assembly language, and the performance is guaranteed; 22 | - Visualization: Supports visualization of analysis results on desktop and mobile; 23 | - Support sub-threads: In addition to the method time-consuming analysis of the main thread, it also supports the method time-consuming analysis of sub-threads; 24 | 25 | ## Dependency 26 | - Real device and some simulators 27 | 28 | ## Usage 29 | 30 | (1) Install via CocoaPods command 31 | ``` 32 | pod 'Guldan' 33 | ``` 34 | (2) import header file 35 | ``` 36 | #import 37 | ``` 38 | (3)start analysis 39 | ``` 40 | [GDNOCMethodTimeProfiler start]; 41 | ``` 42 | (4)stop analysis 43 | ``` 44 | [GDNOCMethodTimeProfiler stop]; 45 | ``` 46 | (5)output result path 47 | ``` 48 | [GDNOCMethodTimeProfiler handleRecordsWithComplete:^(NSArray * _Nonnull filePaths) { 49 | // file path 50 | }]; 51 | ``` 52 | (6)output file path 53 | It can be opened quickly with the help of some sandbox tools. The sandbox directory can also be downloaded using Xcode. Here is only how to use Xcode to find the result file in the sandbox. 54 | Xcode window/Devices and Simulators/select target APP/Click the gear icon and select「Download Container」 55 | 56 | 57 | Right-click the file downloaded in the previous step, select "Show Package Contents" and find the oc_method_cost_mainthread file 58 | 59 | 60 | (7)Desktop visualization with Chrome 61 | Enter chrome://tracing/ in the chrome browser and drag in the oc_method_cost_mainthread file。 62 | 63 | 64 | 65 | ## Author 66 |    [HUOLALA mobile technology team](https://juejin.cn/user/1768489241815070) 67 | ## License 68 |   Guldan is released under the Apache 2.0 license. See [LICENSE](LICENSE) for details. 69 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | ![license](https://img.shields.io/hexpm/l/plug.svg) 2 | ![Pod Version](https://img.shields.io/badge/pod-v1.0.0-green.svg) 3 | ![Platform](https://img.shields.io/badge/platform-iOS-blue.svg) 4 | ![Language](https://img.shields.io/badge/language-ObjectC-green.svg) 5 | 6 | --- 7 | ## 介绍 8 | 9 | guldan是货拉拉开源的一个用于iOS Objective-C方法耗时分析的工具,能够方便开发/测试同学快速获取APP运行某段时间内所有OC方法的执行耗时,并支持可视化。详见 [掘金文章](https://juejin.cn/post/7134877291716280328/) 10 | ## 比较 11 | |方案对比 |优点 | 缺点 12 | |--|:-------------------------:|:-------------------------: 13 | | 静态插桩|可以覆盖函数的 entry edge 与 exit edge ,能够完成对函数的整个执行过程覆盖 | 对包体积有负向影响;无法应用到闭源库;接入成本高 14 | |Messier|分析产物可视化,具有时序性 | 依赖三方维护,部分iOS系统无法应用 15 | | Xcode Instruments | 功能强大、支持子线程分析, | 使用成本高;分析结果不可持续;不支持时序 16 | | 本方案 | 侵入性低、性能高、使用成本低、可视化 | 不支持模拟器、仅面向OC方法耗时 17 | 18 | 19 | ## 特点 20 | - 低侵入性:采用Hook objc_megSend方式采集耗时数据,对业务目标代码无侵入; 21 | - 高性能:采用汇编语言实现核心代码,性能有保障; 22 | - 可视化:支持桌面端和移动端的分析结果可视化; 23 | - 支持子线程:除了主线程的方法耗时分析,也支持子线程的方法耗时分析; 24 | 25 | ## 依赖 26 | - 真机设备和部分模拟器 27 | 28 | ## 使用 29 | 30 | (1) 通过CocoaPods命令安装 31 | ``` 32 | pod 'Guldan' 33 | ``` 34 | (2) 引入头文件 35 | ``` 36 | #import 37 | ``` 38 | (3)开始分析 39 | ``` 40 | [GDNOCMethodTimeProfiler start]; 41 | ``` 42 | (4)结束分析 43 | ``` 44 | [GDNOCMethodTimeProfiler stop]; 45 | ``` 46 | (5)输出结果文件路径 47 | ``` 48 | [GDNOCMethodTimeProfiler handleRecordsWithComplete:^(NSArray * _Nonnull filePaths) { 49 | // file path 50 | }]; 51 | ``` 52 | (6)输出结果文件路径 53 | 可借助一些沙盒工具快速打开。也可以使用Xcode下载沙盒目录。这里仅介绍如何使用Xcode找到沙盒中的结果文件。 54 | Xcode window/Devices and Simulators/选中目标APP/点击齿轮图标并选择「Download Container」 55 | 56 | 57 | 右击上一步下载的文件,选择「显示包内容」并找到oc_method_cost_mainthread文件 58 | 59 | 60 | (7)借助Chrome实现桌面端可视化 61 | 在chrome浏览器中输入chrome://tracing/,拖入oc_method_cost_mainthread文件。 62 | 63 | 64 | 65 | ## 作者 66 |    [货拉拉移动端技术团队](https://juejin.cn/user/1768489241815070) 67 | ## 许可证 68 |   采用Apache 2.0协议,详情参考[LICENSE](LICENSE) 69 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------