├── .gitignore ├── LICENSE ├── README.md ├── SwiftReflection.podspec ├── SwiftReflection.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── SwiftReflection ├── Info.plist ├── SwiftReflection.h └── SwiftReflection.swift └── SwiftReflectionTests ├── Info.plist ├── SwiftReflectionTests.swift └── TestClasses ├── Book.swift └── ValueTypes.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftReflection 2 | Retrieve name and type of properties for a class that inherits from NSObject. You do not need an instance of said class. 3 | 4 | # Usage 5 | SwiftReflection relies on the Objectice-C method `class_copyPropertyList` to fetch names and types of a class that inherits from NSObject. If you create some `Book` class 6 | ```swift 7 | class Book: NSObject { 8 | let title: String 9 | let author: String? 10 | let numberOfPages: Int 11 | let released: Date 12 | let isPocket: Bool 13 | 14 | init(title: String, author: String?, numberOfPages: Int, released: Date, isPocket: Bool) { 15 | self.title = title 16 | self.author = author 17 | self.numberOfPages = numberOfPages 18 | self.released = released 19 | self.isPocket = isPocket 20 | } 21 | } 22 | ``` 23 | 24 | Swift reflection can inspect the five properties of this class using the class method `getTypesOfProperties:inClass`. The following code that inspects properties of the class `Book` results in the commented print below: 25 | ```swift 26 | guard let types = getTypesOfProperties(inClass: Book.self) else { return } 27 | for (name, type) in types { 28 | print("'\(name)' has type '\(type)'") 29 | } 30 | // Prints: 31 | // 'title' has type 'NSString' 32 | // 'numberOfPages' has type 'Int' 33 | // 'author' has type 'NSString' 34 | // 'released' has type 'NSDate' 35 | // 'isPocket' has type 'Bool' 36 | ``` 37 | 38 | 39 | # Support for primitive data types 40 | It is a difference between inspecting properties which types inherits from NSObject, which then can be checked using the `==` operator and inspecting properties of value types (e.g. Bool, Int). If you declare this comparison operator you can check value types as well: 41 | ```swift 42 | func ==(rhs: Any, lhs: Any) -> Bool { 43 | let rhsType: String = "\(rhs)" 44 | let lhsType: String = "\(lhs)" 45 | let same = rhsType == lhsType 46 | return same 47 | } 48 | ``` 49 | 50 | Now you can inspect book by using: 51 | ```swift 52 | func checkPropertiesOfBook() { 53 | guard let types = getTypesOfProperties(inClass: Book.self) else { return } 54 | 55 | for (name, type) in types { 56 | if let objectType = type as? NSObject.Type { 57 | if objectType == NSDate.self { 58 | print("found NSDate") 59 | } 60 | } else { 61 | if type == Int.self { 62 | print("found int") 63 | } 64 | } 65 | } 66 | } 67 | ``` 68 | 69 | 70 | # LIMITATIONS 71 | I have not yet been able to give this project support for when the `value types` (non class types) are optionals. If you have declared a property in you NSObject subclass like this: `var myOptionalInt: Int?` my solution will not work, because the method `class_copyPropertyList` can't find those properties. 72 | 73 | **Does anyone have a solution for this?** 74 | -------------------------------------------------------------------------------- /SwiftReflection.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'SwiftReflection' 3 | s.version = '0.1.0' 4 | s.license = 'Apache' 5 | s.summary = 'Retreive type and name of properties of an NSObject class' 6 | s.homepage = 'https://github.com/Sajjon/SwiftReflection' 7 | s.authors = { 'Sajjon' => 'alex.cyon@gmail.com' } 8 | s.source = { :git => 'https://github.com/Sajjon/SwiftReflection.git', :tag => s.version } 9 | 10 | s.ios.deployment_target = '8.0' 11 | 12 | s.source_files = 'SwiftReflection/*.swift' 13 | end -------------------------------------------------------------------------------- /SwiftReflection.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 653599041D787F6500B411D1 /* SwiftReflection.h in Headers */ = {isa = PBXBuildFile; fileRef = 653599021D787F6500B411D1 /* SwiftReflection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 6535990B1D787F7D00B411D1 /* SwiftReflection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6535990A1D787F7D00B411D1 /* SwiftReflection.swift */; }; 12 | 65F8AC271D78824F00B44DE8 /* SwiftReflectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F8AC261D78824F00B44DE8 /* SwiftReflectionTests.swift */; }; 13 | 65F8AC291D78824F00B44DE8 /* SwiftReflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 653598FF1D787F6500B411D1 /* SwiftReflection.framework */; }; 14 | 65F8AC311D78827F00B44DE8 /* Book.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F8AC301D78827F00B44DE8 /* Book.swift */; }; 15 | 65F8AC331D7882E300B44DE8 /* ValueTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F8AC321D7882E300B44DE8 /* ValueTypes.swift */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXContainerItemProxy section */ 19 | 65F8AC2A1D78824F00B44DE8 /* PBXContainerItemProxy */ = { 20 | isa = PBXContainerItemProxy; 21 | containerPortal = 653598F61D787F6500B411D1 /* Project object */; 22 | proxyType = 1; 23 | remoteGlobalIDString = 653598FE1D787F6500B411D1; 24 | remoteInfo = SwiftReflection; 25 | }; 26 | /* End PBXContainerItemProxy section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 653598FF1D787F6500B411D1 /* SwiftReflection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftReflection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 653599021D787F6500B411D1 /* SwiftReflection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftReflection.h; sourceTree = ""; }; 31 | 653599031D787F6500B411D1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 6535990A1D787F7D00B411D1 /* SwiftReflection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftReflection.swift; sourceTree = ""; }; 33 | 65F8AC241D78824F00B44DE8 /* SwiftReflectionTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftReflectionTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 65F8AC261D78824F00B44DE8 /* SwiftReflectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftReflectionTests.swift; sourceTree = ""; }; 35 | 65F8AC281D78824F00B44DE8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 36 | 65F8AC301D78827F00B44DE8 /* Book.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Book.swift; sourceTree = ""; }; 37 | 65F8AC321D7882E300B44DE8 /* ValueTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValueTypes.swift; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | 653598FB1D787F6500B411D1 /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | 65F8AC211D78824F00B44DE8 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | 65F8AC291D78824F00B44DE8 /* SwiftReflection.framework in Frameworks */, 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | /* End PBXFrameworksBuildPhase section */ 57 | 58 | /* Begin PBXGroup section */ 59 | 653598F51D787F6500B411D1 = { 60 | isa = PBXGroup; 61 | children = ( 62 | 653599011D787F6500B411D1 /* SwiftReflection */, 63 | 65F8AC251D78824F00B44DE8 /* SwiftReflectionTests */, 64 | 653599001D787F6500B411D1 /* Products */, 65 | ); 66 | sourceTree = ""; 67 | }; 68 | 653599001D787F6500B411D1 /* Products */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 653598FF1D787F6500B411D1 /* SwiftReflection.framework */, 72 | 65F8AC241D78824F00B44DE8 /* SwiftReflectionTests.xctest */, 73 | ); 74 | name = Products; 75 | sourceTree = ""; 76 | }; 77 | 653599011D787F6500B411D1 /* SwiftReflection */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 653599021D787F6500B411D1 /* SwiftReflection.h */, 81 | 653599031D787F6500B411D1 /* Info.plist */, 82 | 6535990A1D787F7D00B411D1 /* SwiftReflection.swift */, 83 | ); 84 | path = SwiftReflection; 85 | sourceTree = ""; 86 | }; 87 | 65F8AC251D78824F00B44DE8 /* SwiftReflectionTests */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 65F8AC2F1D78827200B44DE8 /* TestClasses */, 91 | 65F8AC261D78824F00B44DE8 /* SwiftReflectionTests.swift */, 92 | 65F8AC281D78824F00B44DE8 /* Info.plist */, 93 | ); 94 | path = SwiftReflectionTests; 95 | sourceTree = ""; 96 | }; 97 | 65F8AC2F1D78827200B44DE8 /* TestClasses */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 65F8AC301D78827F00B44DE8 /* Book.swift */, 101 | 65F8AC321D7882E300B44DE8 /* ValueTypes.swift */, 102 | ); 103 | path = TestClasses; 104 | sourceTree = ""; 105 | }; 106 | /* End PBXGroup section */ 107 | 108 | /* Begin PBXHeadersBuildPhase section */ 109 | 653598FC1D787F6500B411D1 /* Headers */ = { 110 | isa = PBXHeadersBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | 653599041D787F6500B411D1 /* SwiftReflection.h in Headers */, 114 | ); 115 | runOnlyForDeploymentPostprocessing = 0; 116 | }; 117 | /* End PBXHeadersBuildPhase section */ 118 | 119 | /* Begin PBXNativeTarget section */ 120 | 653598FE1D787F6500B411D1 /* SwiftReflection */ = { 121 | isa = PBXNativeTarget; 122 | buildConfigurationList = 653599071D787F6500B411D1 /* Build configuration list for PBXNativeTarget "SwiftReflection" */; 123 | buildPhases = ( 124 | 653598FA1D787F6500B411D1 /* Sources */, 125 | 653598FB1D787F6500B411D1 /* Frameworks */, 126 | 653598FC1D787F6500B411D1 /* Headers */, 127 | 653598FD1D787F6500B411D1 /* Resources */, 128 | ); 129 | buildRules = ( 130 | ); 131 | dependencies = ( 132 | ); 133 | name = SwiftReflection; 134 | productName = SwiftReflection; 135 | productReference = 653598FF1D787F6500B411D1 /* SwiftReflection.framework */; 136 | productType = "com.apple.product-type.framework"; 137 | }; 138 | 65F8AC231D78824F00B44DE8 /* SwiftReflectionTests */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = 65F8AC2E1D78824F00B44DE8 /* Build configuration list for PBXNativeTarget "SwiftReflectionTests" */; 141 | buildPhases = ( 142 | 65F8AC201D78824F00B44DE8 /* Sources */, 143 | 65F8AC211D78824F00B44DE8 /* Frameworks */, 144 | 65F8AC221D78824F00B44DE8 /* Resources */, 145 | ); 146 | buildRules = ( 147 | ); 148 | dependencies = ( 149 | 65F8AC2B1D78824F00B44DE8 /* PBXTargetDependency */, 150 | ); 151 | name = SwiftReflectionTests; 152 | productName = SwiftReflectionTests; 153 | productReference = 65F8AC241D78824F00B44DE8 /* SwiftReflectionTests.xctest */; 154 | productType = "com.apple.product-type.bundle.unit-test"; 155 | }; 156 | /* End PBXNativeTarget section */ 157 | 158 | /* Begin PBXProject section */ 159 | 653598F61D787F6500B411D1 /* Project object */ = { 160 | isa = PBXProject; 161 | attributes = { 162 | LastSwiftUpdateCheck = 0800; 163 | LastUpgradeCheck = 0800; 164 | ORGANIZATIONNAME = com.cyon; 165 | TargetAttributes = { 166 | 653598FE1D787F6500B411D1 = { 167 | CreatedOnToolsVersion = 8.0; 168 | LastSwiftMigration = 0800; 169 | ProvisioningStyle = Automatic; 170 | }; 171 | 65F8AC231D78824F00B44DE8 = { 172 | CreatedOnToolsVersion = 8.0; 173 | ProvisioningStyle = Automatic; 174 | }; 175 | }; 176 | }; 177 | buildConfigurationList = 653598F91D787F6500B411D1 /* Build configuration list for PBXProject "SwiftReflection" */; 178 | compatibilityVersion = "Xcode 3.2"; 179 | developmentRegion = English; 180 | hasScannedForEncodings = 0; 181 | knownRegions = ( 182 | en, 183 | ); 184 | mainGroup = 653598F51D787F6500B411D1; 185 | productRefGroup = 653599001D787F6500B411D1 /* Products */; 186 | projectDirPath = ""; 187 | projectRoot = ""; 188 | targets = ( 189 | 653598FE1D787F6500B411D1 /* SwiftReflection */, 190 | 65F8AC231D78824F00B44DE8 /* SwiftReflectionTests */, 191 | ); 192 | }; 193 | /* End PBXProject section */ 194 | 195 | /* Begin PBXResourcesBuildPhase section */ 196 | 653598FD1D787F6500B411D1 /* Resources */ = { 197 | isa = PBXResourcesBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | }; 203 | 65F8AC221D78824F00B44DE8 /* Resources */ = { 204 | isa = PBXResourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | }; 210 | /* End PBXResourcesBuildPhase section */ 211 | 212 | /* Begin PBXSourcesBuildPhase section */ 213 | 653598FA1D787F6500B411D1 /* Sources */ = { 214 | isa = PBXSourcesBuildPhase; 215 | buildActionMask = 2147483647; 216 | files = ( 217 | 6535990B1D787F7D00B411D1 /* SwiftReflection.swift in Sources */, 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | }; 221 | 65F8AC201D78824F00B44DE8 /* Sources */ = { 222 | isa = PBXSourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | 65F8AC331D7882E300B44DE8 /* ValueTypes.swift in Sources */, 226 | 65F8AC311D78827F00B44DE8 /* Book.swift in Sources */, 227 | 65F8AC271D78824F00B44DE8 /* SwiftReflectionTests.swift in Sources */, 228 | ); 229 | runOnlyForDeploymentPostprocessing = 0; 230 | }; 231 | /* End PBXSourcesBuildPhase section */ 232 | 233 | /* Begin PBXTargetDependency section */ 234 | 65F8AC2B1D78824F00B44DE8 /* PBXTargetDependency */ = { 235 | isa = PBXTargetDependency; 236 | target = 653598FE1D787F6500B411D1 /* SwiftReflection */; 237 | targetProxy = 65F8AC2A1D78824F00B44DE8 /* PBXContainerItemProxy */; 238 | }; 239 | /* End PBXTargetDependency section */ 240 | 241 | /* Begin XCBuildConfiguration section */ 242 | 653599051D787F6500B411D1 /* Debug */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | ALWAYS_SEARCH_USER_PATHS = NO; 246 | CLANG_ANALYZER_NONNULL = YES; 247 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 248 | CLANG_CXX_LIBRARY = "libc++"; 249 | CLANG_ENABLE_MODULES = YES; 250 | CLANG_ENABLE_OBJC_ARC = YES; 251 | CLANG_WARN_BOOL_CONVERSION = YES; 252 | CLANG_WARN_CONSTANT_CONVERSION = YES; 253 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 254 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 255 | CLANG_WARN_EMPTY_BODY = YES; 256 | CLANG_WARN_ENUM_CONVERSION = YES; 257 | CLANG_WARN_INFINITE_RECURSION = YES; 258 | CLANG_WARN_INT_CONVERSION = YES; 259 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 260 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 261 | CLANG_WARN_UNREACHABLE_CODE = YES; 262 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 263 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 264 | COPY_PHASE_STRIP = NO; 265 | CURRENT_PROJECT_VERSION = 1; 266 | DEBUG_INFORMATION_FORMAT = dwarf; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | ENABLE_TESTABILITY = YES; 269 | GCC_C_LANGUAGE_STANDARD = gnu99; 270 | GCC_DYNAMIC_NO_PIC = NO; 271 | GCC_NO_COMMON_BLOCKS = YES; 272 | GCC_OPTIMIZATION_LEVEL = 0; 273 | GCC_PREPROCESSOR_DEFINITIONS = ( 274 | "DEBUG=1", 275 | "$(inherited)", 276 | ); 277 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 278 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 279 | GCC_WARN_UNDECLARED_SELECTOR = YES; 280 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 281 | GCC_WARN_UNUSED_FUNCTION = YES; 282 | GCC_WARN_UNUSED_VARIABLE = YES; 283 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 284 | MTL_ENABLE_DEBUG_INFO = YES; 285 | ONLY_ACTIVE_ARCH = YES; 286 | SDKROOT = iphoneos; 287 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 288 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 289 | TARGETED_DEVICE_FAMILY = "1,2"; 290 | VERSIONING_SYSTEM = "apple-generic"; 291 | VERSION_INFO_PREFIX = ""; 292 | }; 293 | name = Debug; 294 | }; 295 | 653599061D787F6500B411D1 /* Release */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | ALWAYS_SEARCH_USER_PATHS = NO; 299 | CLANG_ANALYZER_NONNULL = YES; 300 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 301 | CLANG_CXX_LIBRARY = "libc++"; 302 | CLANG_ENABLE_MODULES = YES; 303 | CLANG_ENABLE_OBJC_ARC = YES; 304 | CLANG_WARN_BOOL_CONVERSION = YES; 305 | CLANG_WARN_CONSTANT_CONVERSION = YES; 306 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 307 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 308 | CLANG_WARN_EMPTY_BODY = YES; 309 | CLANG_WARN_ENUM_CONVERSION = YES; 310 | CLANG_WARN_INFINITE_RECURSION = YES; 311 | CLANG_WARN_INT_CONVERSION = YES; 312 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 313 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 314 | CLANG_WARN_UNREACHABLE_CODE = YES; 315 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 316 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 317 | COPY_PHASE_STRIP = NO; 318 | CURRENT_PROJECT_VERSION = 1; 319 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 320 | ENABLE_NS_ASSERTIONS = NO; 321 | ENABLE_STRICT_OBJC_MSGSEND = YES; 322 | GCC_C_LANGUAGE_STANDARD = gnu99; 323 | GCC_NO_COMMON_BLOCKS = YES; 324 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 325 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 326 | GCC_WARN_UNDECLARED_SELECTOR = YES; 327 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 328 | GCC_WARN_UNUSED_FUNCTION = YES; 329 | GCC_WARN_UNUSED_VARIABLE = YES; 330 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 331 | MTL_ENABLE_DEBUG_INFO = NO; 332 | SDKROOT = iphoneos; 333 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 334 | TARGETED_DEVICE_FAMILY = "1,2"; 335 | VALIDATE_PRODUCT = YES; 336 | VERSIONING_SYSTEM = "apple-generic"; 337 | VERSION_INFO_PREFIX = ""; 338 | }; 339 | name = Release; 340 | }; 341 | 653599081D787F6500B411D1 /* Debug */ = { 342 | isa = XCBuildConfiguration; 343 | buildSettings = { 344 | CLANG_ENABLE_MODULES = YES; 345 | CODE_SIGN_IDENTITY = ""; 346 | DEFINES_MODULE = YES; 347 | DYLIB_COMPATIBILITY_VERSION = 1; 348 | DYLIB_CURRENT_VERSION = 1; 349 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 350 | INFOPLIST_FILE = SwiftReflection/Info.plist; 351 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 352 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 353 | PRODUCT_BUNDLE_IDENTIFIER = com.cyon.SwiftReflection; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | SKIP_INSTALL = YES; 356 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 357 | SWIFT_VERSION = 3.0; 358 | }; 359 | name = Debug; 360 | }; 361 | 653599091D787F6500B411D1 /* Release */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | CLANG_ENABLE_MODULES = YES; 365 | CODE_SIGN_IDENTITY = ""; 366 | DEFINES_MODULE = YES; 367 | DYLIB_COMPATIBILITY_VERSION = 1; 368 | DYLIB_CURRENT_VERSION = 1; 369 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 370 | INFOPLIST_FILE = SwiftReflection/Info.plist; 371 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 372 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 373 | PRODUCT_BUNDLE_IDENTIFIER = com.cyon.SwiftReflection; 374 | PRODUCT_NAME = "$(TARGET_NAME)"; 375 | SKIP_INSTALL = YES; 376 | SWIFT_VERSION = 3.0; 377 | }; 378 | name = Release; 379 | }; 380 | 65F8AC2C1D78824F00B44DE8 /* Debug */ = { 381 | isa = XCBuildConfiguration; 382 | buildSettings = { 383 | INFOPLIST_FILE = SwiftReflectionTests/Info.plist; 384 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 385 | PRODUCT_BUNDLE_IDENTIFIER = com.cyon.SwiftReflectionTests; 386 | PRODUCT_NAME = "$(TARGET_NAME)"; 387 | SWIFT_VERSION = 3.0; 388 | }; 389 | name = Debug; 390 | }; 391 | 65F8AC2D1D78824F00B44DE8 /* Release */ = { 392 | isa = XCBuildConfiguration; 393 | buildSettings = { 394 | INFOPLIST_FILE = SwiftReflectionTests/Info.plist; 395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 396 | PRODUCT_BUNDLE_IDENTIFIER = com.cyon.SwiftReflectionTests; 397 | PRODUCT_NAME = "$(TARGET_NAME)"; 398 | SWIFT_VERSION = 3.0; 399 | }; 400 | name = Release; 401 | }; 402 | /* End XCBuildConfiguration section */ 403 | 404 | /* Begin XCConfigurationList section */ 405 | 653598F91D787F6500B411D1 /* Build configuration list for PBXProject "SwiftReflection" */ = { 406 | isa = XCConfigurationList; 407 | buildConfigurations = ( 408 | 653599051D787F6500B411D1 /* Debug */, 409 | 653599061D787F6500B411D1 /* Release */, 410 | ); 411 | defaultConfigurationIsVisible = 0; 412 | defaultConfigurationName = Release; 413 | }; 414 | 653599071D787F6500B411D1 /* Build configuration list for PBXNativeTarget "SwiftReflection" */ = { 415 | isa = XCConfigurationList; 416 | buildConfigurations = ( 417 | 653599081D787F6500B411D1 /* Debug */, 418 | 653599091D787F6500B411D1 /* Release */, 419 | ); 420 | defaultConfigurationIsVisible = 0; 421 | defaultConfigurationName = Release; 422 | }; 423 | 65F8AC2E1D78824F00B44DE8 /* Build configuration list for PBXNativeTarget "SwiftReflectionTests" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | 65F8AC2C1D78824F00B44DE8 /* Debug */, 427 | 65F8AC2D1D78824F00B44DE8 /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | /* End XCConfigurationList section */ 433 | }; 434 | rootObject = 653598F61D787F6500B411D1 /* Project object */; 435 | } 436 | -------------------------------------------------------------------------------- /SwiftReflection.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftReflection/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 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwiftReflection/SwiftReflection.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftReflection.h 3 | // SwiftReflection 4 | // 5 | // Created by Cyon Alexander (Ext. Netlight) on 01/09/16. 6 | // Copyright © 2016 com.cyon. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SwiftReflection. 12 | FOUNDATION_EXPORT double SwiftReflectionVersionNumber; 13 | 14 | //! Project version string for SwiftReflection. 15 | FOUNDATION_EXPORT const unsigned char SwiftReflectionVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /SwiftReflection/SwiftReflection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftReflection.swift 3 | // SwiftReflection 4 | // 5 | // Created by Cyon Alexander (Ext. Netlight) on 01/09/16. 6 | // Copyright © 2016 com.cyon. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ObjectiveC.runtime 11 | 12 | 13 | /* 14 | Please note that the class you are inspecting have to inherit from NSObject. 15 | 16 | This tool can find the name and type of properties of type NSObject, e.g. NSString (or just "String" with Swift 3 syntax), NSDate (or just "NSDate" with Swift 3 syntax), NSNumber etc. 17 | It also works with optionals and implicit optionals for said types, e.g. String?, String!, Date!, Date? etc... 18 | 19 | This tool can also find name and type of "value type" such as Bool, Int, Int32, _HOWEVER_ it does not work if said value type is an optional, e.g. Int? <--- DOES NOT WORK 20 | */ 21 | 22 | 23 | public func getTypesOfProperties(in clazz: NSObject.Type, includeSuperclass: Bool = false, excludeReadOnlyProperties: Bool = false) -> Dictionary? { 24 | let types: Dictionary = [:] 25 | return getTypesOfProperties(in: clazz, types: types, includeSuperclass: includeSuperclass) 26 | } 27 | 28 | public func getTypesOfProperties(in clazz: NSObject.Type, types: Dictionary, includeSuperclass: Bool, excludeReadOnlyProperties: Bool = false) -> Dictionary? { 29 | var count = UInt32() 30 | guard let properties = class_copyPropertyList(clazz, &count) else { return nil } 31 | var types = types 32 | for i in 0.. Dictionary? { 52 | let clazz: NSObject.Type = type(of: object) 53 | return getTypesOfProperties(in: clazz) 54 | } 55 | 56 | public func typeOf(property propertyName: String, for object: NSObject) -> Any? { 57 | let type = type(of: object) 58 | return typeOf(property: propertyName, in: type) 59 | } 60 | 61 | public func typeOf(property propertyName: String, in clazz: NSObject.Type) -> Any? { 62 | guard let propertyTypes = getTypesOfProperties(in: clazz), let type = propertyTypes[propertyName] else { return nil } 63 | print("Property named: '\(propertyName)' has type: \(type)") 64 | return type 65 | } 66 | 67 | public func isProperty(named propertyName: String, ofType targetType: Any, for object: NSObject) -> Bool { 68 | let type = type(of: object) 69 | return isProperty(named: propertyName, ofType: targetType, in: type) 70 | } 71 | 72 | public func isProperty(named propertyName: String, ofType targetType: Any, in clazz: NSObject.Type) -> Bool { 73 | let propertyType = typeOf(property: propertyName, in: clazz) 74 | let match = propertyType == targetType 75 | return match 76 | } 77 | 78 | fileprivate func ==(rhs: Any, lhs: Any) -> Bool { 79 | let rhsType: String = "\(rhs)".withoutOptional 80 | let lhsType: String = "\(lhs)".withoutOptional 81 | let same = rhsType == lhsType 82 | return same 83 | } 84 | 85 | fileprivate func ==(rhs: NSObject.Type, lhs: Any) -> Bool { 86 | let rhsType: String = "\(rhs)".withoutOptional 87 | let lhsType: String = "\(lhs)".withoutOptional 88 | let same = rhsType == lhsType 89 | return same 90 | } 91 | 92 | fileprivate func ==(rhs: Any, lhs: NSObject.Type) -> Bool { 93 | let rhsType: String = "\(rhs)".withoutOptional 94 | let lhsType: String = "\(lhs)".withoutOptional 95 | let same = rhsType == lhsType 96 | return same 97 | } 98 | 99 | struct Unknown {} 100 | 101 | fileprivate func removeBrackets(_ className: String) -> String { 102 | guard className.contains("<") && className.contains(">") else { return className } 103 | let removed = className.chopPrefix().chopSuffix() 104 | return removed 105 | } 106 | 107 | fileprivate func getTypeOf(property: objc_property_t) -> Any { 108 | guard let attributesAsNSString: NSString = NSString(utf8String: property_getAttributes(property)) else { return Any.self } 109 | let attributes = attributesAsNSString as String 110 | let slices = attributes.components(separatedBy: "\"") 111 | guard slices.count > 1 else { return valueType(withAttributes: attributes) } 112 | let objectClassNameRaw = slices[1] 113 | let objectClassName = removeBrackets(objectClassNameRaw) 114 | 115 | guard let objectClass = NSClassFromString(objectClassName) else { 116 | if let nsObjectProtocol = NSProtocolFromString(objectClassName) { 117 | return nsObjectProtocol 118 | } 119 | print("Failed to retrieve type from: `\(objectClassName)`") 120 | return Unknown.self 121 | } 122 | return objectClass 123 | } 124 | 125 | fileprivate func isReadOnly(property: objc_property_t) -> Bool { 126 | guard let attributesAsNSString: NSString = NSString(utf8String: property_getAttributes(property)) else { return false } 127 | let attributes = attributesAsNSString as String 128 | return attributes.contains(",R,") 129 | } 130 | 131 | 132 | fileprivate func valueType(withAttributes attributes: String) -> Any { 133 | guard let letter = attributes.substring(from: 1, to: 2), let type = valueTypesMap[letter] else { return Any.self } 134 | return type 135 | } 136 | 137 | fileprivate func getNameOf(property: objc_property_t) -> String? { 138 | guard 139 | let name: NSString = NSString(utf8String: property_getName(property)) 140 | else { return nil } 141 | return name as String 142 | } 143 | 144 | fileprivate let valueTypesMap: Dictionary = [ 145 | "c" : Int8.self, 146 | "s" : Int16.self, 147 | "i" : Int32.self, 148 | "q" : Int.self, //also: Int64, NSInteger, only true on 64 bit platforms 149 | "S" : UInt16.self, 150 | "I" : UInt32.self, 151 | "Q" : UInt.self, //also UInt64, only true on 64 bit platforms 152 | "B" : Bool.self, 153 | "d" : Double.self, 154 | "f" : Float.self, 155 | "{" : Decimal.self 156 | ] 157 | 158 | private extension String { 159 | func substring(from fromIndex: Int, to toIndex: Int) -> String? { 160 | let substring = self[self.index(self.startIndex, offsetBy: fromIndex).. String { 173 | return substring(from: index(startIndex, offsetBy: count)) 174 | } 175 | 176 | func chopSuffix(_ count: Int = 1) -> String { 177 | return substring(to: index(endIndex, offsetBy: -count)) 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /SwiftReflectionTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwiftReflectionTests/SwiftReflectionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftReflectionTests.swift 3 | // SwiftReflectionTests 4 | // 5 | // Created by Cyon Alexander (Ext. Netlight) on 01/09/16. 6 | // Copyright © 2016 com.cyon. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import Foundation 11 | import SwiftReflection 12 | 13 | 14 | /// Enabling comparision of "primitive data types" such as Bool, Int etc 15 | func ==(rhs: Any, lhs: Any) -> Bool { 16 | let rhsType: String = "\(rhs)" 17 | let lhsType: String = "\(lhs)" 18 | let same = rhsType == lhsType 19 | return same 20 | } 21 | 22 | func ==(rhs: NSObject.Type, lhs: Any) -> Bool { 23 | let rhsType: String = "\(rhs)" 24 | let lhsType: String = "\(lhs)" 25 | let same = rhsType == lhsType 26 | return same 27 | } 28 | 29 | func ==(rhs: Any, lhs: NSObject.Type) -> Bool { 30 | let rhsType: String = "\(rhs)" 31 | let lhsType: String = "\(lhs)" 32 | let same = rhsType == lhsType 33 | return same 34 | } 35 | 36 | class SwiftReflectionTests: XCTestCase { 37 | 38 | override func setUp() { 39 | super.setUp() 40 | // Put setup code here. This method is called before the invocation of each test method in the class. 41 | } 42 | 43 | override func tearDown() { 44 | // Put teardown code here. This method is called after the invocation of each test method in the class. 45 | super.tearDown() 46 | } 47 | 48 | func testBookClass() { 49 | guard let types = SwiftReflection.getTypesOfProperties(in: Book.self) else { 50 | assert(false, "Should be able to get types") 51 | return 52 | } 53 | assert(types.count == 5, "Book should have 5 properties") 54 | for (propertyName, propertyType) in types { 55 | switch propertyName { 56 | case "title": 57 | assert(propertyType == NSString.self, "'title' should be of type 'String'") 58 | case "author": 59 | assert(propertyType == NSString.self, "Even though 'author' has type Optional it should be 'String'") 60 | case "numberOfPages": 61 | assert(propertyType == Int.self, "'numberOfPages' should be of primitive data type 'Int'") 62 | case "released": 63 | assert(propertyType == NSDate.self, "'released' should be of type 'NSDate'") 64 | case "isPocket": 65 | assert(propertyType == Bool.self, "'isPocket' should be of primitive data type 'Bool'") 66 | default: 67 | assert(false, "should not contain any property with any other name") 68 | } 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /SwiftReflectionTests/TestClasses/Book.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Book.swift 3 | // SwiftReflection 4 | // 5 | // Created by Cyon Alexander (Ext. Netlight) on 01/09/16. 6 | // Copyright © 2016 com.cyon. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Book: NSObject { 12 | let title: String 13 | let author: String? 14 | let numberOfPages: Int 15 | let released: Date 16 | let isPocket: Bool 17 | 18 | init(title: String, author: String?, numberOfPages: Int, released: Date, isPocket: Bool) { 19 | self.title = title 20 | self.author = author 21 | self.numberOfPages = numberOfPages 22 | self.released = released 23 | self.isPocket = isPocket 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SwiftReflectionTests/TestClasses/ValueTypes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ValueTypes.swift 3 | // SwiftReflection 4 | // 5 | // Created by Cyon Alexander (Ext. Netlight) on 01/09/16. 6 | // Copyright © 2016 com.cyon. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class ValueTypes: NSObject { 12 | var int8: Int8 = 1 13 | var int16: Int16 = 1 14 | var int32: Int32 = 1 15 | var int64: Int64 = 1 16 | var int: Int = 1 17 | var nsInteger: NSInteger = 1 18 | var uint16: UInt16 = 1 19 | var uint32: UInt32 = 1 20 | var uint64: UInt64 = 1 21 | var uint: UInt = 1 22 | var bool: Bool = true 23 | } 24 | --------------------------------------------------------------------------------