├── .DS_Store ├── .swift-version ├── .travis.yml ├── LICENSE ├── README.md ├── SexyJson.podspec ├── SexyJson.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── WHC.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── xcdebugger │ │ └── Expressions.xcexplist └── xcuserdata │ └── WHC.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── SexyJson.xcscheme │ └── xcschememanagement.plist ├── SexyJson ├── 1.2.0 │ └── SexyJson.podspec ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── Model │ ├── ModelObject.json │ ├── ModelObject.swift │ └── Test.swift └── ViewController.swift └── SexyJsonKit ├── SexyJson.swift ├── SexyJsonOperation.swift └── SexyJsonProtocol.swift /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netyouli/SexyJson/6bc42b32f820703fead0cdce6d6d8b548686800e/.DS_Store -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode8 2 | language: swift 3 | xcode_project: SexyJson.xcodeproj # path to your xcodeproj folder 4 | env: 5 | - ACTION=test PLATFORM=Mac DESTINATION='platform=OS X' 6 | - ACTION=test PLATFORM=iOS DESTINATION='platform=iOS Simulator,name=iPhone 6S' 7 | - ACTION=test PLATFORM=tvOS DESTINATION='platform=tvOS Simulator,name=Apple TV 1080p' 8 | xcode_schemes: SexyJson -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 吴海超 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SexyJson 2 | 3 | ![Build Status](https://api.travis-ci.org/netyouli/SexyJson.svg?branch=master) 4 | [![Pod Version](http://img.shields.io/cocoapods/v/SexyJson.svg?style=flat)](http://cocoadocs.org/docsets/SexyJson/) 5 | [![Platform](https://img.shields.io/cocoapods/p/SnapKit.svg?style=flat)](https://github.com/netyouli/) 6 | [![Pod License](http://img.shields.io/cocoapods/l/SexyJson.svg?style=flat)](https://opensource.org/licenses/MIT) 7 | 8 | SexyJson is Swift5+ json parse open source library quickly and easily, perfect supporting class and struct model, support the KVC model, fully oriented protocol architecture, support iOS and MAC OS X 9 | 10 | **Objective-c version** 👉 [WHC_Model](https://github.com/netyouli/WHC_Model) 11 | 12 | update:Support for compatible swift5.+ 13 | 14 | Note 15 | ============== 16 | - The definition of model must implement SexyJson protocol 17 | - If you have any enumeration type must be specified in the definition of model data type and implementation SexyJsonEnumType protocol 18 | - If you want to use **swift3.2**, please pod SexyJson '~> 0.0.4' 19 | 20 | Require 21 | ============== 22 | * iOS 8.0+ / Mac OS X 10.11+ / tvOS 9.0+ 23 | * Xcode 8.0 or later 24 | * Swift 5.0 25 | 26 | Install 27 | ============== 28 | * CocoaPods: pod 'SexyJson' 29 | 30 | Model 31 | ============== 32 | This is an example of json: 33 | ```swift 34 | let json = "{\"age\":25,\"enmuStr\":\"Work\",\"url\":\"https:\\/\\/www.baidu.com\", 35 | \"subArray\":[{\"test3\":\"test3\",\"test2\":\"test2\",\"cls\":{\"age\":10, 36 | \"name\":\"swift\"},\"test1\":\"test1\"},{\"test3\":\"test3\",\"test2\":\"test2\", 37 | \"cls\":{\"age\":10,\"name\":\"swift\"},\"test1\":\"test1\"}],\"color\":\"0xffbbaa\", 38 | \"nestArray\":[[{\"test\":\"test1\"},{\"test\":\"test2\"}],[{\"test\":\"test3\"}, 39 | {\"test\":\"test4\"}]],\"enmuInt\":10,\"sub\":{\"test1\":\"test1\",\"test2\":\"test2\", 40 | \"test3\":\"test3\"},\"height\":175,\"intArray\":[1,2,3,4],\"name\":\"吴海超\", 41 | \"learn\":[\"iOS\",\"android\",\"js\",\"nodejs\",\"python\"]}" 42 | ``` 43 | The model class: 44 | ```swift 45 | enum WorkEnum: String,SexyJsonEnumType { 46 | case null = "nil" 47 | case one = "Work" 48 | case two = "Not Work" 49 | } 50 | 51 | enum IntEnum: Int,SexyJsonEnumType { 52 | case zero = 0 53 | case hao = 10 54 | case xxx = 20 55 | } 56 | 57 | struct Model :SexyJson { 58 | 59 | var age: Int = 0 60 | var enmuStr: WorkEnum! 61 | var url: URL! 62 | var subArray: [SubArray]! 63 | var color: UIColor! 64 | var nestArray: [[NestArray]]? 65 | var enmuInt: IntEnum = .xxx 66 | var sub: Sub! 67 | var height: Int = 0 68 | var intArray: [Int]! 69 | var name: String! 70 | var learn: [String]! 71 | 72 | /// Model mapping 73 | public mutating func sexyMap(_ map: [String : Any]) { 74 | age <<< map["age"] 75 | enmuStr <<< map["enmuStr"] 76 | url <<< map["url"] 77 | subArray <<< map["subArray"] 78 | color <<< map["color"] 79 | nestArray <<< map["nestArray"] 80 | enmuInt <<< map["enmuInt"] 81 | sub <<< map["sub"] 82 | height <<< map["height"] 83 | intArray <<< map["intArray"] 84 | name <<< map["name"] 85 | learn <<< map["learn"] 86 | } 87 | } 88 | 89 | ``` 90 | **You don't need to manually create the SexyJson model class you can use open source tools with the help of** [WHC_DataModel.app](https://github.com/netyouli/WHC_DataModelFactory) **automatically created SexyJson model** 91 | 92 | Usage 93 | ============== 94 | 95 | Json is converted into a model object(json -> model) 96 | ```swift 97 | let model = Model.sexy_json(json) 98 | ``` 99 | 100 | Model object converted into the dictionary(model -> dictionary) 101 | ```swift 102 | let dictionary = model.sexy_dictionary() 103 | ``` 104 | 105 | Model object converted into the json string(model -> json) 106 | ```swift 107 | let jsonStr = model.sexy_json() 108 | ``` 109 | 110 | SexyJson support json parse the key path 111 | ```swift 112 | let subArrayModel = SubArray.sexy_json(json, keyPath: "subArray[0]") 113 | let subNestArray = NestArray.sexy_json(json, keyPath: "nestArray[0][0]") 114 | let test = String.sexy_json(json, keyPath: "nestArray[0][0].test") 115 | ``` 116 | 117 | Json is converted into a model array object(json -> [model]) 118 | ```swift 119 | let arrayModel = [Model].sexy_json(json) 120 | ``` 121 | 122 | Model object array converted into the array([model] -> array) 123 | ```swift 124 | let array = arrayModel.sexy_array() 125 | ``` 126 | 127 | Model object array converted into the json string([model] -> json) 128 | ```swift 129 | let arrayJson = arrayModel.sexy_json() 130 | ``` 131 | SexyJson support model kvc( Model class implement Codable protocol ) 132 | ```swift 133 | let sub = Sub.sexy_json(json, keyPath: "sub") 134 | if let modelCodingData = try? JSONEncoder().encode(modelCoding) { 135 | if let modelUncoding = try? JSONDecoder().decode(Sub.self, from: modelCodingData) { 136 | print("modelUncodingJson = \(modelUncoding.sexy_json()!)") 137 | } 138 | } 139 | ``` 140 | Prompt 141 | ============== 142 | If you want to view the analytical results, please download this demo to check the specific usage 143 | 144 | Licenses 145 | ============== 146 | All source code is licensed under the MIT License. 147 | 148 | -------------------------------------------------------------------------------- /SexyJson.podspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pod::Spec.new do |s| 4 | s.name = "SexyJson" 5 | s.version = "1.2.2" 6 | s.summary = "SexyJson is Swift5+ json parse open quickly and easily, perfect supporting class and struct model, support the KVC model" 7 | 8 | s.homepage = "https://github.com/netyouli/SexyJson" 9 | 10 | s.license = "MIT" 11 | 12 | s.author = { "吴海超(WHC)" => "712641411@qq.com" } 13 | 14 | s.platform = :ios 15 | s.platform = :ios, "8.0" 16 | 17 | s.source = { :git => "https://github.com/netyouli/SexyJson.git", :tag => s.version.to_s} 18 | 19 | s.source_files = "SexyJsonKit/*.{swift}" 20 | s.ios.deployment_target = '8.0' 21 | s.osx.deployment_target = '10.10' 22 | s.tvos.deployment_target = '9.0' 23 | s.requires_arc = true 24 | 25 | 26 | end 27 | -------------------------------------------------------------------------------- /SexyJson.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FE25EEB41ED42DCE00D9027F /* ModelObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE25EEB31ED42DCE00D9027F /* ModelObject.swift */; }; 11 | FE49C088207C9BE1009EF034 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE49C087207C9BE1009EF034 /* Test.swift */; }; 12 | FE6F0B041EC80E7200FCCFB6 /* SexyJsonProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE6F0B031EC80E7200FCCFB6 /* SexyJsonProtocol.swift */; }; 13 | FE6F0B061EC8204C00FCCFB6 /* SexyJsonOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE6F0B051EC8204C00FCCFB6 /* SexyJsonOperation.swift */; }; 14 | FEB8E54E1EBC2C39008045B9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB8E54D1EBC2C39008045B9 /* AppDelegate.swift */; }; 15 | FEB8E5501EBC2C39008045B9 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB8E54F1EBC2C39008045B9 /* ViewController.swift */; }; 16 | FEB8E5531EBC2C39008045B9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FEB8E5511EBC2C39008045B9 /* Main.storyboard */; }; 17 | FEB8E5551EBC2C39008045B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FEB8E5541EBC2C39008045B9 /* Assets.xcassets */; }; 18 | FEB8E5581EBC2C39008045B9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FEB8E5561EBC2C39008045B9 /* LaunchScreen.storyboard */; }; 19 | FEB8E5611EBC2C97008045B9 /* SexyJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB8E5601EBC2C97008045B9 /* SexyJson.swift */; }; 20 | FEC072E31FC6B276004207FB /* ModelObject.json in Resources */ = {isa = PBXBuildFile; fileRef = FEC072E21FC6B276004207FB /* ModelObject.json */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | FE25EEB31ED42DCE00D9027F /* ModelObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModelObject.swift; sourceTree = ""; }; 25 | FE49C087207C9BE1009EF034 /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; 26 | FE6F0B031EC80E7200FCCFB6 /* SexyJsonProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SexyJsonProtocol.swift; sourceTree = ""; }; 27 | FE6F0B051EC8204C00FCCFB6 /* SexyJsonOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SexyJsonOperation.swift; sourceTree = ""; }; 28 | FEB8E54A1EBC2C38008045B9 /* SexyJson.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SexyJson.app; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | FEB8E54D1EBC2C39008045B9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 30 | FEB8E54F1EBC2C39008045B9 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 31 | FEB8E5521EBC2C39008045B9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 32 | FEB8E5541EBC2C39008045B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 33 | FEB8E5571EBC2C39008045B9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 34 | FEB8E5591EBC2C39008045B9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | FEB8E5601EBC2C97008045B9 /* SexyJson.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SexyJson.swift; sourceTree = ""; }; 36 | FEC072E21FC6B276004207FB /* ModelObject.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ModelObject.json; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | FEB8E5471EBC2C38008045B9 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | /* End PBXFrameworksBuildPhase section */ 48 | 49 | /* Begin PBXGroup section */ 50 | FE25EEB21ED42DB900D9027F /* Model */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | FEC072E21FC6B276004207FB /* ModelObject.json */, 54 | FE25EEB31ED42DCE00D9027F /* ModelObject.swift */, 55 | FE49C087207C9BE1009EF034 /* Test.swift */, 56 | ); 57 | path = Model; 58 | sourceTree = ""; 59 | }; 60 | FEB8E5411EBC2C38008045B9 = { 61 | isa = PBXGroup; 62 | children = ( 63 | FEB8E55F1EBC2C7B008045B9 /* SexyJsonKit */, 64 | FEB8E54C1EBC2C39008045B9 /* SexyJson */, 65 | FEB8E54B1EBC2C38008045B9 /* Products */, 66 | ); 67 | sourceTree = ""; 68 | }; 69 | FEB8E54B1EBC2C38008045B9 /* Products */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | FEB8E54A1EBC2C38008045B9 /* SexyJson.app */, 73 | ); 74 | name = Products; 75 | sourceTree = ""; 76 | }; 77 | FEB8E54C1EBC2C39008045B9 /* SexyJson */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | FE25EEB21ED42DB900D9027F /* Model */, 81 | FEB8E54D1EBC2C39008045B9 /* AppDelegate.swift */, 82 | FEB8E54F1EBC2C39008045B9 /* ViewController.swift */, 83 | FEB8E5511EBC2C39008045B9 /* Main.storyboard */, 84 | FEB8E5541EBC2C39008045B9 /* Assets.xcassets */, 85 | FEB8E5561EBC2C39008045B9 /* LaunchScreen.storyboard */, 86 | FEB8E5591EBC2C39008045B9 /* Info.plist */, 87 | ); 88 | path = SexyJson; 89 | sourceTree = ""; 90 | }; 91 | FEB8E55F1EBC2C7B008045B9 /* SexyJsonKit */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | FEB8E5601EBC2C97008045B9 /* SexyJson.swift */, 95 | FE6F0B031EC80E7200FCCFB6 /* SexyJsonProtocol.swift */, 96 | FE6F0B051EC8204C00FCCFB6 /* SexyJsonOperation.swift */, 97 | ); 98 | path = SexyJsonKit; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | FEB8E5491EBC2C38008045B9 /* SexyJson */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = FEB8E55C1EBC2C39008045B9 /* Build configuration list for PBXNativeTarget "SexyJson" */; 107 | buildPhases = ( 108 | FEB8E5461EBC2C38008045B9 /* Sources */, 109 | FEB8E5471EBC2C38008045B9 /* Frameworks */, 110 | FEB8E5481EBC2C38008045B9 /* Resources */, 111 | ); 112 | buildRules = ( 113 | ); 114 | dependencies = ( 115 | ); 116 | name = SexyJson; 117 | productName = SexyJson; 118 | productReference = FEB8E54A1EBC2C38008045B9 /* SexyJson.app */; 119 | productType = "com.apple.product-type.application"; 120 | }; 121 | /* End PBXNativeTarget section */ 122 | 123 | /* Begin PBXProject section */ 124 | FEB8E5421EBC2C38008045B9 /* Project object */ = { 125 | isa = PBXProject; 126 | attributes = { 127 | LastSwiftUpdateCheck = 0820; 128 | LastUpgradeCheck = 0900; 129 | ORGANIZATIONNAME = WHC; 130 | TargetAttributes = { 131 | FEB8E5491EBC2C38008045B9 = { 132 | CreatedOnToolsVersion = 8.2.1; 133 | DevelopmentTeam = 7F5YZXGNJ3; 134 | ProvisioningStyle = Automatic; 135 | }; 136 | }; 137 | }; 138 | buildConfigurationList = FEB8E5451EBC2C38008045B9 /* Build configuration list for PBXProject "SexyJson" */; 139 | compatibilityVersion = "Xcode 3.2"; 140 | developmentRegion = English; 141 | hasScannedForEncodings = 0; 142 | knownRegions = ( 143 | English, 144 | en, 145 | Base, 146 | ); 147 | mainGroup = FEB8E5411EBC2C38008045B9; 148 | productRefGroup = FEB8E54B1EBC2C38008045B9 /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | FEB8E5491EBC2C38008045B9 /* SexyJson */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | FEB8E5481EBC2C38008045B9 /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | FEB8E5581EBC2C39008045B9 /* LaunchScreen.storyboard in Resources */, 163 | FEB8E5551EBC2C39008045B9 /* Assets.xcassets in Resources */, 164 | FEB8E5531EBC2C39008045B9 /* Main.storyboard in Resources */, 165 | FEC072E31FC6B276004207FB /* ModelObject.json in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXSourcesBuildPhase section */ 172 | FEB8E5461EBC2C38008045B9 /* Sources */ = { 173 | isa = PBXSourcesBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | FEB8E5501EBC2C39008045B9 /* ViewController.swift in Sources */, 177 | FEB8E5611EBC2C97008045B9 /* SexyJson.swift in Sources */, 178 | FE6F0B041EC80E7200FCCFB6 /* SexyJsonProtocol.swift in Sources */, 179 | FE49C088207C9BE1009EF034 /* Test.swift in Sources */, 180 | FE6F0B061EC8204C00FCCFB6 /* SexyJsonOperation.swift in Sources */, 181 | FE25EEB41ED42DCE00D9027F /* ModelObject.swift in Sources */, 182 | FEB8E54E1EBC2C39008045B9 /* AppDelegate.swift in Sources */, 183 | ); 184 | runOnlyForDeploymentPostprocessing = 0; 185 | }; 186 | /* End PBXSourcesBuildPhase section */ 187 | 188 | /* Begin PBXVariantGroup section */ 189 | FEB8E5511EBC2C39008045B9 /* Main.storyboard */ = { 190 | isa = PBXVariantGroup; 191 | children = ( 192 | FEB8E5521EBC2C39008045B9 /* Base */, 193 | ); 194 | name = Main.storyboard; 195 | sourceTree = ""; 196 | }; 197 | FEB8E5561EBC2C39008045B9 /* LaunchScreen.storyboard */ = { 198 | isa = PBXVariantGroup; 199 | children = ( 200 | FEB8E5571EBC2C39008045B9 /* Base */, 201 | ); 202 | name = LaunchScreen.storyboard; 203 | sourceTree = ""; 204 | }; 205 | /* End PBXVariantGroup section */ 206 | 207 | /* Begin XCBuildConfiguration section */ 208 | FEB8E55A1EBC2C39008045B9 /* Debug */ = { 209 | isa = XCBuildConfiguration; 210 | buildSettings = { 211 | ALWAYS_SEARCH_USER_PATHS = NO; 212 | CLANG_ANALYZER_NONNULL = YES; 213 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 214 | CLANG_CXX_LIBRARY = "libc++"; 215 | CLANG_ENABLE_MODULES = YES; 216 | CLANG_ENABLE_OBJC_ARC = YES; 217 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 218 | CLANG_WARN_BOOL_CONVERSION = YES; 219 | CLANG_WARN_COMMA = YES; 220 | CLANG_WARN_CONSTANT_CONVERSION = YES; 221 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 222 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 223 | CLANG_WARN_EMPTY_BODY = YES; 224 | CLANG_WARN_ENUM_CONVERSION = YES; 225 | CLANG_WARN_INFINITE_RECURSION = YES; 226 | CLANG_WARN_INT_CONVERSION = YES; 227 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 228 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 229 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 230 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 231 | CLANG_WARN_STRICT_PROTOTYPES = YES; 232 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 233 | CLANG_WARN_UNREACHABLE_CODE = YES; 234 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 235 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 236 | COPY_PHASE_STRIP = NO; 237 | DEBUG_INFORMATION_FORMAT = dwarf; 238 | ENABLE_STRICT_OBJC_MSGSEND = YES; 239 | ENABLE_TESTABILITY = YES; 240 | GCC_C_LANGUAGE_STANDARD = gnu99; 241 | GCC_DYNAMIC_NO_PIC = NO; 242 | GCC_NO_COMMON_BLOCKS = YES; 243 | GCC_OPTIMIZATION_LEVEL = 0; 244 | GCC_PREPROCESSOR_DEFINITIONS = ( 245 | "DEBUG=1", 246 | "$(inherited)", 247 | ); 248 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 249 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 250 | GCC_WARN_UNDECLARED_SELECTOR = YES; 251 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 252 | GCC_WARN_UNUSED_FUNCTION = YES; 253 | GCC_WARN_UNUSED_VARIABLE = YES; 254 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 255 | MTL_ENABLE_DEBUG_INFO = YES; 256 | ONLY_ACTIVE_ARCH = YES; 257 | SDKROOT = iphoneos; 258 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 259 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 260 | }; 261 | name = Debug; 262 | }; 263 | FEB8E55B1EBC2C39008045B9 /* Release */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | ALWAYS_SEARCH_USER_PATHS = NO; 267 | CLANG_ANALYZER_NONNULL = YES; 268 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 269 | CLANG_CXX_LIBRARY = "libc++"; 270 | CLANG_ENABLE_MODULES = YES; 271 | CLANG_ENABLE_OBJC_ARC = YES; 272 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 273 | CLANG_WARN_BOOL_CONVERSION = YES; 274 | CLANG_WARN_COMMA = YES; 275 | CLANG_WARN_CONSTANT_CONVERSION = YES; 276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 277 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 278 | CLANG_WARN_EMPTY_BODY = YES; 279 | CLANG_WARN_ENUM_CONVERSION = YES; 280 | CLANG_WARN_INFINITE_RECURSION = YES; 281 | CLANG_WARN_INT_CONVERSION = YES; 282 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 283 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 285 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 286 | CLANG_WARN_STRICT_PROTOTYPES = YES; 287 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 288 | CLANG_WARN_UNREACHABLE_CODE = YES; 289 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 290 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 291 | COPY_PHASE_STRIP = NO; 292 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 293 | ENABLE_NS_ASSERTIONS = NO; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | GCC_C_LANGUAGE_STANDARD = gnu99; 296 | GCC_NO_COMMON_BLOCKS = YES; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 304 | MTL_ENABLE_DEBUG_INFO = NO; 305 | SDKROOT = iphoneos; 306 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 307 | VALIDATE_PRODUCT = YES; 308 | }; 309 | name = Release; 310 | }; 311 | FEB8E55D1EBC2C39008045B9 /* Debug */ = { 312 | isa = XCBuildConfiguration; 313 | buildSettings = { 314 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 315 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 316 | DEVELOPMENT_TEAM = 7F5YZXGNJ3; 317 | INFOPLIST_FILE = SexyJson/Info.plist; 318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 319 | PRODUCT_BUNDLE_IDENTIFIER = WHC.SexyJson; 320 | PRODUCT_NAME = "$(TARGET_NAME)"; 321 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 322 | SWIFT_VERSION = 5.0; 323 | }; 324 | name = Debug; 325 | }; 326 | FEB8E55E1EBC2C39008045B9 /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 330 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 331 | DEVELOPMENT_TEAM = 7F5YZXGNJ3; 332 | INFOPLIST_FILE = SexyJson/Info.plist; 333 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 334 | PRODUCT_BUNDLE_IDENTIFIER = WHC.SexyJson; 335 | PRODUCT_NAME = "$(TARGET_NAME)"; 336 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 337 | SWIFT_VERSION = 5.0; 338 | }; 339 | name = Release; 340 | }; 341 | /* End XCBuildConfiguration section */ 342 | 343 | /* Begin XCConfigurationList section */ 344 | FEB8E5451EBC2C38008045B9 /* Build configuration list for PBXProject "SexyJson" */ = { 345 | isa = XCConfigurationList; 346 | buildConfigurations = ( 347 | FEB8E55A1EBC2C39008045B9 /* Debug */, 348 | FEB8E55B1EBC2C39008045B9 /* Release */, 349 | ); 350 | defaultConfigurationIsVisible = 0; 351 | defaultConfigurationName = Release; 352 | }; 353 | FEB8E55C1EBC2C39008045B9 /* Build configuration list for PBXNativeTarget "SexyJson" */ = { 354 | isa = XCConfigurationList; 355 | buildConfigurations = ( 356 | FEB8E55D1EBC2C39008045B9 /* Debug */, 357 | FEB8E55E1EBC2C39008045B9 /* Release */, 358 | ); 359 | defaultConfigurationIsVisible = 0; 360 | defaultConfigurationName = Release; 361 | }; 362 | /* End XCConfigurationList section */ 363 | }; 364 | rootObject = FEB8E5421EBC2C38008045B9 /* Project object */; 365 | } 366 | -------------------------------------------------------------------------------- /SexyJson.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SexyJson.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SexyJson.xcodeproj/project.xcworkspace/xcuserdata/WHC.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netyouli/SexyJson/6bc42b32f820703fead0cdce6d6d8b548686800e/SexyJson.xcodeproj/project.xcworkspace/xcuserdata/WHC.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SexyJson.xcodeproj/project.xcworkspace/xcuserdata/WHC.xcuserdatad/xcdebugger/Expressions.xcexplist: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SexyJson.xcodeproj/xcuserdata/WHC.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 14 | 15 | 16 | 18 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /SexyJson.xcodeproj/xcuserdata/WHC.xcuserdatad/xcschemes/SexyJson.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /SexyJson.xcodeproj/xcuserdata/WHC.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SexyJson.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | FEB8E5491EBC2C38008045B9 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SexyJson/1.2.0/SexyJson.podspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pod::Spec.new do |s| 4 | s.name = "SexyJson" 5 | s.version = "1.2.0" 6 | s.summary = "SexyJson is Swift5+ json parse open quickly and easily, perfect supporting class and struct model, support the KVC model" 7 | 8 | s.homepage = "https://github.com/netyouli/SexyJson" 9 | 10 | s.license = "MIT" 11 | 12 | s.author = { "吴海超(WHC)" => "712641411@qq.com" } 13 | 14 | s.platform = :ios 15 | s.platform = :ios, "8.0" 16 | 17 | s.source = { :git => "https://github.com/netyouli/SexyJson.git", :tag => s.version.to_s} 18 | 19 | s.source_files = "SexyJsonKit/*.{swift}" 20 | s.ios.deployment_target = '8.0' 21 | s.osx.deployment_target = '10.11' 22 | s.tvos.deployment_target = '9.0' 23 | s.requires_arc = true 24 | 25 | 26 | end 27 | -------------------------------------------------------------------------------- /SexyJson/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SexyJson 4 | // 5 | // Created by WHC on 17/5/5. 6 | // Copyright © 2017年 WHC. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /SexyJson/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /SexyJson/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 | -------------------------------------------------------------------------------- /SexyJson/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /SexyJson/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /SexyJson/Model/ModelObject.json: -------------------------------------------------------------------------------- 1 | { 2 | "age" : 25, 3 | "enmuStr" : "Work", 4 | "url" : "https:\/\/www.baidu.com", 5 | "subArray" : [ 6 | { 7 | "test3" : "test3", 8 | "test2" : "test2", 9 | "cls" : { 10 | "age" : 10, 11 | "name" : "swift" 12 | }, 13 | "test1" : "test1" 14 | }, 15 | { 16 | "test3" : "test3", 17 | "test2" : "test2", 18 | "cls" : { 19 | "age" : 10, 20 | "name" : "swift" 21 | }, 22 | "test1" : "test1" 23 | } 24 | ], 25 | "color" : "0xffbbaa", 26 | "nestArray" : [ 27 | [ 28 | { 29 | "test" : "test1" 30 | }, 31 | { 32 | "test" : "test2" 33 | } 34 | ], 35 | [ 36 | { 37 | "test" : "test3" 38 | }, 39 | { 40 | "test" : "test4" 41 | } 42 | ] 43 | ], 44 | "enmuInt" : 10, 45 | "sub" : { 46 | "test1" : "test1", 47 | "test2" : "test2", 48 | "test3" : "test3" 49 | }, 50 | "height" : 175, 51 | "intArray" : [ 52 | 1, 53 | 2, 54 | 3, 55 | 4 56 | ], 57 | "name" : "吴海超", 58 | "learn" : [ 59 | "iOS", 60 | "android", 61 | "js", 62 | "nodejs", 63 | "python" 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /SexyJson/Model/ModelObject.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelObject.swift 3 | // SexyJson 4 | // 5 | // Created by WHC on 17/5/23. 6 | // Copyright © 2017年 WHC. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum WorkEnum: String,SexyJsonEnumType { 12 | case null = "nil" 13 | case one = "Work" 14 | case two = "Not Work" 15 | } 16 | 17 | enum IntEnum: Int,SexyJsonEnumType { 18 | case zero = 0 19 | case hao = 10 20 | case xxx = 20 21 | } 22 | 23 | 24 | struct Cls :SexyJson { 25 | 26 | 27 | var age: Int = 0 28 | var name: String! 29 | 30 | public mutating func sexyMap(_ map: [String : Any]) { 31 | 32 | age <<< map["age"] 33 | name <<< map["name"] 34 | } 35 | 36 | } 37 | 38 | struct SubArray :SexyJson { 39 | 40 | var test3: String! 41 | var test2: String! 42 | var cls: Cls! 43 | var test1: String! 44 | 45 | public mutating func sexyMap(_ map: [String : Any]) { 46 | 47 | test3 <<< map["test3"] 48 | test2 <<< map["test2"] 49 | cls <<< map["cls"] 50 | test1 <<< map["test1"] 51 | } 52 | 53 | } 54 | 55 | struct NestArray :SexyJson { 56 | var test: String! 57 | 58 | public mutating func sexyMap(_ map: [String : Any]) { 59 | 60 | test <<< map["test"] 61 | } 62 | 63 | } 64 | 65 | class Sub: Codable, SexyJson { 66 | 67 | required init() { 68 | } 69 | 70 | var test1: String! 71 | var test2: String! 72 | var test3: String! 73 | 74 | public func sexyMap(_ map: [String : Any]) { 75 | 76 | test1 <<< map["test1"] 77 | test2 <<< map["test2"] 78 | test3 <<< map["test3"] 79 | } 80 | 81 | } 82 | 83 | struct ModelObject :SexyJson { 84 | 85 | var age: Int = 0 86 | var enmuStr: WorkEnum! 87 | var url: URL! 88 | var subArray: [SubArray]! 89 | var color: UIColor! 90 | var nestArray: [[NestArray]]? 91 | var enmuInt: IntEnum = .xxx 92 | var sub: Sub! 93 | var height: Int = 0 94 | var intArray: [Int]! 95 | var name: String! 96 | var learn: [String]! 97 | 98 | public mutating func sexyMap(_ map: [String : Any]) { 99 | 100 | age <<< map["age"] 101 | enmuStr <<< map["enmuStr"] 102 | url <<< map["url"] 103 | subArray <<< map["subArray"] 104 | color <<< map["color"] 105 | nestArray <<< map["nestArray"] 106 | 107 | enmuInt <<< map["enmuInt"] 108 | sub <<< map["sub"] 109 | height <<< map["height"] 110 | intArray <<< map["intArray"] 111 | name <<< map["name"] 112 | learn <<< map["learn"] 113 | } 114 | 115 | } 116 | 117 | class OBject: NSObject, SexyJson { 118 | required override init() { 119 | } 120 | 121 | func sexyMap(_ map: [String : Any]) { 122 | ks <<< map["ks"] 123 | } 124 | 125 | var ks: String? 126 | 127 | 128 | } 129 | -------------------------------------------------------------------------------- /SexyJson/Model/Test.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Test.swift 3 | // SexyJson 4 | // 5 | // Created by WHC on 2018/4/10. 6 | // Copyright © 2018年 WHC. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | 13 | /** 14 | * Copyright 2018 wuhaichao.com 15 | * Auto-generated:2018/4/10 下午3:20:26 16 | * 17 | * @author wuhaichao.com (whc) 18 | * @website http://wuhaichao.com 19 | * @github https://github.com/netyouli 20 | */ 21 | 22 | 23 | //MARK: - hotelListFilterItem - 24 | 25 | struct HotelListFilterItem:SexyJson { 26 | 27 | var hotelStyle: String? 28 | mutating func sexyMap(_ map: [String : Any]) { 29 | hotelStyle <<< map["hotelStyle"] 30 | } 31 | 32 | } 33 | 34 | //MARK: - dataList - 35 | 36 | struct DataList:SexyJson { 37 | var name: String? 38 | var isDefault: Bool = false 39 | var hotelListFilterItem: HotelListFilterItem? 40 | var dataId: Int = 0 41 | var tagList: [Any]? 42 | 43 | public mutating func sexyMap(_ map: [String : Any]) { 44 | 45 | name <<< map["name"] 46 | isDefault <<< map["isDefault"] 47 | hotelListFilterItem <<< map["hotelListFilterItem"] 48 | dataId <<< map["dataId"] 49 | tagList <<< map["tagList"] 50 | 51 | 52 | } 53 | } 54 | 55 | //MARK: - queryHotelObj - 56 | 57 | struct QueryHotelObj:SexyJson { 58 | var dataList: [DataList]? 59 | 60 | public mutating func sexyMap(_ map: [String : Any]) { 61 | 62 | dataList <<< map["dataList"] 63 | 64 | 65 | } 66 | } 67 | 68 | //MARK: - BaseClass - 69 | 70 | struct BaseClass:SexyJson { 71 | var queryHotelObj: QueryHotelObj? 72 | var resultType: Int = 0 73 | var message: String? 74 | 75 | public mutating func sexyMap(_ map: [String : Any]) { 76 | 77 | queryHotelObj <<< map["queryHotelObj"] 78 | resultType <<< map["resultType"] 79 | message <<< map["message"] 80 | 81 | 82 | } 83 | } 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /SexyJson/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SexyJson 4 | // 5 | // Created by WHC on 17/5/5. 6 | // Copyright © 2017年 WHC. All rights reserved. 7 | // 8 | // Github 9 | 10 | import UIKit 11 | 12 | class ViewController: UIViewController { 13 | @IBOutlet private weak var sexyLab: UILabel! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | /// layout 19 | sexyLab.frame = UIScreen.main.bounds 20 | 21 | let json = """ 22 | { 23 | "queryHotelObj": { 24 | "dataList": [ 25 | { 26 | "name": "酒店", 27 | "isDefault": true, 28 | "hotelListFilterItem": {}, 29 | "dataId": 1, 30 | "tagList": [] 31 | }, 32 | { 33 | "name": "公寓", 34 | "isDefault": true, 35 | "hotelListFilterItem": { 36 | "hotelStyle": "80,81" 37 | }, 38 | "dataId": 8, 39 | "tagList": [ 40 | { 41 | "type": 0, 42 | "name": "测试1", 43 | "targetUrl": "aaa" 44 | } 45 | ] 46 | }, 47 | { 48 | "name": "时租", 49 | "isDefault": true, 50 | "hotelListFilterItem": {}, 51 | "dataId": 3, 52 | "tagList": [] 53 | }, 54 | { 55 | "name": "国际", 56 | "isDefault": true, 57 | "hotelListFilterItem": {}, 58 | "dataId": 9, 59 | "tagList": [] 60 | }, 61 | { 62 | "name": "精选", 63 | "isDefault": true, 64 | "hotelListFilterItem": { 65 | "hotelStyle": "8" 66 | }, 67 | "dataId": 7, 68 | "tagList": [] 69 | } 70 | ] 71 | }, 72 | "resultType": 0, 73 | "message": "" 74 | } 75 | """ 76 | 77 | let test = BaseClass.sexy_json(json) 78 | 79 | let obj = OBject() 80 | obj.ks = "09" 81 | 82 | let jk = obj.sexy_copy() 83 | 84 | if let testjson = test?.sexy_json(format: true) { 85 | print("testJson = " + testjson) 86 | } 87 | 88 | let jsonString = try! String(contentsOfFile: Bundle.main.path(forResource: "ModelObject", ofType: "json")!, encoding: .utf8) 89 | let jsonData = jsonString.data(using: .utf8) 90 | 91 | print("***************** Model *****************\n\n") 92 | print("json -> model 对象:") 93 | let model = ModelObject.sexy_json(jsonData) 94 | print("model = \(String(describing: model))") 95 | print("\n---------------------------------------------------\n") 96 | 97 | print("model 对象 -> 字典:") 98 | let modelDict = model?.sexy_dictionary() 99 | print("modelDict = \(modelDict!)") 100 | print("\n---------------------------------------------------\n") 101 | 102 | print("model 对象 -> json字符串:") 103 | let modelJson = model?.sexy_json() 104 | print("modelJson = \(modelJson!)") 105 | 106 | 107 | 108 | print("\n***************** [Model] *****************\n\n") 109 | print("json -> [Model] 对象:") 110 | let arrayModel = [SubArray].sexy_json(modelJson,keyPath: "subArray") 111 | print("arrayModel = \(arrayModel!)") 112 | print("\n---------------------------------------------------\n") 113 | /* keyPath 用法展示 114 | let subArrayModel = SubArray.sexy_json(modelJson,keyPath: "subArray[0]") 115 | let subNestArray = NestArray.sexy_json(modelJson,keyPath: "nestArray[0][0]") 116 | let test = String.sexy_json(modelJson, keyPath: "nestArray[0][0].test") 117 | */ 118 | 119 | print("[model] 对象 -> 数组:") 120 | let arrayModelArray = arrayModel?.sexy_array() 121 | print("arrayModelArray = \(arrayModelArray!)") 122 | print("\n---------------------------------------------------\n") 123 | 124 | print("[model] 对象 -> json字符串:") 125 | let arrayModelJson = arrayModel?.sexy_json(format: true) 126 | print("arrayModelJson = \(arrayModelJson!)") 127 | 128 | 129 | print("\n***************** Model Coding *****************\n\n") 130 | let modelCoding = Sub.sexy_json(jsonData, keyPath: "sub") 131 | if let modelCodingData = try? JSONEncoder().encode(modelCoding) { 132 | if let modelUncoding = try? JSONDecoder().decode(Sub.self, from: modelCodingData) { 133 | print("modelUncodingJson = \(modelUncoding.sexy_json()!)") 134 | } 135 | } 136 | } 137 | 138 | override func viewWillAppear(_ animated: Bool) { 139 | super.viewWillAppear(animated) 140 | setLayout() 141 | } 142 | 143 | private func setLayout() { 144 | sexyLab.numberOfLines = 0 145 | sexyLab.textAlignment = .center 146 | sexyLab.font = UIFont.boldSystemFont(ofSize: 30) 147 | sexyLab.text = "SexyJson\nFast" 148 | } 149 | 150 | override func didReceiveMemoryWarning() { 151 | super.didReceiveMemoryWarning() 152 | // Dispose of any resources that can be recreated. 153 | } 154 | 155 | 156 | } 157 | 158 | -------------------------------------------------------------------------------- /SexyJsonKit/SexyJson.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SexyJson.swift 3 | // SexyJson 4 | // 5 | // Created by WHC on 17/5/5. 6 | // Copyright © 2017年 WHC. All rights reserved. 7 | // 8 | // Github 9 | 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | // THE SOFTWARE. 27 | 28 | import Foundation 29 | 30 | internal extension _SexyJsonBase { 31 | //// parser json keypath value 32 | static func _sexyKeyPathValue(_ keyPathArray: [String], json: Any?) -> Any? { 33 | var jsonObject = json 34 | keyPathArray.forEach({ (key) in 35 | if let range = key.range(of: "[") { 36 | let realKey = String(key[..)[realKey] 40 | indexString = String(key[range.lowerBound...]) 41 | } 42 | var handleIndexString = indexString.replacingOccurrences(of: "]", with: ",") 43 | handleIndexString = handleIndexString.replacingOccurrences(of: "[", with: "") 44 | if handleIndexString.hasSuffix(",") { 45 | handleIndexString = String(handleIndexString[..)[key] 67 | } 68 | }) 69 | return jsonObject 70 | } 71 | 72 | /// parser json 73 | static func _sexyJson(_ json: Any?, keyPath: String?) -> Self? { 74 | if json != nil { 75 | if keyPath != nil && keyPath != "" { 76 | var json_object: Any! 77 | switch json { 78 | case let str as String: 79 | let json_data = str.data(using: .utf8) 80 | return self._sexyJson(json_data, keyPath: keyPath) 81 | case let data as Data: 82 | json_object = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) 83 | return self._sexyJson(json_object, keyPath: keyPath) 84 | case _ as Dictionary , _ as Array: 85 | if let keyPathArray = keyPath?.components(separatedBy: ".") { 86 | let jsonObject = _sexyKeyPathValue(keyPathArray, json: json) 87 | switch jsonObject { 88 | case _ as Dictionary: 89 | print("SexyJson: Call api error,array json use api \(self).json(json)") 90 | return nil 91 | case _ as Array: 92 | print("SexyJson: Call api error,array json use api [\(self)].json(json)") 93 | return nil 94 | default: 95 | if let value = jsonObject as? Self { 96 | return value 97 | } 98 | print("SexyJson: Call api error, json not nil") 99 | return nil 100 | } 101 | } 102 | default: 103 | print("SexyJson: Call api error, json not nil") 104 | return nil 105 | } 106 | } 107 | if let value = json as? Self { 108 | return value 109 | } 110 | return nil 111 | } 112 | return nil 113 | } 114 | } 115 | 116 | extension NSObject { 117 | private struct SexyJsonConst { 118 | static var cachePropertyList = "SexyJsonConst###cachePropertyList" 119 | } 120 | 121 | private class func getPropertyList() -> [String] { 122 | if let cachePropertyList = objc_getAssociatedObject(self, &SexyJsonConst.cachePropertyList) as? [String], !cachePropertyList.isEmpty { 123 | return cachePropertyList 124 | } 125 | var propertyList = [String]() 126 | if let superClass = class_getSuperclass(self.classForCoder()) { 127 | if superClass != NSObject.classForCoder() { 128 | if let superList = (superClass as? NSObject.Type)?.getPropertyList() { 129 | propertyList.append(contentsOf: superList) 130 | } 131 | } 132 | } 133 | var count:UInt32 = 0 134 | if let properties = class_copyPropertyList(self.classForCoder(), &count) { 135 | for i in 0 ..< count { 136 | let name = property_getName(properties[Int(i)]) 137 | if let nameStr = String(cString: name, encoding: .utf8) { 138 | propertyList.append(nameStr) 139 | } 140 | } 141 | } 142 | objc_setAssociatedObject(self, &SexyJsonConst.cachePropertyList, propertyList, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 143 | return propertyList 144 | } 145 | 146 | //MARK: - model -> coding - 147 | 148 | 149 | /// model kvc编码 150 | /// 151 | /// - Parameter aCoder: 编码对象 152 | func sexy_encode(_ aCoder: NSCoder) { 153 | let selfType = type(of: self) 154 | selfType.getPropertyList().forEach { (name) in 155 | if let value = self.value(forKey: name) { 156 | aCoder.encode(value, forKey: name) 157 | } 158 | } 159 | } 160 | 161 | 162 | /// model kvc解码 163 | /// 164 | /// - Parameter decode: 解码对象 165 | func sexy_decode(_ decode: NSCoder) { 166 | let selfType = type(of: self) 167 | selfType.getPropertyList().forEach { (name) in 168 | if let value = decode.decodeObject(forKey: name) { 169 | self.setValue(value, forKey: name) 170 | } 171 | } 172 | } 173 | 174 | public func sexy_copy() -> Self? { 175 | if let proself = self as? SexyJson { 176 | if let selftype = self.classForCoder as? SexyJson.Type { 177 | return selftype.sexy_json(proself.sexyToValue()) as? Self 178 | } 179 | }else { 180 | print("SexyJson: Call sexy_copy error, \(self) not implementation SexyJson") 181 | } 182 | return nil 183 | } 184 | } 185 | 186 | public extension SexyJsonBasicType { 187 | 188 | /// 解析json 189 | /// 190 | /// - Parameters: 191 | /// - json: json数据(字符串、字典,data) 192 | /// - keyPath: json key路径 193 | /// - Returns: model对象 194 | static func sexy_json(_ json: Any?, keyPath: String?) -> Self? { 195 | return _sexyJson(json, keyPath: keyPath) 196 | } 197 | } 198 | 199 | public extension SexyJsonObjectType { 200 | 201 | /// 解析json 202 | /// 203 | /// - Parameters: 204 | /// - json: json数据(字符串、字典,data) 205 | /// - keyPath: json key路径 206 | /// - Returns: model对象 207 | static func sexy_json(_ json: Any?, keyPath: String?) -> Self? { 208 | return _sexyJson(json, keyPath: keyPath) 209 | } 210 | } 211 | 212 | public extension SexyJson { 213 | 214 | //MARK: - json -> model - 215 | 216 | 217 | /// 解析json 218 | /// 219 | /// - Parameter json: json数据(字符串、字典,data) 220 | /// - Returns: model对象 221 | static func sexy_json(_ json: Any?) -> Self? { 222 | switch json { 223 | case let str as String: 224 | let json_data = str.data(using: .utf8) 225 | return Self.sexy_json(json_data) 226 | case let data as Data: 227 | let json_object = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) 228 | return Self.sexy_json(json_object) 229 | case let dictionary as Dictionary: 230 | var model = Self.init() 231 | model.sexyMap(dictionary) 232 | return model 233 | case _ as Array: 234 | print("SexyJson: Call api error,array json use api [\(self)].json(json)") 235 | return nil 236 | default: 237 | print("SexyJson: Call api error, json not nil") 238 | return nil 239 | } 240 | } 241 | 242 | /// 解析json 243 | /// 244 | /// - Parameters: 245 | /// - json: json数据(字符串、字典,data) 246 | /// - keyPath: json key路径 247 | /// - Returns: model对象 248 | static func sexy_json(_ json: Any?, keyPath: String?) -> Self? { 249 | if json != nil { 250 | if keyPath != nil && keyPath != "" { 251 | var json_object: Any! 252 | switch json { 253 | case let str as String: 254 | let json_data = str.data(using: .utf8) 255 | return self.sexy_json(json_data, keyPath: keyPath) 256 | case let data as Data: 257 | json_object = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) 258 | return self.sexy_json(json_object, keyPath: keyPath) 259 | case _ as Dictionary , _ as Array: 260 | if let keyPathArray = keyPath?.components(separatedBy: ".") { 261 | let jsonObject = _sexyKeyPathValue(keyPathArray, json: json) 262 | switch jsonObject { 263 | case _ as Dictionary: 264 | return self.sexy_json(jsonObject) 265 | case _ as Array: 266 | print("SexyJson: Call api error,array json use api [\(self)].json(json)") 267 | return nil 268 | default: 269 | print("SexyJson: Call api error, json not nil") 270 | return nil 271 | } 272 | } 273 | default: 274 | print("SexyJson: Call api error, json not nil") 275 | return nil 276 | } 277 | } 278 | return self.sexy_json(json) 279 | } 280 | return nil 281 | } 282 | 283 | //MARK: - model -> json - 284 | 285 | 286 | /// model->json string 287 | /// 288 | /// - Parameter format: 格式化json 289 | /// - Returns: json string 290 | func sexy_json(format: Bool = false) -> String? { 291 | if let map = self.sexy_dictionary() { 292 | if JSONSerialization.isValidJSONObject(map) { 293 | do { 294 | let jsonData = try JSONSerialization.data(withJSONObject: map, options: format ? .prettyPrinted : []) 295 | return String(data: jsonData, encoding: .utf8) 296 | }catch let error { 297 | print("SexyJson: error \(error)") 298 | } 299 | }else { 300 | print("SexyJson: error invalid json map") 301 | } 302 | return nil 303 | } 304 | return nil 305 | } 306 | 307 | /// model->json 字典 308 | /// 309 | /// - Returns: json 字典 310 | func sexy_dictionary() -> [String: Any]? { 311 | return self.sexyToValue() as? [String : Any] 312 | } 313 | } 314 | 315 | public extension Dictionary { 316 | 317 | /// map->json string 318 | /// 319 | /// - Parameter format: 格式化json 320 | /// - Returns: json string 321 | func sexy_json(format: Bool = false) -> String? { 322 | if let jsonMap = self.sexyToValue() { 323 | if JSONSerialization.isValidJSONObject(jsonMap) { 324 | do { 325 | let jsonData = try JSONSerialization.data(withJSONObject: jsonMap, options: format ? .prettyPrinted : []) 326 | return String(data: jsonData, encoding: .utf8) 327 | }catch let error { 328 | print("SexyJson: error \(error)") 329 | } 330 | }else { 331 | print("SexyJson: error invalid json map") 332 | } 333 | return nil 334 | } 335 | return nil 336 | } 337 | } 338 | 339 | public extension Array { 340 | 341 | //MARK: - json -> model - 342 | 343 | 344 | /// 解析json->[Model] 345 | /// 346 | /// - Parameter json: json数据(字符串、字典,data) 347 | /// - Returns: 模型数组[Model] 348 | static func sexy_json(_ json: Any?) -> [Element]? { 349 | switch json { 350 | case let jsonList as [Any]: 351 | var modelList = [Element]() 352 | jsonList.forEach({ (each) in 353 | switch Element.self { 354 | case is SexyJson.Type: 355 | if let model = (Element.self as? SexyJson.Type)?.sexy_json(each) { 356 | if let value = model as? Element { 357 | modelList.append(value) 358 | } 359 | } 360 | case is _SexyJsonBasicType.Type: 361 | if let model = (Element.self as? _SexyJsonBasicType.Type)?.sexyTransform(each) { 362 | if let value = model as? Element { 363 | modelList.append(value) 364 | } 365 | } 366 | case is SexyJsonObjectType.Type: 367 | if let model = (Element.self as? SexyJsonObjectType.Type)?._sexyTransform(each) { 368 | if let value = model as? Element { 369 | modelList.append(value) 370 | } 371 | } 372 | default: 373 | if let value = each as? Element { 374 | modelList.append(value) 375 | } 376 | } 377 | }) 378 | return modelList 379 | case let str as String: 380 | let json_data = str.data(using: .utf8) 381 | return [Element].sexy_json(json_data) 382 | case let data as Data: 383 | let json_object = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) 384 | return [Element].sexy_json(json_object) 385 | case _ as Dictionary: 386 | print("Call api error,object json use api Model.json(json)") 387 | return nil 388 | default: 389 | print("Call api error, json not nil") 390 | return nil 391 | } 392 | } 393 | 394 | 395 | /// 解析json->[Model] 396 | /// 397 | /// - Parameters: 398 | /// - json: json数据(字符串、字典,data) 399 | /// - keyPath: json keyPath路径 400 | /// - Returns: 模型数组[Model] 401 | static func sexy_json(_ json: Any?, keyPath: String?) -> [Element]? { 402 | if json != nil { 403 | if keyPath != nil && keyPath != "" { 404 | var json_object: Any! 405 | switch json { 406 | case let str as String: 407 | let json_data = str.data(using: .utf8) 408 | return self.sexy_json(json_data, keyPath: keyPath) 409 | case let data as Data: 410 | json_object = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) 411 | return self.sexy_json(json_object, keyPath: keyPath) 412 | case _ as Dictionary, _ as Array: 413 | if let keyPathArray = keyPath?.components(separatedBy: ".") { 414 | let jsonObject = _sexyKeyPathValue(keyPathArray, json: json) 415 | switch jsonObject { 416 | case _ as Dictionary: 417 | print("Call api error,object json use api Model.json(json)") 418 | return nil 419 | case _ as [Any]: 420 | return [Element].sexy_json(jsonObject) 421 | default: 422 | print("Call api error, json not nil") 423 | return nil 424 | } 425 | } 426 | default: 427 | print("Call api error, json not nil") 428 | return nil 429 | } 430 | } 431 | return [Element].sexy_json(json) 432 | } 433 | return nil 434 | } 435 | 436 | //MARK: - model -> json - 437 | 438 | 439 | /// [Model]数组-> json string 440 | /// 441 | /// - Parameter format: 格式化json 442 | /// - Returns: json string 443 | func sexy_json(format: Bool = false) -> String? { 444 | if let map = self.sexy_array() { 445 | if JSONSerialization.isValidJSONObject(map) { 446 | do { 447 | let jsonData = try JSONSerialization.data(withJSONObject: map, options: format ? .prettyPrinted : []) 448 | return String(data: jsonData, encoding: .utf8) 449 | }catch let error { 450 | print("SexyJson: error \(error)") 451 | } 452 | }else { 453 | print("SexyJson: error invalid json map") 454 | } 455 | return nil 456 | } 457 | return nil 458 | } 459 | 460 | /// [Model]数组-> [json] 461 | /// 462 | /// - Returns: [json] 463 | func sexy_array() -> [Any]? { 464 | return self.sexyToValue() as? [Any] 465 | } 466 | } 467 | -------------------------------------------------------------------------------- /SexyJsonKit/SexyJsonOperation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SexyJsonOperation.swift 3 | // SexyJson 4 | // 5 | // Created by WHC on 17/5/14. 6 | // Copyright © 2017年 WHC. All rights reserved. 7 | // 8 | // Github 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | import Foundation 28 | 29 | infix operator <<< 30 | 31 | //MARK: - SexyJsonBasicType - 32 | 33 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 34 | public func <<< (left: inout T!, right: Any?) -> Void { 35 | left = T.sexyTransform(right) 36 | } 37 | #endif 38 | 39 | public func <<< (left: inout T?, right: Any?) -> Void { 40 | left = T.sexyTransform(right) 41 | } 42 | 43 | public func <<< (left: inout T, right: Any?) -> Void { 44 | if let value = T.sexyTransform(right) { 45 | left = value 46 | } 47 | } 48 | 49 | //MARK: - SexyJsonEnumType - 50 | 51 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 52 | public func <<< (left: inout T!, right: Any?) -> Void { 53 | left = T.sexyTransform(right) 54 | } 55 | #endif 56 | 57 | public func <<< (left: inout T?, right: Any?) -> Void { 58 | left = T.sexyTransform(right) 59 | } 60 | 61 | public func <<< (left: inout T, right: Any?) -> Void { 62 | if let value = T.sexyTransform(right) { 63 | left = value 64 | } 65 | } 66 | 67 | //MARK: - SexyJsonObjectType - 68 | 69 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 70 | public func <<< (left: inout T!, right: Any?) -> Void { 71 | left = T._sexyTransform(right) as? T 72 | } 73 | #endif 74 | 75 | public func <<< (left: inout T?, right: Any?) -> Void { 76 | left = T._sexyTransform(right) as? T 77 | } 78 | 79 | public func <<< (left: inout T, right: Any?) -> Void { 80 | if let value = T._sexyTransform(right) as? T { 81 | left = value 82 | } 83 | } 84 | 85 | 86 | //MARK: - SexyJson - 87 | 88 | public func <<< (left: inout T?, right: Any?) -> Void { 89 | if let rightMap = right as? [String: Any] { 90 | left = T.init() 91 | left!.sexyMap(rightMap) 92 | } 93 | } 94 | 95 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 96 | public func <<< (left: inout T!, right: Any?) -> Void { 97 | if let rightMap = right as? [String: Any] { 98 | left = T.init() 99 | left.sexyMap(rightMap) 100 | } 101 | } 102 | #endif 103 | 104 | public func <<< (left: inout T, right: Any?) -> Void { 105 | if let rightMap = right as? [String: Any] { 106 | left.sexyMap(rightMap) 107 | } 108 | } 109 | 110 | //MARK: - [SexyJsonBasicType] - 111 | public func <<< (left: inout [T]?, right: Any?) -> Void { 112 | if right != nil { 113 | left = [T].init() 114 | left! <<< right 115 | } 116 | } 117 | 118 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 119 | public func <<< (left: inout [T]!, right: Any?) -> Void { 120 | if right != nil { 121 | left = [T].init() 122 | left! <<< right 123 | } 124 | } 125 | #endif 126 | 127 | public func <<< (left: inout [T], right: Any?) -> Void { 128 | if let rightMap = right as? [Any] { 129 | rightMap.forEach({ (map) in 130 | left.append(T.sexyTransform(map)!) 131 | }) 132 | } 133 | } 134 | 135 | //MARK: - [SexyJsonEnumType] - 136 | 137 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 138 | public func <<< (left: inout [T]!, right: Any?) -> Void { 139 | if right != nil { 140 | left = [T].init() 141 | left! <<< right 142 | } 143 | } 144 | 145 | #endif 146 | 147 | public func <<< (left: inout [T]?, right: Any?) -> Void { 148 | if right != nil { 149 | left = [T].init() 150 | left! <<< right 151 | } 152 | } 153 | 154 | public func <<< (left: inout [T], right: Any?) -> Void { 155 | if let rightMap = right as? [Any] { 156 | rightMap.forEach({ (map) in 157 | left.append(T.sexyTransform(map)!) 158 | }) 159 | } 160 | } 161 | 162 | //MARK: - [SexyJsonObjectType] - 163 | 164 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 165 | public func <<< (left: inout [T]!, right: Any?) -> Void { 166 | if right != nil { 167 | left = [T].init() 168 | left! <<< right 169 | } 170 | } 171 | 172 | #endif 173 | 174 | public func <<< (left: inout [T]?, right: Any?) -> Void { 175 | if right != nil { 176 | left = [T].init() 177 | left! <<< right 178 | } 179 | } 180 | 181 | public func <<< (left: inout [T], right: Any?) -> Void { 182 | if let rightMap = right as? [Any] { 183 | rightMap.forEach({ (map) in 184 | if let value = T._sexyTransform(map) as? T { 185 | left.append(value) 186 | } 187 | }) 188 | } 189 | } 190 | 191 | //MARK: - [SexyJson] - 192 | 193 | public func <<< (left: inout [T]?, right: Any?) -> Void { 194 | if right != nil { 195 | left = [T].init() 196 | left! <<< right 197 | } 198 | } 199 | 200 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 201 | public func <<< (left: inout [T]!, right: Any?) -> Void { 202 | if right != nil { 203 | left = [T].init() 204 | left! <<< right 205 | } 206 | } 207 | #endif 208 | 209 | public func <<< (left: inout [T], right: Any?) -> Void { 210 | if let rightMap = right as? [Any] { 211 | rightMap.forEach({ (map) in 212 | if let elementMap = map as? [String : Any] { 213 | var element = T.init() 214 | element.sexyMap(elementMap) 215 | left.append(element) 216 | } 217 | }) 218 | } 219 | } 220 | 221 | -------------------------------------------------------------------------------- /SexyJsonKit/SexyJsonProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SexyJsonProtocol.swift 3 | // SexyJson 4 | // 5 | // Created by WHC on 17/5/14. 6 | // Copyright © 2017年 WHC. All rights reserved. 7 | // 8 | // Github 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #if os(iOS) || os(tvOS) || os(watchOS) 28 | import UIKit 29 | #else 30 | import AppKit 31 | #endif 32 | 33 | #if os(iOS) || os(tvOS) || os(watchOS) 34 | public typealias SexyColor = UIColor 35 | #else 36 | public typealias SexyColor = NSColor 37 | #endif 38 | 39 | //MARK: - Public protocol - 40 | 41 | public protocol _SexyJsonBase { 42 | func sexyToValue() -> Any? 43 | } 44 | 45 | public protocol _SexyJsonInitBase: _SexyJsonBase { 46 | init() 47 | } 48 | 49 | public protocol _SexyJsonBasicType: _SexyJsonBase { 50 | static func sexyTransform(_ value: Any?) -> Self? 51 | } 52 | 53 | public protocol _SexyJsonObjectType: _SexyJsonInitBase {} 54 | public protocol SexyJsonBasicType: _SexyJsonBasicType{} 55 | public protocol SexyJsonCollectionType: _SexyJsonBasicType{} 56 | public protocol SexyJsonEnumType: SexyJsonBasicType{} 57 | public protocol SexyJsonObjectType: _SexyJsonObjectType { 58 | static func _sexyTransform(_ value: Any?) -> Any? 59 | } 60 | 61 | public protocol SexyJson: _SexyJsonInitBase { 62 | mutating func sexyMap(_ map: [String : Any]) -> Void 63 | } 64 | 65 | 66 | public extension SexyJson { 67 | func sexyToValue() -> Any? { 68 | let mirror = Mirror(reflecting: self) 69 | var jsonMap = [String: Any]() 70 | var children = [(label: String?, value: Any)]() 71 | let mirrorChildrenCollection = AnyRandomAccessCollection(mirror.children)! 72 | children += mirrorChildrenCollection 73 | var currentMirror = mirror 74 | while let superclassChildren = currentMirror.superclassMirror?.children { 75 | let randomCollection = AnyRandomAccessCollection(superclassChildren)! 76 | children += randomCollection 77 | currentMirror = currentMirror.superclassMirror! 78 | } 79 | children.enumerated().forEach({ (index, element) in 80 | if let key = element.label, !key.isEmpty { 81 | if let value = (element.value as? _SexyJsonBase)?.sexyToValue() { 82 | jsonMap[key] = value 83 | } 84 | } 85 | }) 86 | return jsonMap 87 | } 88 | } 89 | 90 | #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) 91 | extension ImplicitlyUnwrappedOptional: _SexyJsonBase { 92 | public func sexyToValue() -> Any? { 93 | return self == nil ? nil : (self! as? _SexyJsonBase)?.sexyToValue() 94 | } 95 | } 96 | #endif 97 | 98 | extension Optional: _SexyJsonBase { 99 | 100 | public func sexyToValue() -> Any? { 101 | return self == nil ? nil : (self! as? _SexyJsonBase)?.sexyToValue() 102 | } 103 | } 104 | 105 | //MARK: - Internal protocol - 106 | 107 | public protocol SexyJsonBoolType:SexyJsonBasicType {} 108 | 109 | extension SexyJsonBoolType { 110 | public static func sexyTransform(_ object: Any?) -> Bool? { 111 | switch object { 112 | case let str as NSString: 113 | let lowerCase = str.lowercased 114 | if ["0", "false"].contains(lowerCase) { 115 | return false 116 | } 117 | if ["1", "true"].contains(lowerCase) { 118 | return true 119 | } 120 | return false 121 | case let num as NSNumber: 122 | return num.boolValue 123 | default: 124 | return false 125 | } 126 | } 127 | 128 | public func sexyToValue() -> Any? { 129 | return self 130 | } 131 | } 132 | 133 | public protocol SexyJsonFloatType:SexyJsonBasicType, LosslessStringConvertible { 134 | init(_ number: NSNumber) 135 | } 136 | 137 | extension SexyJsonFloatType { 138 | public static func sexyTransform(_ value: Any?) -> Self? { 139 | switch value { 140 | case let str as String: 141 | return Self(str) 142 | case let num as NSNumber: 143 | return Self(num) 144 | default: 145 | return Self(0.0) 146 | } 147 | } 148 | 149 | public func sexyToValue() -> Any? { 150 | return self 151 | } 152 | } 153 | 154 | public protocol SexyJsonIntType:SexyJsonBasicType, BinaryInteger { 155 | init?(_ text: String, radix: Int) 156 | init(_ number: NSNumber) 157 | } 158 | 159 | extension SexyJsonIntType { 160 | public static func sexyTransform(_ value: Any?) -> Self? { 161 | switch value { 162 | case let str as String: 163 | return Self(str, radix: 10) 164 | case let num as NSNumber: 165 | return Self(num) 166 | default: 167 | return Self(0) 168 | } 169 | } 170 | 171 | public func sexyToValue() -> Any? { 172 | return self 173 | } 174 | } 175 | 176 | public protocol SexyJsonCGFloatType: SexyJsonBasicType { 177 | 178 | } 179 | extension SexyJsonCGFloatType { 180 | public static func sexyTransform(_ value: Any?) -> CGFloat? { 181 | switch value { 182 | case let str as String: 183 | return CGFloat((str as NSString).floatValue) 184 | case let num as NSNumber: 185 | return CGFloat(num.floatValue) 186 | default: 187 | return 0 188 | } 189 | } 190 | 191 | public func sexyToValue() -> Any? { 192 | return self 193 | } 194 | 195 | } 196 | 197 | extension CGFloat: SexyJsonCGFloatType {} 198 | extension Bool: SexyJsonBoolType {} 199 | extension Float: SexyJsonFloatType {} 200 | extension Double: SexyJsonFloatType {} 201 | extension Int: SexyJsonIntType {} 202 | extension UInt: SexyJsonIntType {} 203 | extension Int8: SexyJsonIntType {} 204 | extension Int16: SexyJsonIntType {} 205 | extension Int32: SexyJsonIntType {} 206 | extension Int64: SexyJsonIntType {} 207 | extension UInt8: SexyJsonIntType {} 208 | extension UInt16: SexyJsonIntType {} 209 | extension UInt32: SexyJsonIntType {} 210 | extension UInt64: SexyJsonIntType {} 211 | 212 | extension NSNumber: SexyJsonObjectType { 213 | public static func _sexyTransform(_ value: Any?) -> Any? { 214 | switch value { 215 | case let str as String: 216 | return NSNumber(value: (str as NSString).floatValue) 217 | case let num as NSNumber: 218 | return num 219 | default: 220 | return NSNumber(value: 0) 221 | } 222 | } 223 | 224 | public func sexyToValue() -> Any? { 225 | return self 226 | } 227 | } 228 | 229 | extension String: SexyJsonBasicType { 230 | public static func sexyTransform(_ value: Any?) -> String? { 231 | switch value { 232 | case let str as String: 233 | return str 234 | case let num as NSNumber: 235 | if NSStringFromClass(type(of: num)) == "__NSCFBoolean" { 236 | if num.boolValue { 237 | return "true" 238 | } 239 | return "false" 240 | } 241 | return num.stringValue 242 | default: 243 | if let vl = value { 244 | switch vl { 245 | case nil, is NSNull: 246 | return nil 247 | default: 248 | return "\(vl)" 249 | } 250 | } 251 | return nil 252 | } 253 | } 254 | 255 | public func sexyToValue() -> Any? { 256 | return self 257 | } 258 | } 259 | 260 | extension NSString: SexyJsonObjectType { 261 | public static func _sexyTransform(_ value: Any?) -> Any? { 262 | if let str = String.sexyTransform(value) { 263 | return NSString(string: str) 264 | } 265 | return nil 266 | } 267 | 268 | public func sexyToValue() -> Any? { 269 | return self 270 | } 271 | } 272 | 273 | extension Array: SexyJsonCollectionType { 274 | public static func sexyTransform(_ value: Any?) -> [Element]? { 275 | guard let array = value as? NSArray else { 276 | print("SexyJson: Expect value not NSArray") 277 | return nil 278 | } 279 | typealias Element = Iterator.Element 280 | var result: [Element] = [Element]() 281 | array.forEach { (each) in 282 | if let element = (Element.self as? _SexyJsonBasicType.Type)?.sexyTransform(each) as? Element { 283 | result.append(element) 284 | }else if let element = (Element.self as? SexyJsonObjectType.Type)?._sexyTransform(each) as? Element { 285 | result.append(element) 286 | }else if let element = (Element.self as? SexyJson.Type)?.sexy_json(each) as? Element { 287 | result.append(element) 288 | }else if let element = each as? Element { 289 | result.append(element) 290 | } 291 | } 292 | return result 293 | } 294 | 295 | public func sexyToValue() -> Any? { 296 | var jsonArray = [Any]() 297 | self.forEach { (element) in 298 | if let value = (element as? _SexyJsonBase)?.sexyToValue() { 299 | jsonArray.append(value) 300 | } 301 | } 302 | return jsonArray 303 | } 304 | } 305 | 306 | extension Set: SexyJsonCollectionType { 307 | public static func sexyTransform(_ value: Any?) -> Set? { 308 | guard let array = value as? NSArray else { 309 | print("SexyJson: Expect value not NSArray") 310 | return nil 311 | } 312 | typealias Element = Iterator.Element 313 | var result = Set() 314 | array.forEach { (each) in 315 | if let element = (Element.self as? _SexyJsonBasicType.Type)?.sexyTransform(each) as? Element { 316 | result.insert(element) 317 | }else if let element = (Element.self as? SexyJsonObjectType.Type)?._sexyTransform(each) as? Element { 318 | result.insert(element) 319 | }else if let element = (Element.self as? SexyJson.Type)?.sexy_json(each) as? Element { 320 | result.insert(element) 321 | }else if let element = each as? Element { 322 | result.insert(element) 323 | } 324 | } 325 | return result 326 | } 327 | 328 | public func sexyToValue() -> Any? { 329 | var jsonArray = [Any]() 330 | self.forEach { (element) in 331 | if let value = (element as? _SexyJsonBase)?.sexyToValue() { 332 | jsonArray.append(value) 333 | } 334 | } 335 | return jsonArray 336 | } 337 | } 338 | 339 | extension Dictionary: SexyJsonCollectionType { 340 | public static func sexyTransform(_ value: Any?) -> Dictionary? { 341 | guard let nsDict = value as? NSDictionary else { 342 | print("SexyJson: Expect value not NSDictionary") 343 | return nil 344 | } 345 | var result: [Key: Value] = [Key: Value]() 346 | for (key, value) in nsDict { 347 | if let sKey = key as? Key, let nsValue = value as? NSObject { 348 | if let nValue = (Value.self as? _SexyJsonBasicType.Type)?.sexyTransform(nsValue) as? Value { 349 | result[sKey] = nValue 350 | }else if let nValue = (Value.self as? SexyJsonObjectType.Type)?._sexyTransform(nsValue) as? Value { 351 | result[sKey] = nValue 352 | }else if let nValue = (Value.self as? SexyJson.Type)?.sexy_json(nsValue) as? Value { 353 | result[sKey] = nValue 354 | }else if let nValue = nsValue as? Value { 355 | result[sKey] = nValue 356 | } 357 | } 358 | } 359 | return result 360 | } 361 | 362 | public func sexyToValue() -> Any? { 363 | var jsonMap = [String: Any]() 364 | self.forEach { (key,value) in 365 | if let val = (value as? _SexyJsonBase)?.sexyToValue() { 366 | jsonMap[key as! String] = val 367 | } 368 | } 369 | return jsonMap 370 | } 371 | } 372 | 373 | public extension RawRepresentable where Self: SexyJsonEnumType { 374 | static func sexyTransform(_ value: Any?) -> Self? { 375 | if let transforType = RawValue.self as? SexyJsonBasicType.Type { 376 | if let typedValue = transforType.sexyTransform(value) { 377 | return Self(rawValue: typedValue as! RawValue) 378 | } 379 | } 380 | return nil 381 | } 382 | 383 | func sexyToValue() -> Any? { 384 | return self.rawValue 385 | } 386 | } 387 | 388 | extension NSData: SexyJsonObjectType { 389 | public static func _sexyTransform(_ value: Any?) -> Any? { 390 | return Data.sexyTransform(value) 391 | } 392 | 393 | public func sexyToValue() -> Any? { 394 | return (self as Data).sexyToValue() 395 | } 396 | } 397 | 398 | extension Data: SexyJsonBasicType { 399 | public static func sexyTransform(_ value: Any?) -> Data? { 400 | switch value { 401 | case let num as NSNumber: 402 | return num.stringValue.data(using: .utf8) 403 | case let str as NSString: 404 | return str.data(using: String.Encoding.utf8.rawValue) 405 | case let data as NSData: 406 | return data as Data 407 | default: 408 | return nil 409 | } 410 | } 411 | 412 | public func sexyToValue() -> Any? { 413 | return String(data: self, encoding: .utf8) 414 | } 415 | } 416 | 417 | extension NSDate: SexyJsonObjectType { 418 | public static func _sexyTransform(_ value: Any?) -> Any? { 419 | return Date.sexyTransform(value) 420 | } 421 | 422 | public func sexyToValue() -> Any? { 423 | return (self as Date).sexyToValue() 424 | } 425 | } 426 | 427 | extension Date: SexyJsonBasicType { 428 | public static func sexyTransform(_ value: Any?) -> Date? { 429 | switch value { 430 | case let num as NSNumber: 431 | return Date(timeIntervalSince1970: num.doubleValue) 432 | case let str as NSString: 433 | return Date(timeIntervalSince1970: TimeInterval(atof(str as String))) 434 | default: 435 | return nil 436 | } 437 | } 438 | 439 | public func sexyToValue() -> Any? { 440 | let formatter = DateFormatter() 441 | formatter.locale = Locale(identifier: "en_US_POSIX") 442 | formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" 443 | return formatter.string(from: self) 444 | } 445 | } 446 | 447 | extension NSURL: SexyJsonObjectType { 448 | public static func _sexyTransform(_ value: Any?) -> Any? { 449 | return URL.sexyTransform(value) 450 | } 451 | 452 | public func sexyToValue() -> Any? { 453 | return self.absoluteString 454 | } 455 | } 456 | 457 | extension URL: SexyJsonBasicType { 458 | public static func sexyTransform(_ value: Any?) -> URL? { 459 | switch value { 460 | case let str as NSString: 461 | return URL(string: str as String) 462 | default: 463 | return nil 464 | } 465 | } 466 | 467 | public func sexyToValue() -> Any? { 468 | return self.absoluteString 469 | } 470 | } 471 | 472 | extension SexyColor: SexyJsonObjectType { 473 | 474 | fileprivate func colorString() -> String { 475 | let comps = self.cgColor.components! 476 | let r = Int(comps[0] * 255) 477 | let g = Int(comps[1] * 255) 478 | let b = Int(comps[2] * 255) 479 | let a = Int(comps[3] * 255) 480 | var hexString: String = "#" 481 | hexString += String(format: "%02X%02X%02X", r, g, b) 482 | hexString += String(format: "%02X", a) 483 | return hexString 484 | } 485 | 486 | fileprivate static func getColor(hex: String) -> SexyColor? { 487 | var red: CGFloat = 0.0 488 | var green: CGFloat = 0.0 489 | var blue: CGFloat = 0.0 490 | var alpha: CGFloat = 1.0 491 | 492 | let scanner = Scanner(string: hex) 493 | var hexValue: CUnsignedLongLong = 0 494 | if scanner.scanHexInt64(&hexValue) { 495 | switch (hex.count) { 496 | case 3: 497 | red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 498 | green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 499 | blue = CGFloat(hexValue & 0x00F) / 15.0 500 | case 4: 501 | red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 502 | green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 503 | blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 504 | alpha = CGFloat(hexValue & 0x000F) / 15.0 505 | case 6: 506 | red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 507 | green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 508 | blue = CGFloat(hexValue & 0x0000FF) / 255.0 509 | case 8: 510 | red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 511 | green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 512 | blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 513 | alpha = CGFloat(hexValue & 0x000000FF) / 255.0 514 | default: 515 | // Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8 516 | return nil 517 | } 518 | } else { 519 | // "Scan hex error 520 | return nil 521 | } 522 | #if os(iOS) || os(tvOS) || os(watchOS) 523 | return UIColor(red: red, green: green, blue: blue, alpha: alpha) 524 | #else 525 | return NSColor(calibratedRed: red, green: green, blue: blue, alpha: alpha) 526 | #endif 527 | } 528 | 529 | public static func _sexyTransform(_ value: Any?) -> Any? { 530 | switch value { 531 | case let str as String: 532 | return getColor(hex: str) 533 | default: 534 | return nil 535 | } 536 | } 537 | 538 | public func sexyToValue() -> Any? { 539 | return colorString() 540 | } 541 | } 542 | --------------------------------------------------------------------------------