├── .gitignore ├── ESJsonFormat.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── ESJsonFormat.xcscheme ├── ESJsonFormat ├── Category │ ├── NSObject_Extension.h │ ├── NSObject_Extension.m │ ├── NSString+ESExtension.h │ └── NSString+ESExtension.m ├── Controller │ ├── ESDialogController.h │ ├── ESDialogController.m │ ├── ESDialogController.xib │ ├── ESInputJsonController.h │ ├── ESInputJsonController.m │ ├── ESInputJsonController.xib │ ├── ESSettingController.h │ ├── ESSettingController.m │ └── ESSettingController.xib ├── DataModelsTemplate.txt ├── ESJsonFormat-Prefix.pch ├── ESJsonFormat.h ├── ESJsonFormat.m ├── ESJsonFormatManager.h ├── ESJsonFormatManager.m ├── Info.plist ├── Model │ ├── ESClassInfo.h │ ├── ESClassInfo.m │ ├── ESFormatInfo.h │ ├── ESFormatInfo.m │ ├── ESPair.h │ ├── ESPair.m │ ├── ESPbxprojInfo.h │ └── ESPbxprojInfo.m ├── Setting │ ├── ESJsonFormatSetting.h │ └── ESJsonFormatSetting.m └── Utils │ ├── ESUtils.h │ └── ESUtils.m ├── LICENSE ├── README.md ├── ScreenShot ├── ScreenShot1.png ├── ScreenShot2.gif ├── ScreenShot3.gif ├── ScreenShot4.jpeg ├── ScreenShot5.gif ├── ScreenShot6.gif ├── ScreenShot7.gif └── Setting.png └── plugin └── ESJsonFormat.xcplugin.zip /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | -------------------------------------------------------------------------------- /ESJsonFormat.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4F6FB4EA1B4967420023406F /* ESPair.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F6FB4E91B4967420023406F /* ESPair.m */; }; 11 | 4FA2FE6C1B5E54B8006F9974 /* DataModelsTemplate.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4FA2FE6B1B5E54B8006F9974 /* DataModelsTemplate.txt */; }; 12 | 4FB2DAA11B5BD84E000D5DA9 /* ESSettingController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FB2DA9F1B5BD84E000D5DA9 /* ESSettingController.m */; }; 13 | 4FB2DAA21B5BD84E000D5DA9 /* ESSettingController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4FB2DAA01B5BD84E000D5DA9 /* ESSettingController.xib */; }; 14 | 4FB2DAA61B5BDC53000D5DA9 /* ESJsonFormatSetting.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FB2DAA51B5BDC53000D5DA9 /* ESJsonFormatSetting.m */; }; 15 | 4FC82A491B520D9D00B4239F /* ESUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FC82A481B520D9D00B4239F /* ESUtils.m */; }; 16 | 4FDBA00D1B47BA8E00FAEBE9 /* NSString+ESExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FDBA00C1B47BA8E00FAEBE9 /* NSString+ESExtension.m */; }; 17 | 4FF8F33E1B400F8B005C73C2 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FF8F33D1B400F8B005C73C2 /* AppKit.framework */; }; 18 | 4FF8F3401B400F8B005C73C2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FF8F33F1B400F8B005C73C2 /* Foundation.framework */; }; 19 | 4FF8F3451B400F8B005C73C2 /* ESJsonFormat.xcscheme in Resources */ = {isa = PBXBuildFile; fileRef = 4FF8F3441B400F8B005C73C2 /* ESJsonFormat.xcscheme */; }; 20 | 4FF8F3481B400F8B005C73C2 /* ESJsonFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF8F3471B400F8B005C73C2 /* ESJsonFormat.m */; }; 21 | 4FF8F3581B40100C005C73C2 /* ESDialogController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF8F3531B40100C005C73C2 /* ESDialogController.m */; }; 22 | 4FF8F3591B40100C005C73C2 /* ESDialogController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4FF8F3541B40100C005C73C2 /* ESDialogController.xib */; }; 23 | 4FF8F35A1B40100C005C73C2 /* ESInputJsonController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF8F3561B40100C005C73C2 /* ESInputJsonController.m */; }; 24 | 4FF8F35B1B40100C005C73C2 /* ESInputJsonController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4FF8F3571B40100C005C73C2 /* ESInputJsonController.xib */; }; 25 | 4FF8F3681B401233005C73C2 /* ESClassInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF8F3671B401233005C73C2 /* ESClassInfo.m */; }; 26 | 4FF8F36B1B4012DC005C73C2 /* ESJsonFormatManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF8F36A1B4012DC005C73C2 /* ESJsonFormatManager.m */; }; 27 | 4FF8F36E1B401368005C73C2 /* ESFormatInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF8F36D1B401368005C73C2 /* ESFormatInfo.m */; }; 28 | 4FF8F3721B401487005C73C2 /* NSObject_Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF8F3711B401487005C73C2 /* NSObject_Extension.m */; }; 29 | 4FF8F3751B4014AB005C73C2 /* ESPbxprojInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FF8F3741B4014AB005C73C2 /* ESPbxprojInfo.m */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 4F6FB4E81B4967420023406F /* ESPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESPair.h; sourceTree = ""; }; 34 | 4F6FB4E91B4967420023406F /* ESPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESPair.m; sourceTree = ""; }; 35 | 4FA2FE6B1B5E54B8006F9974 /* DataModelsTemplate.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DataModelsTemplate.txt; sourceTree = ""; }; 36 | 4FB2DA9E1B5BD84E000D5DA9 /* ESSettingController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ESSettingController.h; path = ../Controller/ESSettingController.h; sourceTree = ""; }; 37 | 4FB2DA9F1B5BD84E000D5DA9 /* ESSettingController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ESSettingController.m; path = ../Controller/ESSettingController.m; sourceTree = ""; }; 38 | 4FB2DAA01B5BD84E000D5DA9 /* ESSettingController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ESSettingController.xib; path = ../Controller/ESSettingController.xib; sourceTree = ""; }; 39 | 4FB2DAA41B5BDC53000D5DA9 /* ESJsonFormatSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESJsonFormatSetting.h; sourceTree = ""; }; 40 | 4FB2DAA51B5BDC53000D5DA9 /* ESJsonFormatSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESJsonFormatSetting.m; sourceTree = ""; }; 41 | 4FC82A471B520D9D00B4239F /* ESUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESUtils.h; sourceTree = ""; }; 42 | 4FC82A481B520D9D00B4239F /* ESUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESUtils.m; sourceTree = ""; }; 43 | 4FDBA00B1B47BA8E00FAEBE9 /* NSString+ESExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+ESExtension.h"; sourceTree = ""; }; 44 | 4FDBA00C1B47BA8E00FAEBE9 /* NSString+ESExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+ESExtension.m"; sourceTree = ""; }; 45 | 4FF8F33A1B400F8B005C73C2 /* ESJsonFormat.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ESJsonFormat.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 4FF8F33D1B400F8B005C73C2 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 47 | 4FF8F33F1B400F8B005C73C2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 48 | 4FF8F3431B400F8B005C73C2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | 4FF8F3441B400F8B005C73C2 /* ESJsonFormat.xcscheme */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = ESJsonFormat.xcscheme; path = ESJsonFormat.xcodeproj/xcshareddata/xcschemes/ESJsonFormat.xcscheme; sourceTree = SOURCE_ROOT; }; 50 | 4FF8F3461B400F8B005C73C2 /* ESJsonFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ESJsonFormat.h; sourceTree = ""; }; 51 | 4FF8F3471B400F8B005C73C2 /* ESJsonFormat.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ESJsonFormat.m; sourceTree = ""; }; 52 | 4FF8F3521B40100C005C73C2 /* ESDialogController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESDialogController.h; sourceTree = ""; }; 53 | 4FF8F3531B40100C005C73C2 /* ESDialogController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESDialogController.m; sourceTree = ""; }; 54 | 4FF8F3541B40100C005C73C2 /* ESDialogController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ESDialogController.xib; sourceTree = ""; }; 55 | 4FF8F3551B40100C005C73C2 /* ESInputJsonController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESInputJsonController.h; sourceTree = ""; }; 56 | 4FF8F3561B40100C005C73C2 /* ESInputJsonController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESInputJsonController.m; sourceTree = ""; }; 57 | 4FF8F3571B40100C005C73C2 /* ESInputJsonController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ESInputJsonController.xib; sourceTree = ""; }; 58 | 4FF8F3661B401233005C73C2 /* ESClassInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESClassInfo.h; sourceTree = ""; }; 59 | 4FF8F3671B401233005C73C2 /* ESClassInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESClassInfo.m; sourceTree = ""; }; 60 | 4FF8F3691B4012DC005C73C2 /* ESJsonFormatManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESJsonFormatManager.h; sourceTree = ""; }; 61 | 4FF8F36A1B4012DC005C73C2 /* ESJsonFormatManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESJsonFormatManager.m; sourceTree = ""; }; 62 | 4FF8F36C1B401368005C73C2 /* ESFormatInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESFormatInfo.h; sourceTree = ""; }; 63 | 4FF8F36D1B401368005C73C2 /* ESFormatInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESFormatInfo.m; sourceTree = ""; }; 64 | 4FF8F3701B401487005C73C2 /* NSObject_Extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSObject_Extension.h; sourceTree = ""; }; 65 | 4FF8F3711B401487005C73C2 /* NSObject_Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObject_Extension.m; sourceTree = ""; }; 66 | 4FF8F3731B4014AB005C73C2 /* ESPbxprojInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ESPbxprojInfo.h; sourceTree = ""; }; 67 | 4FF8F3741B4014AB005C73C2 /* ESPbxprojInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ESPbxprojInfo.m; sourceTree = ""; }; 68 | 4FF8F3761B401914005C73C2 /* ESJsonFormat-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ESJsonFormat-Prefix.pch"; sourceTree = ""; }; 69 | /* End PBXFileReference section */ 70 | 71 | /* Begin PBXFrameworksBuildPhase section */ 72 | 4FF8F3381B400F8B005C73C2 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | 4FF8F33E1B400F8B005C73C2 /* AppKit.framework in Frameworks */, 77 | 4FF8F3401B400F8B005C73C2 /* Foundation.framework in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 4FB2DAA31B5BDC06000D5DA9 /* Setting */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 4FB2DA9E1B5BD84E000D5DA9 /* ESSettingController.h */, 88 | 4FB2DA9F1B5BD84E000D5DA9 /* ESSettingController.m */, 89 | 4FB2DAA01B5BD84E000D5DA9 /* ESSettingController.xib */, 90 | 4FB2DAA41B5BDC53000D5DA9 /* ESJsonFormatSetting.h */, 91 | 4FB2DAA51B5BDC53000D5DA9 /* ESJsonFormatSetting.m */, 92 | ); 93 | path = Setting; 94 | sourceTree = ""; 95 | }; 96 | 4FC82A461B520D8F00B4239F /* Utils */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 4FC82A471B520D9D00B4239F /* ESUtils.h */, 100 | 4FC82A481B520D9D00B4239F /* ESUtils.m */, 101 | ); 102 | path = Utils; 103 | sourceTree = ""; 104 | }; 105 | 4FF8F3311B400F8B005C73C2 = { 106 | isa = PBXGroup; 107 | children = ( 108 | 4FF8F3411B400F8B005C73C2 /* ESJsonFormat */, 109 | 4FF8F33C1B400F8B005C73C2 /* Frameworks */, 110 | 4FF8F33B1B400F8B005C73C2 /* Products */, 111 | ); 112 | sourceTree = ""; 113 | }; 114 | 4FF8F33B1B400F8B005C73C2 /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 4FF8F33A1B400F8B005C73C2 /* ESJsonFormat.xcplugin */, 118 | ); 119 | name = Products; 120 | sourceTree = ""; 121 | }; 122 | 4FF8F33C1B400F8B005C73C2 /* Frameworks */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 4FF8F33D1B400F8B005C73C2 /* AppKit.framework */, 126 | 4FF8F33F1B400F8B005C73C2 /* Foundation.framework */, 127 | ); 128 | name = Frameworks; 129 | sourceTree = ""; 130 | }; 131 | 4FF8F3411B400F8B005C73C2 /* ESJsonFormat */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 4FB2DAA31B5BDC06000D5DA9 /* Setting */, 135 | 4FC82A461B520D8F00B4239F /* Utils */, 136 | 4FF8F36F1B401487005C73C2 /* Category */, 137 | 4FF8F3511B40100C005C73C2 /* Controller */, 138 | 4FF8F35C1B401014005C73C2 /* Model */, 139 | 4FF8F3461B400F8B005C73C2 /* ESJsonFormat.h */, 140 | 4FF8F3471B400F8B005C73C2 /* ESJsonFormat.m */, 141 | 4FF8F3691B4012DC005C73C2 /* ESJsonFormatManager.h */, 142 | 4FF8F36A1B4012DC005C73C2 /* ESJsonFormatManager.m */, 143 | 4FF8F3421B400F8B005C73C2 /* Supporting Files */, 144 | ); 145 | path = ESJsonFormat; 146 | sourceTree = ""; 147 | }; 148 | 4FF8F3421B400F8B005C73C2 /* Supporting Files */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 4FA2FE6B1B5E54B8006F9974 /* DataModelsTemplate.txt */, 152 | 4FF8F3431B400F8B005C73C2 /* Info.plist */, 153 | 4FF8F3441B400F8B005C73C2 /* ESJsonFormat.xcscheme */, 154 | 4FF8F3761B401914005C73C2 /* ESJsonFormat-Prefix.pch */, 155 | ); 156 | name = "Supporting Files"; 157 | sourceTree = ""; 158 | }; 159 | 4FF8F3511B40100C005C73C2 /* Controller */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 4FF8F3521B40100C005C73C2 /* ESDialogController.h */, 163 | 4FF8F3531B40100C005C73C2 /* ESDialogController.m */, 164 | 4FF8F3541B40100C005C73C2 /* ESDialogController.xib */, 165 | 4FF8F3551B40100C005C73C2 /* ESInputJsonController.h */, 166 | 4FF8F3561B40100C005C73C2 /* ESInputJsonController.m */, 167 | 4FF8F3571B40100C005C73C2 /* ESInputJsonController.xib */, 168 | ); 169 | path = Controller; 170 | sourceTree = ""; 171 | }; 172 | 4FF8F35C1B401014005C73C2 /* Model */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 4FF8F3661B401233005C73C2 /* ESClassInfo.h */, 176 | 4FF8F3671B401233005C73C2 /* ESClassInfo.m */, 177 | 4FF8F36C1B401368005C73C2 /* ESFormatInfo.h */, 178 | 4FF8F36D1B401368005C73C2 /* ESFormatInfo.m */, 179 | 4FF8F3731B4014AB005C73C2 /* ESPbxprojInfo.h */, 180 | 4FF8F3741B4014AB005C73C2 /* ESPbxprojInfo.m */, 181 | 4F6FB4E81B4967420023406F /* ESPair.h */, 182 | 4F6FB4E91B4967420023406F /* ESPair.m */, 183 | ); 184 | path = Model; 185 | sourceTree = ""; 186 | }; 187 | 4FF8F36F1B401487005C73C2 /* Category */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 4FF8F3701B401487005C73C2 /* NSObject_Extension.h */, 191 | 4FF8F3711B401487005C73C2 /* NSObject_Extension.m */, 192 | 4FDBA00B1B47BA8E00FAEBE9 /* NSString+ESExtension.h */, 193 | 4FDBA00C1B47BA8E00FAEBE9 /* NSString+ESExtension.m */, 194 | ); 195 | path = Category; 196 | sourceTree = ""; 197 | }; 198 | /* End PBXGroup section */ 199 | 200 | /* Begin PBXNativeTarget section */ 201 | 4FF8F3391B400F8B005C73C2 /* ESJsonFormat */ = { 202 | isa = PBXNativeTarget; 203 | buildConfigurationList = 4FF8F34E1B400F8B005C73C2 /* Build configuration list for PBXNativeTarget "ESJsonFormat" */; 204 | buildPhases = ( 205 | 4FF8F3361B400F8B005C73C2 /* Sources */, 206 | 4FF8F3371B400F8B005C73C2 /* Resources */, 207 | 4FF8F3381B400F8B005C73C2 /* Frameworks */, 208 | ); 209 | buildRules = ( 210 | ); 211 | dependencies = ( 212 | ); 213 | name = ESJsonFormat; 214 | productName = ESJsonFormat; 215 | productReference = 4FF8F33A1B400F8B005C73C2 /* ESJsonFormat.xcplugin */; 216 | productType = "com.apple.product-type.bundle"; 217 | }; 218 | /* End PBXNativeTarget section */ 219 | 220 | /* Begin PBXProject section */ 221 | 4FF8F3321B400F8B005C73C2 /* Project object */ = { 222 | isa = PBXProject; 223 | attributes = { 224 | CLASSPREFIX = ES; 225 | LastUpgradeCheck = 0630; 226 | ORGANIZATIONNAME = EnjoySR; 227 | TargetAttributes = { 228 | 4FF8F3391B400F8B005C73C2 = { 229 | CreatedOnToolsVersion = 6.3.2; 230 | }; 231 | }; 232 | }; 233 | buildConfigurationList = 4FF8F3351B400F8B005C73C2 /* Build configuration list for PBXProject "ESJsonFormat" */; 234 | compatibilityVersion = "Xcode 3.2"; 235 | developmentRegion = English; 236 | hasScannedForEncodings = 0; 237 | knownRegions = ( 238 | en, 239 | ); 240 | mainGroup = 4FF8F3311B400F8B005C73C2; 241 | productRefGroup = 4FF8F33B1B400F8B005C73C2 /* Products */; 242 | projectDirPath = ""; 243 | projectRoot = ""; 244 | targets = ( 245 | 4FF8F3391B400F8B005C73C2 /* ESJsonFormat */, 246 | ); 247 | }; 248 | /* End PBXProject section */ 249 | 250 | /* Begin PBXResourcesBuildPhase section */ 251 | 4FF8F3371B400F8B005C73C2 /* Resources */ = { 252 | isa = PBXResourcesBuildPhase; 253 | buildActionMask = 2147483647; 254 | files = ( 255 | 4FF8F35B1B40100C005C73C2 /* ESInputJsonController.xib in Resources */, 256 | 4FA2FE6C1B5E54B8006F9974 /* DataModelsTemplate.txt in Resources */, 257 | 4FF8F3451B400F8B005C73C2 /* ESJsonFormat.xcscheme in Resources */, 258 | 4FB2DAA21B5BD84E000D5DA9 /* ESSettingController.xib in Resources */, 259 | 4FF8F3591B40100C005C73C2 /* ESDialogController.xib in Resources */, 260 | ); 261 | runOnlyForDeploymentPostprocessing = 0; 262 | }; 263 | /* End PBXResourcesBuildPhase section */ 264 | 265 | /* Begin PBXSourcesBuildPhase section */ 266 | 4FF8F3361B400F8B005C73C2 /* Sources */ = { 267 | isa = PBXSourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | 4FF8F3681B401233005C73C2 /* ESClassInfo.m in Sources */, 271 | 4FB2DAA61B5BDC53000D5DA9 /* ESJsonFormatSetting.m in Sources */, 272 | 4FF8F3481B400F8B005C73C2 /* ESJsonFormat.m in Sources */, 273 | 4FB2DAA11B5BD84E000D5DA9 /* ESSettingController.m in Sources */, 274 | 4FF8F36E1B401368005C73C2 /* ESFormatInfo.m in Sources */, 275 | 4F6FB4EA1B4967420023406F /* ESPair.m in Sources */, 276 | 4FF8F35A1B40100C005C73C2 /* ESInputJsonController.m in Sources */, 277 | 4FF8F3721B401487005C73C2 /* NSObject_Extension.m in Sources */, 278 | 4FC82A491B520D9D00B4239F /* ESUtils.m in Sources */, 279 | 4FF8F36B1B4012DC005C73C2 /* ESJsonFormatManager.m in Sources */, 280 | 4FF8F3581B40100C005C73C2 /* ESDialogController.m in Sources */, 281 | 4FF8F3751B4014AB005C73C2 /* ESPbxprojInfo.m in Sources */, 282 | 4FDBA00D1B47BA8E00FAEBE9 /* NSString+ESExtension.m in Sources */, 283 | ); 284 | runOnlyForDeploymentPostprocessing = 0; 285 | }; 286 | /* End PBXSourcesBuildPhase section */ 287 | 288 | /* Begin XCBuildConfiguration section */ 289 | 4FF8F34C1B400F8B005C73C2 /* Debug */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | ALWAYS_SEARCH_USER_PATHS = NO; 293 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 294 | CLANG_CXX_LIBRARY = "libc++"; 295 | CLANG_ENABLE_MODULES = YES; 296 | CLANG_ENABLE_OBJC_ARC = YES; 297 | CLANG_WARN_BOOL_CONVERSION = YES; 298 | CLANG_WARN_CONSTANT_CONVERSION = YES; 299 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 300 | CLANG_WARN_EMPTY_BODY = YES; 301 | CLANG_WARN_ENUM_CONVERSION = YES; 302 | CLANG_WARN_INT_CONVERSION = YES; 303 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 304 | CLANG_WARN_UNREACHABLE_CODE = YES; 305 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 306 | COPY_PHASE_STRIP = NO; 307 | ENABLE_STRICT_OBJC_MSGSEND = YES; 308 | GCC_C_LANGUAGE_STANDARD = gnu99; 309 | GCC_DYNAMIC_NO_PIC = NO; 310 | GCC_NO_COMMON_BLOCKS = YES; 311 | GCC_OPTIMIZATION_LEVEL = 0; 312 | GCC_PREPROCESSOR_DEFINITIONS = ( 313 | "DEBUG=1", 314 | "$(inherited)", 315 | ); 316 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 317 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 318 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 319 | GCC_WARN_UNDECLARED_SELECTOR = YES; 320 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 321 | GCC_WARN_UNUSED_FUNCTION = YES; 322 | GCC_WARN_UNUSED_VARIABLE = YES; 323 | MTL_ENABLE_DEBUG_INFO = YES; 324 | ONLY_ACTIVE_ARCH = YES; 325 | }; 326 | name = Debug; 327 | }; 328 | 4FF8F34D1B400F8B005C73C2 /* Release */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ALWAYS_SEARCH_USER_PATHS = NO; 332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 333 | CLANG_CXX_LIBRARY = "libc++"; 334 | CLANG_ENABLE_MODULES = YES; 335 | CLANG_ENABLE_OBJC_ARC = YES; 336 | CLANG_WARN_BOOL_CONVERSION = YES; 337 | CLANG_WARN_CONSTANT_CONVERSION = YES; 338 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 339 | CLANG_WARN_EMPTY_BODY = YES; 340 | CLANG_WARN_ENUM_CONVERSION = YES; 341 | CLANG_WARN_INT_CONVERSION = YES; 342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 343 | CLANG_WARN_UNREACHABLE_CODE = YES; 344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 345 | COPY_PHASE_STRIP = NO; 346 | ENABLE_NS_ASSERTIONS = NO; 347 | ENABLE_STRICT_OBJC_MSGSEND = YES; 348 | GCC_C_LANGUAGE_STANDARD = gnu99; 349 | GCC_NO_COMMON_BLOCKS = YES; 350 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 351 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 352 | GCC_WARN_UNDECLARED_SELECTOR = YES; 353 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 354 | GCC_WARN_UNUSED_FUNCTION = YES; 355 | GCC_WARN_UNUSED_VARIABLE = YES; 356 | MTL_ENABLE_DEBUG_INFO = NO; 357 | }; 358 | name = Release; 359 | }; 360 | 4FF8F34F1B400F8B005C73C2 /* Debug */ = { 361 | isa = XCBuildConfiguration; 362 | buildSettings = { 363 | COMBINE_HIDPI_IMAGES = YES; 364 | DEPLOYMENT_LOCATION = YES; 365 | DSTROOT = "$(HOME)"; 366 | GCC_PREFIX_HEADER = "ESJsonFormat/ESJsonFormat-Prefix.pch"; 367 | INFOPLIST_FILE = ESJsonFormat/Info.plist; 368 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 369 | MACOSX_DEPLOYMENT_TARGET = 10.10; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | WRAPPER_EXTENSION = xcplugin; 372 | }; 373 | name = Debug; 374 | }; 375 | 4FF8F3501B400F8B005C73C2 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | COMBINE_HIDPI_IMAGES = YES; 379 | DEPLOYMENT_LOCATION = YES; 380 | DSTROOT = "$(HOME)"; 381 | GCC_PREFIX_HEADER = "ESJsonFormat/ESJsonFormat-Prefix.pch"; 382 | INFOPLIST_FILE = ESJsonFormat/Info.plist; 383 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 384 | MACOSX_DEPLOYMENT_TARGET = 10.10; 385 | PRODUCT_NAME = "$(TARGET_NAME)"; 386 | WRAPPER_EXTENSION = xcplugin; 387 | }; 388 | name = Release; 389 | }; 390 | /* End XCBuildConfiguration section */ 391 | 392 | /* Begin XCConfigurationList section */ 393 | 4FF8F3351B400F8B005C73C2 /* Build configuration list for PBXProject "ESJsonFormat" */ = { 394 | isa = XCConfigurationList; 395 | buildConfigurations = ( 396 | 4FF8F34C1B400F8B005C73C2 /* Debug */, 397 | 4FF8F34D1B400F8B005C73C2 /* Release */, 398 | ); 399 | defaultConfigurationIsVisible = 0; 400 | defaultConfigurationName = Release; 401 | }; 402 | 4FF8F34E1B400F8B005C73C2 /* Build configuration list for PBXNativeTarget "ESJsonFormat" */ = { 403 | isa = XCConfigurationList; 404 | buildConfigurations = ( 405 | 4FF8F34F1B400F8B005C73C2 /* Debug */, 406 | 4FF8F3501B400F8B005C73C2 /* Release */, 407 | ); 408 | defaultConfigurationIsVisible = 0; 409 | defaultConfigurationName = Release; 410 | }; 411 | /* End XCConfigurationList section */ 412 | }; 413 | rootObject = 4FF8F3321B400F8B005C73C2 /* Project object */; 414 | } 415 | -------------------------------------------------------------------------------- /ESJsonFormat.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ESJsonFormat.xcodeproj/xcshareddata/xcschemes/ESJsonFormat.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 63 | 66 | 67 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ESJsonFormat/Category/NSObject_Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject_Extension.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSObject (Xcode_Plugin_Template_Extension) 12 | 13 | + (void)pluginDidLoad:(NSBundle *)plugin; 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ESJsonFormat/Category/NSObject_Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject_Extension.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | 10 | #import "NSObject_Extension.h" 11 | #import "ESJsonFormat.h" 12 | 13 | @implementation NSObject (Xcode_Plugin_Template_Extension) 14 | 15 | + (void)pluginDidLoad:(NSBundle *)plugin 16 | { 17 | static dispatch_once_t onceToken; 18 | NSString *currentApplicationName = [[NSBundle mainBundle] infoDictionary][@"CFBundleName"]; 19 | if ([currentApplicationName isEqual:@"Xcode"]) { 20 | dispatch_once(&onceToken, ^{ 21 | sharedPlugin = [[ESJsonFormat alloc] initWithBundle:plugin]; 22 | }); 23 | } 24 | } 25 | @end 26 | -------------------------------------------------------------------------------- /ESJsonFormat/Category/NSString+ESExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+ESExtension.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/4. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (ESExtension) 12 | 13 | - (NSString *)substringWithStartStr:(NSString *)start endStr:(NSString *)endStr; 14 | @end 15 | -------------------------------------------------------------------------------- /ESJsonFormat/Category/NSString+ESExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+ESExtension.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/4. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "NSString+ESExtension.h" 10 | 11 | @implementation NSString (ESExtension) 12 | 13 | - (NSString *)substringWithStartStr:(NSString *)start endStr:(NSString *)endStr{ 14 | NSString *resultStr = nil; 15 | NSRange range; 16 | NSRange tempRange = [self rangeOfString:start]; 17 | if (tempRange.location !=NSNotFound) { 18 | range.location = tempRange.location+tempRange.length; 19 | tempRange = [self rangeOfString:endStr]; 20 | if (tempRange.location!=NSNotFound) { 21 | range.length = tempRange.location-range.location; 22 | return [self substringWithRange:range]; 23 | } 24 | } 25 | return resultStr; 26 | } 27 | @end 28 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESDialogController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESDialogController.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/26. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ESDialogController : NSWindowController 12 | @property (nonatomic, copy) NSString *msg; 13 | @property (nonatomic, copy) NSString *className; 14 | @property (nonatomic, assign) BOOL objIsKindOfArray; 15 | @property (nonatomic, copy) void (^enterBlock)(NSString *className); 16 | 17 | 18 | -(void)setDataWithMsg:(NSString *)msg defaultClassName:(NSString *)className enter:(void(^)(NSString *className))enterBlock; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESDialogController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESDialogController.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/26. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESDialogController.h" 10 | 11 | @interface ESDialogController () 12 | 13 | @property (weak) IBOutlet NSTextField *msgLabel; 14 | @property (weak) IBOutlet NSTextField *classNameField; 15 | 16 | @property (weak) IBOutlet NSButtonCell *implementCheckButton; 17 | @property (weak) IBOutlet NSView *implementCustomView; 18 | 19 | @property (weak) IBOutlet NSLayoutConstraint *fieldBottomConstraint; 20 | 21 | @property (weak) IBOutlet NSLayoutConstraint *checkButtonBottomConstraint; 22 | @end 23 | 24 | @implementation ESDialogController 25 | 26 | - (void)windowDidLoad { 27 | [super windowDidLoad]; 28 | self.classNameField.delegate = self; 29 | self.window.delegate = self; 30 | self.msgLabel.stringValue = self.msg; 31 | self.classNameField.stringValue = self.className; 32 | [self.classNameField becomeFirstResponder]; 33 | 34 | if (YES) { 35 | [self hideImplementCheckButton]; 36 | } 37 | } 38 | 39 | -(void)setDataWithMsg:(NSString *)msg defaultClassName:(NSString *)className enter:(void(^)(NSString *className))enterBlock{ 40 | self.msg = msg; 41 | self.className = className; 42 | self.enterBlock = enterBlock; 43 | } 44 | 45 | -(void)hideImplementCheckButton{ 46 | self.implementCheckButton.state = NSOffState; 47 | self.implementCustomView.hidden = YES; 48 | NSView *rootView = self.window.contentView; 49 | [rootView removeConstraint:self.checkButtonBottomConstraint]; 50 | self.fieldBottomConstraint.constant = 15; 51 | [rootView updateConstraints]; 52 | } 53 | 54 | 55 | - (void)enterBtnClick:(NSButton *)sender { 56 | if (self.enterBlock) { 57 | self.enterBlock(self.classNameField.stringValue); 58 | } 59 | [self close]; 60 | } 61 | 62 | -(void)windowWillClose:(NSNotification *)notification{ 63 | [NSApp stopModal]; 64 | [NSApp endSheet:[self window]]; 65 | [[self window] orderOut:nil]; 66 | } 67 | 68 | 69 | #pragma mark - nstextfiled delegate 70 | 71 | -(void)controlTextDidEndEditing:(NSNotification *)notification{ 72 | if ( [[[notification userInfo] objectForKey:@"NSTextMovement"] intValue] == NSReturnTextMovement){ 73 | [self enterBtnClick:nil]; 74 | } 75 | } 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESDialogController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESInputJsonController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestWindowController.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/19. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @protocol ESInputJsonControllerDelegate 13 | 14 | @optional 15 | -(void)windowWillClose; 16 | @end 17 | 18 | @interface ESInputJsonController : NSWindowController 19 | @property (nonatomic, weak) id delegate; 20 | @end 21 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESInputJsonController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestWindowController.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/19. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESInputJsonController.h" 10 | #import "ESDialogController.h" 11 | #import "ESJsonFormatManager.h" 12 | #import "ESJsonFormat.h" 13 | #import "ESClassInfo.h" 14 | #import "ESJsonFormatSetting.h" 15 | #import "ESPair.h" 16 | 17 | @interface ESInputJsonController () 18 | 19 | /** 20 | * 字段对应的类的名字[key->JSON字段 : value->类名(用户输入)] 21 | */ 22 | @property (nonatomic, strong) NSMutableDictionary *replaceClassNames; 23 | @property (nonatomic, strong) NSMutableDictionary *implementMethodOfMJExtensionClassNames; 24 | 25 | @property (unsafe_unretained) IBOutlet NSTextView *inputTextView; 26 | 27 | @property (weak) IBOutlet NSButton *enterButton; 28 | 29 | @property (weak) IBOutlet NSButton *cancelButton; 30 | 31 | @property (weak) IBOutlet NSScrollView *scrollView; 32 | 33 | @end 34 | 35 | @implementation ESInputJsonController 36 | 37 | -(NSMutableDictionary *)replaceClassNames{ 38 | if (!_replaceClassNames) { 39 | _replaceClassNames = [NSMutableDictionary dictionary]; 40 | } 41 | return _replaceClassNames; 42 | } 43 | 44 | -(NSMutableDictionary *)implementMethodOfMJExtensionClassNames{ 45 | if (!_implementMethodOfMJExtensionClassNames) { 46 | _implementMethodOfMJExtensionClassNames = [NSMutableDictionary dictionary]; 47 | } 48 | return _implementMethodOfMJExtensionClassNames; 49 | } 50 | 51 | - (void)windowDidLoad { 52 | [super windowDidLoad]; 53 | self.inputTextView.delegate = self; 54 | self.window.delegate = self; 55 | } 56 | 57 | -(void)windowWillClose:(NSNotification *)notification{ 58 | if ([self.delegate respondsToSelector:@selector(windowWillClose)]) { 59 | [self.delegate windowWillClose]; 60 | } 61 | } 62 | 63 | - (IBAction)cancelButtonClick:(NSButton *)sender { 64 | [self close]; 65 | } 66 | 67 | - (IBAction)enterButtonClick:(NSButton *)sender { 68 | NSTextView *textView = self.inputTextView; 69 | id result = [self dictionaryWithJsonStr:textView.string]; 70 | if ([result isKindOfClass:[NSError class]]) { 71 | NSError *error = result; 72 | NSAlert *alert = [NSAlert alertWithError:error]; 73 | [alert runModal]; 74 | NSLog(@"Error:Json is invalid"); 75 | }else{ 76 | 77 | ESClassInfo *classInfo = [self dealClassNameWithJsonResult:result]; 78 | 79 | [self close]; 80 | [[NSNotificationCenter defaultCenter] postNotificationName:ESFormatResultNotification object:classInfo]; 81 | } 82 | } 83 | 84 | /** 85 | * 初始类名,RootClass/JSON为数组/创建文件与否 86 | * 87 | * @param result JSON转成字典或者数组 88 | * 89 | * @return 类信息 90 | */ 91 | - (ESClassInfo *)dealClassNameWithJsonResult:(id)result{ 92 | __block ESClassInfo *classInfo = nil; 93 | //如果当前是JSON对应是字典 94 | if ([result isKindOfClass:[NSDictionary class]]) { 95 | //如果是生成到文件,提示输入Root class name 96 | if ([ESJsonFormatSetting defaultSetting].outputToFiles) { 97 | ESDialogController *dialog = [[ESDialogController alloc] initWithWindowNibName:@"ESDialogController"]; 98 | NSString *msg = [NSString stringWithFormat:@"The root class for output to files name is:"]; 99 | [dialog setDataWithMsg:msg defaultClassName:ESRootClassName enter:^(NSString *className) { 100 | classInfo = [[ESClassInfo alloc] initWithClassNameKey:ESRootClassName ClassName:className classDic:result]; 101 | }]; 102 | [NSApp beginSheet:[dialog window] modalForWindow:[NSApp mainWindow] modalDelegate:nil didEndSelector:nil contextInfo:nil]; 103 | [NSApp runModalForWindow:[dialog window]]; 104 | [self dealPropertyNameWithClassInfo:classInfo]; 105 | }else{ 106 | //不生成到文件,Root class 里面用户自己创建 107 | classInfo = [[ESClassInfo alloc] initWithClassNameKey:ESRootClassName ClassName:ESRootClassName classDic:result]; 108 | [self dealPropertyNameWithClassInfo:classInfo]; 109 | } 110 | }else if([result isKindOfClass:[NSArray class]]){ 111 | if ([ESJsonFormatSetting defaultSetting].outputToFiles) { 112 | //当前是JSON代表数组,生成到文件需要提示用户输入Root Class name, 113 | ESDialogController *dialog = [[ESDialogController alloc] initWithWindowNibName:@"ESDialogController"]; 114 | NSString *msg = [NSString stringWithFormat:@"The root class for output to files name is:"]; 115 | __block NSString *rootClassName = ESRootClassName; 116 | [dialog setDataWithMsg:msg defaultClassName:ESRootClassName enter:^(NSString *className) { 117 | rootClassName = className; 118 | }]; 119 | [NSApp beginSheet:[dialog window] modalForWindow:[NSApp mainWindow] modalDelegate:nil didEndSelector:nil contextInfo:nil]; 120 | [NSApp runModalForWindow:[dialog window]]; 121 | 122 | //并且提示用户输入JSON对应的key的名字 123 | dialog = [[ESDialogController alloc] initWithWindowNibName:@"ESDialogController"]; 124 | msg = [NSString stringWithFormat:@"The JSON is an array,the correspond 'key' is:"]; 125 | [dialog setDataWithMsg:msg defaultClassName:ESArrayKeyName enter:^(NSString *className) { 126 | //输入完毕之后,将这个class设置 127 | NSDictionary *dic = [NSDictionary dictionaryWithObject:result forKey:className]; 128 | classInfo = [[ESClassInfo alloc] initWithClassNameKey:ESRootClassName ClassName:rootClassName classDic:dic]; 129 | }]; 130 | [NSApp beginSheet:[dialog window] modalForWindow:[NSApp mainWindow] modalDelegate:nil didEndSelector:nil contextInfo:nil]; 131 | [NSApp runModalForWindow:[dialog window]]; 132 | [self dealPropertyNameWithClassInfo:classInfo]; 133 | }else{ 134 | //Root class 已存在,只需要输入JSON对应的key的名字 135 | ESDialogController *dialog = [[ESDialogController alloc] initWithWindowNibName:@"ESDialogController"]; 136 | NSString *msg = [NSString stringWithFormat:@"The JSON is an array,the correspond 'key' is:"]; 137 | [dialog setDataWithMsg:msg defaultClassName:ESArrayKeyName enter:^(NSString *className) { 138 | //输入完毕之后,将这个class设置 139 | NSDictionary *dic = [NSDictionary dictionaryWithObject:result forKey:className]; 140 | classInfo = [[ESClassInfo alloc] initWithClassNameKey:ESRootClassName ClassName:ESRootClassName classDic:dic]; 141 | }]; 142 | [NSApp beginSheet:[dialog window] modalForWindow:[NSApp mainWindow] modalDelegate:nil didEndSelector:nil contextInfo:nil]; 143 | [NSApp runModalForWindow:[dialog window]]; 144 | [self dealPropertyNameWithClassInfo:classInfo]; 145 | } 146 | } 147 | return classInfo; 148 | } 149 | 150 | 151 | /** 152 | * 处理属性名字(用户输入属性对应字典对应类或者集合里面对应类的名字) 153 | * 154 | * @param classInfo 要处理的ClassInfo 155 | * 156 | * @return 处理完毕的ClassInfo 157 | */ 158 | - (ESClassInfo *)dealPropertyNameWithClassInfo:(ESClassInfo *)classInfo{ 159 | 160 | NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:classInfo.classDic]; 161 | for (NSString *key in dic) { 162 | //取出的可能是NSDictionary或者NSArray 163 | id obj = dic[key]; 164 | if ([obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSDictionary class]]) { 165 | ESDialogController *dialog = [[ESDialogController alloc] initWithWindowNibName:@"ESDialogController"]; 166 | NSString *msg = [NSString stringWithFormat:@"The '%@' correspond class name is:",key]; 167 | if ([obj isKindOfClass:[NSArray class]]) { 168 | //May be 'NSString',will crash 169 | if (!([[obj firstObject] isKindOfClass:[NSDictionary class]] || [[obj firstObject] isKindOfClass:[NSArray class]])) { 170 | continue; 171 | } 172 | dialog.objIsKindOfArray = YES; 173 | msg = [NSString stringWithFormat:@"The '%@' child items class name is:",key]; 174 | } 175 | __block NSString *childClassName;//Record the current class name 176 | [dialog setDataWithMsg:msg defaultClassName:[key capitalizedString] enter:^(NSString *className) { 177 | if (![className isEqualToString:key]) { 178 | self.replaceClassNames[key] = className; 179 | } 180 | childClassName = className; 181 | }]; 182 | [NSApp beginSheet:[dialog window] modalForWindow:[NSApp mainWindow] modalDelegate:nil didEndSelector:nil contextInfo:nil]; 183 | [NSApp runModalForWindow:[dialog window]]; 184 | //如果当前obj是 NSDictionary 或者 NSArray,继续向下遍历 185 | if ([obj isKindOfClass:[NSDictionary class]]) { 186 | ESClassInfo *childClassInfo = [[ESClassInfo alloc] initWithClassNameKey:key ClassName:childClassName classDic:obj]; 187 | [self dealPropertyNameWithClassInfo:childClassInfo]; 188 | //设置classInfo里面属性对应class 189 | [classInfo.propertyClassDic setObject:childClassInfo forKey:key]; 190 | }else if([obj isKindOfClass:[NSArray class]]){ 191 | //如果是 NSArray 取出第一个元素向下遍历 192 | NSArray *array = obj; 193 | if (array.firstObject) { 194 | NSObject *obj = [array firstObject]; 195 | //May be 'NSString',will crash 196 | if ([obj isKindOfClass:[NSDictionary class]]) { 197 | ESClassInfo *childClassInfo = [[ESClassInfo alloc] initWithClassNameKey:key ClassName:childClassName classDic:(NSDictionary *)obj]; 198 | [self dealPropertyNameWithClassInfo:childClassInfo]; 199 | //设置classInfo里面属性类型为 NSArray 情况下,NSArray 内部元素类型的对应的class 200 | [classInfo.propertyArrayDic setObject:childClassInfo forKey:key]; 201 | } 202 | } 203 | } 204 | } 205 | } 206 | return classInfo; 207 | } 208 | 209 | 210 | -(void)close{ 211 | [super close]; 212 | } 213 | 214 | -(void)textDidChange:(NSNotification *)notification{ 215 | NSTextView *textView = notification.object; 216 | id result = [self dictionaryWithJsonStr:textView.string]; 217 | if ([result isKindOfClass:[NSDictionary class]]) { 218 | NSDictionary *dic = result; 219 | [dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 220 | if ([obj isKindOfClass:[NSArray class]]) { 221 | *stop = YES; 222 | } 223 | }]; 224 | } 225 | } 226 | 227 | 228 | /** 229 | * 检查是否是一个有效的JSON 230 | */ 231 | -(id)dictionaryWithJsonStr:(NSString *)jsonString{ 232 | jsonString = [[jsonString stringByReplacingOccurrencesOfString:@" " withString:@""] stringByReplacingOccurrencesOfString:@" " withString:@""]; 233 | NSLog(@"jsonString=%@",jsonString); 234 | NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; 235 | NSError *err; 236 | id dicOrArray = [NSJSONSerialization JSONObjectWithData:jsonData 237 | options:NSJSONReadingMutableContainers 238 | error:&err]; 239 | if (err) { 240 | return err; 241 | }else{ 242 | return dicOrArray; 243 | } 244 | 245 | } 246 | 247 | @end 248 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESInputJsonController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 39 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 78 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESSettingController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESSettingController.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/19. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ESSettingController : NSWindowController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESSettingController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESSettingController.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/19. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESSettingController.h" 10 | #import "ESJsonFormatSetting.h" 11 | 12 | @interface ESSettingController () 13 | @property (weak) IBOutlet NSButton *btnImpMJExtesion; 14 | @property (weak) IBOutlet NSButton *btnGeneric; 15 | @property (weak) IBOutlet NSButton *btnOutputToFile; 16 | @property (weak) IBOutlet NSButton *btnUpercaseForId; 17 | 18 | @end 19 | 20 | @implementation ESSettingController 21 | 22 | - (void)windowDidLoad { 23 | [super windowDidLoad]; 24 | 25 | 26 | self.btnImpMJExtesion.state = (NSCellStateValue)[[ESJsonFormatSetting defaultSetting] impOjbClassInArray]; 27 | self.btnGeneric.state = (NSCellStateValue)[[ESJsonFormatSetting defaultSetting] useGeneric]; 28 | self.btnOutputToFile.state = (NSCellStateValue)[[ESJsonFormatSetting defaultSetting] outputToFiles]; 29 | self.btnUpercaseForId.state = (NSCellStateValue)[[ESJsonFormatSetting defaultSetting] uppercaseKeyWordForId]; 30 | if (![ESUtils isXcode7AndLater]) { 31 | self.btnGeneric.enabled = NO; 32 | } 33 | } 34 | 35 | - (IBAction)btnImpMtdForMJClick:(NSButton *)sender { 36 | [[ESJsonFormatSetting defaultSetting] setImpOjbClassInArray:sender.state]; 37 | } 38 | 39 | - (IBAction)btnUseGenericClick:(NSButton *)sender { 40 | [[ESJsonFormatSetting defaultSetting] setUseGeneric:sender.state]; 41 | } 42 | 43 | - (IBAction)btnOutputToFilesClick:(NSButton *)sender { 44 | [[ESJsonFormatSetting defaultSetting] setOutputToFiles:sender.state]; 45 | } 46 | 47 | - (IBAction)btnUpercaseKeyWordForIdClick:(NSButton *)sender { 48 | [[ESJsonFormatSetting defaultSetting] setUppercaseKeyWordForId:sender.state]; 49 | } 50 | 51 | 52 | - (IBAction)tapGes:(NSClickGestureRecognizer *)sender { 53 | NSURL* url = [[ NSURL alloc ] initWithString :@"http://t.cn/RLarUfg"]; 54 | [[NSWorkspace sharedWorkspace] openURL:url]; 55 | } 56 | 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /ESJsonFormat/Controller/ESSettingController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 36 | 46 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ESJsonFormat/DataModelsTemplate.txt: -------------------------------------------------------------------------------- 1 | // 2 | // __MODELNAME__ 3 | // __PRODUCTNAME__ 4 | // 5 | // Created by __NAME__ on __DATE__ 6 | // Copyright (c) __ORGANIZATIONNAME__. All rights reserved. 7 | // 8 | 9 | -------------------------------------------------------------------------------- /ESJsonFormat/ESJsonFormat-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // ESJsonFormat-Prefix.pch 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #ifndef ESJsonFormat_ESJsonFormat_Prefix_pch 10 | #define ESJsonFormat_ESJsonFormat_Prefix_pch 11 | 12 | #ifdef __OBJC__ 13 | #import 14 | #import 15 | #import "ESUtils.h" 16 | #import "NSString+ESExtension.h" 17 | #endif 18 | 19 | 20 | #if 1 21 | #define __DEBUG__ 22 | #endif 23 | 24 | #ifdef __DEBUG__ 25 | #define NSLog(...) NSLog(__VA_ARGS__) 26 | #else 27 | #define NSLog(...) do{} while(0) 28 | #endif 29 | 30 | #define ESFormatResultNotification @"ESFormatResultNotification" 31 | 32 | #define ESRootClassName @"ESRootClass" 33 | 34 | #define ESItemClassName @"ESItemClass" 35 | 36 | #define ESArrayKeyName @"esArray" 37 | 38 | #define ESJsonFormatPluginPath [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"Developer/Shared/Xcode/Plug-ins/ESJsonFormat.xcplugin"] 39 | 40 | #define ESUppercaseKeyWords @[@"id"] 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /ESJsonFormat/ESJsonFormat.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESJsonFormat.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ESJsonFormat; 12 | 13 | static ESJsonFormat *sharedPlugin; 14 | static ESJsonFormat *instance; 15 | 16 | @interface ESJsonFormat : NSObject 17 | 18 | @property (nonatomic, assign,getter=isSwift) BOOL swift; 19 | 20 | + (instancetype)sharedPlugin; 21 | + (instancetype)instance; 22 | - (id)initWithBundle:(NSBundle *)plugin; 23 | 24 | @property (nonatomic, strong, readonly) NSBundle* bundle; 25 | @end -------------------------------------------------------------------------------- /ESJsonFormat/ESJsonFormat.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESJsonFormat.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESJsonFormat.h" 10 | #import "ESJsonFormatManager.h" 11 | #import "ESFormatInfo.h" 12 | #import "ESInputJsonController.h" 13 | #import "ESSettingController.h" 14 | #import "ESPbxprojInfo.h" 15 | #import "ESJsonFormatSetting.h" 16 | #import "ESClassInfo.h" 17 | 18 | @interface ESJsonFormat() 19 | @property (nonatomic, strong) ESInputJsonController *inputCtrl; 20 | @property (nonatomic, strong) ESSettingController *settingCtrl; 21 | @property (nonatomic, strong) id eventMonitor; 22 | @property (nonatomic, strong, readwrite) NSBundle *bundle; 23 | @property (nonatomic, copy) NSString *currentFilePath; 24 | @property (nonatomic, copy) NSString *currentProjectPath; 25 | @property (nonatomic) NSTextView *currentTextView; 26 | @property (nonatomic, assign) BOOL notiTag; 27 | 28 | @end 29 | 30 | @implementation ESJsonFormat 31 | 32 | + (instancetype)sharedPlugin{ 33 | return sharedPlugin; 34 | } 35 | 36 | + (instancetype)instance{ 37 | return instance; 38 | } 39 | 40 | - (id)initWithBundle:(NSBundle *)plugin 41 | { 42 | if (self = [super init]) { 43 | // reference to plugin's bundle, for resource access 44 | self.bundle = plugin; 45 | [[NSNotificationCenter defaultCenter] addObserver:self 46 | selector:@selector(didApplicationFinishLaunchingNotification:) 47 | name:NSApplicationDidFinishLaunchingNotification 48 | object:nil]; 49 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(outputResult:) name:ESFormatResultNotification object:nil]; 50 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationLog:) name:NSTextViewDidChangeSelectionNotification object:nil]; 51 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationLog:) name:@"IDEEditorDocumentDidChangeNotification" object:nil]; 52 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationLog:) name:@"PBXProjectDidOpenNotification" object:nil]; 53 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationLog:) name:@"SourceEditorSelectedSourceRangeChangedNotification" object:nil]; 54 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationLog:) name:@"IDEWorkspaceDocumentWillWriteStateDataNotification" object:nil]; 55 | } 56 | instance = self; 57 | return self; 58 | } 59 | 60 | - (void)notificationLog:(NSNotification *)notify 61 | { 62 | 63 | if (!self.notiTag) return; 64 | if ([notify.name isEqualToString:NSTextViewDidChangeSelectionNotification]) { 65 | if ([notify.object isKindOfClass:NSClassFromString(@"DVTSourceTextView")]) { 66 | NSTextView *text = (NSTextView *)notify.object; 67 | self.currentTextView = text; 68 | } 69 | }else if ([notify.name isEqualToString:@"IDEEditorDocumentDidChangeNotification"]){ 70 | //Track the current open paths 71 | NSObject *array = notify.userInfo[@"IDEEditorDocumentChangeLocationsKey"]; 72 | NSURL *url = [[array valueForKey:@"documentURL"] firstObject]; 73 | if (![url isKindOfClass:[NSNull class]]) { 74 | NSString *path = [url absoluteString]; 75 | self.currentFilePath = path; 76 | if ([self.currentFilePath hasSuffix:@"swift"]) { 77 | self.swift = YES; 78 | }else{ 79 | self.swift = NO; 80 | } 81 | } 82 | }else if ([notify.name isEqualToString:@"PBXProjectDidOpenNotification"]){ 83 | self.currentProjectPath = [notify.object valueForKey:@"path"]; 84 | [[ESPbxprojInfo shareInstance] setParamsWithPath:[self.currentProjectPath stringByAppendingPathComponent:@"project.pbxproj"]]; 85 | }else if ([notify.name isEqualToString:@"SourceEditorSelectedSourceRangeChangedNotification"]) { 86 | // 适配 Xcode 9,在Xcode 9 中代码编辑区域的 View 类型如下,继承于 NSView,但使用方式与 NSTextView 类似 87 | if ([notify.object isKindOfClass:NSClassFromString(@"IDEPegasusSourceEditor.SourceCodeEditorView")]) { 88 | self.currentTextView = notify.object; 89 | } 90 | }else if ([notify.name isEqualToString:@"IDEWorkspaceDocumentWillWriteStateDataNotification"]) { 91 | NSArray *recentEditorDocumentURLs = [notify.object valueForKey:@"_recentEditorDocumentURLs"]; 92 | NSString *path = [recentEditorDocumentURLs.firstObject absoluteString]; 93 | if ([path hasPrefix:@"file"]) { 94 | self.currentFilePath = path; 95 | } 96 | } 97 | 98 | } 99 | 100 | -(void)outputResult:(NSNotification*)noti{ 101 | ESClassInfo *classInfo = noti.object; 102 | if ([ESJsonFormatSetting defaultSetting].outputToFiles) { 103 | //选择保存路径 104 | NSOpenPanel *panel = [NSOpenPanel openPanel]; 105 | [panel setTitle:@"ESJsonFormat"]; 106 | [panel setCanChooseDirectories:YES]; 107 | [panel setCanCreateDirectories:YES]; 108 | [panel setCanChooseFiles:NO]; 109 | 110 | if ([panel runModal] == NSModalResponseOK) { 111 | NSString *folderPath = [[[panel URLs] objectAtIndex:0] relativePath]; 112 | [classInfo createFileWithFolderPath:folderPath]; 113 | [[NSWorkspace sharedWorkspace] openFile:folderPath]; 114 | } 115 | 116 | }else{ 117 | if (!self.currentTextView) return; 118 | if (!self.isSwift) { 119 | //先添加主类的属性 120 | [self.currentTextView insertText:classInfo.propertyContent]; 121 | 122 | //再添加把其他类的的字符串拼接到最后面 123 | [self.currentTextView insertText:classInfo.classInsertTextViewContentForH replacementRange:NSMakeRange(self.currentTextView.string.length, 0)]; 124 | 125 | //@class 126 | NSString *atClassContent = classInfo.atClassContent; 127 | if (atClassContent.length>0) { 128 | NSRange atInsertRange = [self.currentTextView.string rangeOfString:@"\n@interface"]; 129 | if (atInsertRange.location != NSNotFound) { 130 | [self.currentTextView insertText:[NSString stringWithFormat:@"\n%@",atClassContent] replacementRange:NSMakeRange(atInsertRange.location, 0)]; 131 | } 132 | } 133 | 134 | //再添加.m文件的内容 135 | NSString *urlStr = [NSString stringWithFormat:@"%@m",[self.currentFilePath substringWithRange:NSMakeRange(0, self.currentFilePath.length-1)]] ; 136 | NSURL *writeUrl = [NSURL URLWithString:urlStr]; 137 | //The original content 138 | NSString *originalContent = [NSString stringWithContentsOfURL:writeUrl encoding:NSUTF8StringEncoding error:nil]; 139 | 140 | //输出RootClass的impOjbClassInArray方法 141 | if ([ESJsonFormatSetting defaultSetting].impOjbClassInArray) { 142 | NSString *methodStr = [ESJsonFormatManager methodContentOfObjectClassInArrayWithClassInfo:classInfo]; 143 | if (methodStr.length) { 144 | NSRange lastEndRange = [originalContent rangeOfString:@"@end"]; 145 | if (lastEndRange.location != NSNotFound) { 146 | originalContent = [originalContent stringByReplacingCharactersInRange:NSMakeRange(lastEndRange.location, 0) withString:methodStr]; 147 | } 148 | } 149 | } 150 | originalContent = [originalContent stringByReplacingCharactersInRange:NSMakeRange(originalContent.length, 0) withString:classInfo.classInsertTextViewContentForM]; 151 | [originalContent writeToURL:writeUrl atomically:YES encoding:NSUTF8StringEncoding error:nil]; 152 | 153 | }else{ 154 | //Swift 155 | [self.currentTextView insertText:classInfo.propertyContent]; 156 | 157 | //再添加把其他类的的字符串拼接到最后面 158 | [self.currentTextView insertText:classInfo.classInsertTextViewContentForH replacementRange:NSMakeRange(self.currentTextView.string.length, 0)]; 159 | } 160 | } 161 | } 162 | 163 | - (void)didApplicationFinishLaunchingNotification:(NSNotification*)noti{ 164 | self.notiTag = YES; 165 | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidFinishLaunchingNotification object:nil]; 166 | NSMenuItem *menuItem = [[NSApp mainMenu] itemWithTitle:@"Window"]; 167 | if (menuItem) { 168 | 169 | NSMenu *menu = [[NSMenu alloc] init]; 170 | 171 | //Input JSON window 172 | NSMenuItem *inputJsonWindow = [[NSMenuItem alloc] initWithTitle:@"Input JSON window" action:@selector(showInputJsonWindow:) keyEquivalent:@"J"]; 173 | [inputJsonWindow setKeyEquivalentModifierMask:NSAlphaShiftKeyMask | NSControlKeyMask]; 174 | inputJsonWindow.target = self; 175 | [menu addItem:inputJsonWindow]; 176 | 177 | //Setting 178 | NSMenuItem *settingWindow = [[NSMenuItem alloc] initWithTitle:@"Setting" action:@selector(showSettingWindow:) keyEquivalent:@""]; 179 | settingWindow.target = self; 180 | [menu addItem:settingWindow]; 181 | 182 | NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"ESJsonFormat" action:nil keyEquivalent:@""]; 183 | item.submenu = menu; 184 | 185 | [[menuItem submenu] addItem:item]; 186 | } 187 | } 188 | 189 | - (void)showInputJsonWindow:(NSMenuItem *)item{ 190 | 191 | if (!(self.currentTextView && self.currentFilePath)) { 192 | NSError *error = [NSError errorWithDomain:@"Current state is not edit!" code:0 userInfo:nil]; 193 | NSAlert *alert = [NSAlert alertWithError:error]; 194 | [alert runModal]; 195 | return; 196 | } 197 | self.notiTag = NO; 198 | self.inputCtrl = [[ESInputJsonController alloc] initWithWindowNibName:@"ESInputJsonController"]; 199 | self.inputCtrl.delegate = self; 200 | [self.inputCtrl showWindow:self.inputCtrl]; 201 | } 202 | 203 | - (void)showSettingWindow:(NSMenuItem *)item{ 204 | self.settingCtrl = [[ESSettingController alloc] initWithWindowNibName:@"ESSettingController"]; 205 | [self.settingCtrl showWindow:self.settingCtrl]; 206 | } 207 | 208 | -(void)windowWillClose{ 209 | self.notiTag = YES; 210 | } 211 | - (void)dealloc{ 212 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 213 | } 214 | 215 | 216 | @end 217 | -------------------------------------------------------------------------------- /ESJsonFormat/ESJsonFormatManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESJsonFormatManager.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | @class ESClassInfo; 11 | @interface ESJsonFormatManager : NSObject 12 | 13 | /** 14 | * 解析一个类里面属性字段的内容 15 | * 16 | * @param classInfo 类信息 17 | * 18 | * @return 19 | */ 20 | + (NSString *)parsePropertyContentWithClassInfo:(ESClassInfo *)classInfo; 21 | 22 | /** 23 | * 解析一个类头文件的内容(会根据是否创建文件返回的内容有所不同) 24 | * 25 | * @param classInfo 类信息 26 | * 27 | * @return 类头文件里面的内容 28 | */ 29 | + (NSString *)parseClassHeaderContentWithClassInfo:(ESClassInfo *)classInfo; 30 | 31 | 32 | /** 33 | * 解析一个类实现文件内容 (仅对OC有效) 34 | * 35 | * @param classInfo 类信息 36 | * 37 | * @return 实现文件里面的内容 38 | */ 39 | + (NSString *)parseClassImpContentWithClassInfo:(ESClassInfo *)classInfo; 40 | 41 | 42 | /** 43 | * 生成 MJExtension2.0 的集合中指定对象的方法 44 | * 45 | * @param classInfo 指定类信息 46 | * 47 | * @return 48 | */ 49 | + (NSString *)methodContentOfObjectClassInArrayWithClassInfo:(ESClassInfo *)classInfo; 50 | 51 | 52 | /** 53 | * 创建文件 54 | * 55 | * @param folderPath 输出的文件夹路径 56 | * @param classInfo 类信息 57 | */ 58 | + (void)createFileWithFolderPath:(NSString *)folderPath classInfo:(ESClassInfo *)classInfo; 59 | 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /ESJsonFormat/ESJsonFormatManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESJsonFormatManager.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESJsonFormatManager.h" 10 | #import "ESClassInfo.h" 11 | #import "ESFormatInfo.h" 12 | #import "ESClassInfo.h" 13 | #import "ESPair.h" 14 | #import "ESJsonFormat.h" 15 | #import "ESJsonFormatSetting.h" 16 | #import "ESPbxprojInfo.h" 17 | #import "ESClassInfo.h" 18 | 19 | 20 | @interface ESJsonFormatManager() 21 | 22 | @end 23 | @implementation ESJsonFormatManager 24 | 25 | + (NSString *)parsePropertyContentWithClassInfo:(ESClassInfo *)classInfo{ 26 | NSMutableString *resultStr = [NSMutableString string]; 27 | NSDictionary *dic = classInfo.classDic; 28 | [dic enumerateKeysAndObjectsUsingBlock:^(id key, NSObject *obj, BOOL *stop) { 29 | if ([ESJsonFormat instance].isSwift) { 30 | [resultStr appendFormat:@"\n%@\n",[self formatSwiftWithKey:key value:obj classInfo:classInfo]]; 31 | }else{ 32 | [resultStr appendFormat:@"\n%@\n",[self formatObjcWithKey:key value:obj classInfo:classInfo]]; 33 | } 34 | }]; 35 | return resultStr; 36 | } 37 | 38 | /** 39 | * 格式化OC属性字符串 40 | * 41 | * @param key JSON里面key字段 42 | * @param value JSON里面key对应的NSDiction或者NSArray 43 | * @param classInfo 类信息 44 | * 45 | * @return 46 | */ 47 | + (NSString *)formatObjcWithKey:(NSString *)key value:(NSObject *)value classInfo:(ESClassInfo *)classInfo{ 48 | NSString *qualifierStr = @"copy"; 49 | NSString *typeStr = @"NSString"; 50 | //判断大小写 51 | if ([ESUppercaseKeyWords containsObject:key] && [ESJsonFormatSetting defaultSetting].uppercaseKeyWordForId) { 52 | key = [key uppercaseString]; 53 | } 54 | if ([value isKindOfClass:[NSString class]]) { 55 | return [NSString stringWithFormat:@"@property (nonatomic, %@) %@ *%@;",qualifierStr,typeStr,key]; 56 | }else if([value isKindOfClass:[@(YES) class]]){ 57 | //the 'NSCFBoolean' is private subclass of 'NSNumber' 58 | qualifierStr = @"assign"; 59 | typeStr = @"BOOL"; 60 | return [NSString stringWithFormat:@"@property (nonatomic, %@) %@ %@;",qualifierStr,typeStr,key]; 61 | }else if([value isKindOfClass:[NSNumber class]]){ 62 | qualifierStr = @"assign"; 63 | NSString *valueStr = [NSString stringWithFormat:@"%@",value]; 64 | if ([valueStr rangeOfString:@"."].location!=NSNotFound){ 65 | typeStr = @"CGFloat"; 66 | }else{ 67 | NSNumber *valueNumber = (NSNumber *)value; 68 | if ([valueNumber longValue]<2147483648) { 69 | typeStr = @"NSInteger"; 70 | }else{ 71 | typeStr = @"long long"; 72 | } 73 | } 74 | return [NSString stringWithFormat:@"@property (nonatomic, %@) %@ %@;",qualifierStr,typeStr,key]; 75 | }else if([value isKindOfClass:[NSArray class]]){ 76 | NSArray *array = (NSArray *)value; 77 | 78 | //May be 'NSString',will crash 79 | NSString *genericTypeStr = @""; 80 | NSObject *firstObj = [array firstObject]; 81 | if ([firstObj isKindOfClass:[NSDictionary class]]) { 82 | ESClassInfo *childInfo = classInfo.propertyArrayDic[key]; 83 | genericTypeStr = [NSString stringWithFormat:@"<%@ *>",childInfo.className]; 84 | }else if ([firstObj isKindOfClass:[NSString class]]){ 85 | genericTypeStr = @""; 86 | }else if ([firstObj isKindOfClass:[NSNumber class]]){ 87 | genericTypeStr = @""; 88 | } 89 | 90 | qualifierStr = @"strong"; 91 | typeStr = @"NSArray"; 92 | if ([ESJsonFormatSetting defaultSetting].useGeneric && [ESUtils isXcode7AndLater]) { 93 | return [NSString stringWithFormat:@"@property (nonatomic, %@) %@%@ *%@;",qualifierStr,typeStr,genericTypeStr,key]; 94 | } 95 | return [NSString stringWithFormat:@"@property (nonatomic, %@) %@ *%@;",qualifierStr,typeStr,key]; 96 | }else if ([value isKindOfClass:[NSDictionary class]]){ 97 | qualifierStr = @"strong"; 98 | ESClassInfo *childInfo = classInfo.propertyClassDic[key]; 99 | typeStr = childInfo.className; 100 | if (!typeStr) { 101 | typeStr = [key capitalizedString]; 102 | } 103 | return [NSString stringWithFormat:@"@property (nonatomic, %@) %@ *%@;",qualifierStr,typeStr,key]; 104 | } 105 | return [NSString stringWithFormat:@"@property (nonatomic, %@) %@ *%@;",qualifierStr,typeStr,key]; 106 | } 107 | 108 | 109 | /** 110 | * 格式化Swift属性字符串 111 | * 112 | * @param key JSON里面key字段 113 | * @param value JSON里面key对应的NSDiction或者NSArray 114 | * @param classInfo 类信息 115 | * 116 | * @return 117 | */ 118 | + (NSString *)formatSwiftWithKey:(NSString *)key value:(NSObject *)value classInfo:(ESClassInfo *)classInfo{ 119 | NSString *typeStr = @"String"; 120 | //判断大小写 121 | if ([ESUppercaseKeyWords containsObject:key] && [ESJsonFormatSetting defaultSetting].uppercaseKeyWordForId) { 122 | key = [key uppercaseString]; 123 | } 124 | if ([value isKindOfClass:[NSString class]]) { 125 | return [NSString stringWithFormat:@" var %@: %@ = \"\"",key,typeStr]; 126 | }else if([value isKindOfClass:[@(YES) class]]){ 127 | typeStr = @"Bool"; 128 | return [NSString stringWithFormat:@" var %@: %@ = false",key,typeStr]; 129 | }else if([value isKindOfClass:[NSNumber class]]){ 130 | NSString *valueStr = [NSString stringWithFormat:@"%@",value]; 131 | if ([valueStr rangeOfString:@"."].location!=NSNotFound){ 132 | typeStr = @"Double"; 133 | }else{ 134 | typeStr = @"Int"; 135 | } 136 | return [NSString stringWithFormat:@" var %@: %@ = 0",key,typeStr]; 137 | }else if([value isKindOfClass:[NSArray class]]){ 138 | ESClassInfo *childInfo = classInfo.propertyArrayDic[key]; 139 | NSString *type = childInfo.className; 140 | return [NSString stringWithFormat:@" var %@: [%@]?",key,type==nil?@"String":type]; 141 | }else if ([value isKindOfClass:[NSDictionary class]]){ 142 | ESClassInfo *childInfo = classInfo.propertyClassDic[key]; 143 | typeStr = childInfo.className; 144 | if (!typeStr) { 145 | typeStr = [key capitalizedString]; 146 | } 147 | return [NSString stringWithFormat:@" var %@: %@?",key,typeStr]; 148 | } 149 | return [NSString stringWithFormat:@" var %@: %@",key,typeStr]; 150 | } 151 | 152 | 153 | 154 | + (NSString *)parseClassHeaderContentWithClassInfo:(ESClassInfo *)classInfo{ 155 | if ([ESJsonFormat instance].isSwift) { 156 | return [self parseClassContentForSwiftWithClassInfo:classInfo]; 157 | }else{ 158 | return [self parseClassHeaderContentForOjbcWithClassInfo:classInfo]; 159 | } 160 | } 161 | 162 | + (NSString *)parseClassImpContentWithClassInfo:(ESClassInfo *)classInfo{ 163 | 164 | if ([ESJsonFormat instance].isSwift) { 165 | return @""; 166 | } 167 | 168 | NSMutableString *result = [NSMutableString stringWithString:@""]; 169 | if ([ESJsonFormatSetting defaultSetting].impOjbClassInArray) { 170 | [result appendFormat:@"@implementation %@\n%@\n@end\n",classInfo.className,[self methodContentOfObjectClassInArrayWithClassInfo:classInfo]]; 171 | }else{ 172 | [result appendFormat:@"@implementation %@\n\n@end\n",classInfo.className]; 173 | } 174 | 175 | if ([ESJsonFormatSetting defaultSetting].outputToFiles) { 176 | //headerStr 177 | NSMutableString *headerString = [NSMutableString stringWithString:[self dealHeaderStrWithClassInfo:classInfo type:@"m"]]; 178 | //import 179 | [headerString appendString:[NSString stringWithFormat:@"#import \"%@.h\"\n",classInfo.className]]; 180 | for (NSString *key in classInfo.propertyArrayDic) { 181 | ESClassInfo *childClassInfo = classInfo.propertyArrayDic[key]; 182 | [headerString appendString:[NSString stringWithFormat:@"#import \"%@.h\"\n",childClassInfo.className]]; 183 | } 184 | [headerString appendString:@"\n"]; 185 | [result insertString:headerString atIndex:0]; 186 | } 187 | return [result copy]; 188 | } 189 | 190 | /** 191 | * 解析.h文件内容--Objc 192 | * 193 | * @param classInfo 类信息 194 | * 195 | * @return 196 | */ 197 | + (NSString *)parseClassHeaderContentForOjbcWithClassInfo:(ESClassInfo *)classInfo{ 198 | NSMutableString *result = [NSMutableString stringWithFormat:@"@interface %@ : NSObject\n",classInfo.className]; 199 | [result appendString:classInfo.propertyContent]; 200 | [result appendString:@"\n@end"]; 201 | 202 | if ([ESJsonFormatSetting defaultSetting].outputToFiles) { 203 | //headerStr 204 | NSMutableString *headerString = [NSMutableString stringWithString:[self dealHeaderStrWithClassInfo:classInfo type:@"h"]]; 205 | //@class 206 | [headerString appendString:[NSString stringWithFormat:@"%@\n\n",classInfo.atClassContent]]; 207 | [result insertString:headerString atIndex:0]; 208 | } 209 | return [result copy]; 210 | } 211 | 212 | /** 213 | * 解析.swift文件内容--Swift 214 | * 215 | * @param classInfo 类信息 216 | * 217 | * @return 218 | */ 219 | + (NSString *)parseClassContentForSwiftWithClassInfo:(ESClassInfo *)classInfo{ 220 | NSMutableString *result = [NSMutableString stringWithFormat:@"class %@: NSObject {\n",classInfo.className]; 221 | [result appendString:classInfo.propertyContent]; 222 | [result appendString:@"\n}"]; 223 | if ([ESJsonFormatSetting defaultSetting].outputToFiles) { 224 | [result insertString:@"import UIKit\n\n" atIndex:0]; 225 | //headerStr 226 | NSMutableString *headerString = [NSMutableString stringWithString:[self dealHeaderStrWithClassInfo:classInfo type:@"swift"]]; 227 | [result insertString:headerString atIndex:0]; 228 | } 229 | return [result copy]; 230 | } 231 | 232 | 233 | /** 234 | * 生成 MJExtension 的集合中指定对象的方法 235 | * 236 | * @param classInfo 指定类信息 237 | * 238 | * @return 239 | */ 240 | + (NSString *)methodContentOfObjectClassInArrayWithClassInfo:(ESClassInfo *)classInfo{ 241 | if (classInfo.propertyArrayDic.count==0) { 242 | return @""; 243 | }else{ 244 | NSMutableString *result = [NSMutableString string]; 245 | for (NSString *key in classInfo.propertyArrayDic) { 246 | ESClassInfo *childClassInfo = classInfo.propertyArrayDic[key]; 247 | [result appendFormat:@"@\"%@\" : [%@ class], ",key,childClassInfo.className]; 248 | } 249 | if ([result hasSuffix:@", "]) { 250 | result = [NSMutableString stringWithFormat:@"%@",[result substringToIndex:result.length-2]]; 251 | } 252 | //append method content (objectClassInArray) 253 | NSString *methodStr = [NSString stringWithFormat:@"\n+ (NSDictionary *)objectClassInArray{\n return @{%@};\n}\n",result]; 254 | return methodStr; 255 | } 256 | } 257 | 258 | 259 | /** 260 | * 拼装模板信息 261 | * 262 | * @param classInfo 类信息 263 | * @param type .h或者.m或者.swift 264 | * 265 | * @return 266 | */ 267 | + (NSString *)dealHeaderStrWithClassInfo:(ESClassInfo *)classInfo type:(NSString *)type{ 268 | //模板文字 269 | NSString *templateFile = [ESJsonFormatPluginPath stringByAppendingPathComponent:@"Contents/Resources/DataModelsTemplate.txt"]; 270 | NSString *templateString = [NSString stringWithContentsOfFile:templateFile encoding:NSUTF8StringEncoding error:nil]; 271 | //替换模型名字 272 | templateString = [templateString stringByReplacingOccurrencesOfString:@"__MODELNAME__" withString:[NSString stringWithFormat:@"%@.%@",classInfo.className,type]]; 273 | //替换用户名 274 | templateString = [templateString stringByReplacingOccurrencesOfString:@"__NAME__" withString:NSFullUserName()]; 275 | //产品名 276 | NSString *productName = [ESPbxprojInfo shareInstance].productName; 277 | if (productName.length) { 278 | templateString = [templateString stringByReplacingOccurrencesOfString:@"__PRODUCTNAME__" withString:productName]; 279 | } 280 | //组织名 281 | NSString *organizationName = [ESPbxprojInfo shareInstance].organizationName; 282 | if (organizationName.length) { 283 | templateString = [templateString stringByReplacingOccurrencesOfString:@"__ORGANIZATIONNAME__" withString:organizationName]; 284 | } 285 | //时间 286 | templateString = [templateString stringByReplacingOccurrencesOfString:@"__DATE__" withString:[self dateStr]]; 287 | 288 | if ([type isEqualToString:@"h"] || [type isEqualToString:@"switf"]) { 289 | NSMutableString *string = [NSMutableString stringWithString:templateString]; 290 | if ([type isEqualToString:@"h"]) { 291 | [string appendString:@"#import \n\n"]; 292 | }else{ 293 | [string appendString:@"import UIKit\n\n"]; 294 | } 295 | templateString = [string copy]; 296 | } 297 | return [templateString copy]; 298 | } 299 | 300 | /** 301 | * 返回模板信息里面日期字符串 302 | * 303 | * @return 304 | */ 305 | + (NSString *)dateStr{ 306 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 307 | formatter.dateFormat = @"yy/MM/dd"; 308 | return [formatter stringFromDate:[NSDate date]]; 309 | } 310 | 311 | 312 | + (void)createFileWithFolderPath:(NSString *)folderPath classInfo:(ESClassInfo *)classInfo{ 313 | if (![ESJsonFormat instance].isSwift) { 314 | //创建.h文件 315 | [self createFileWithFileName:[folderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.h",classInfo.className]] content:classInfo.classContentForH]; 316 | //创建.m文件 317 | [self createFileWithFileName:[folderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.m",classInfo.className]] content:classInfo.classContentForM]; 318 | }else{ 319 | //创建.swift文件 320 | [self createFileWithFileName:[folderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.swift",classInfo.className]] content:classInfo.classContentForH]; 321 | } 322 | } 323 | 324 | /** 325 | * 创建文件 326 | * 327 | * @param FileName 文件名字 328 | * @param content 文件内容 329 | */ 330 | + (void)createFileWithFileName:(NSString *)FileName content:(NSString *)content{ 331 | NSFileManager *manager = [NSFileManager defaultManager]; 332 | [manager createFileAtPath:FileName contents:[content dataUsingEncoding:NSUTF8StringEncoding] attributes:nil]; 333 | } 334 | 335 | @end 336 | -------------------------------------------------------------------------------- /ESJsonFormat/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.enjoy.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | DVTPlugInCompatibilityUUIDs 26 | 27 | AABB7188-E14E-4433-AD3B-5CD791EAD9A3 28 | 1637F4D5-0B27-416B-A78D-498965D64877 29 | F41BD31E-2683-44B8-AE7F-5F09E919790E 30 | 992275C1-432A-4CF7-B659-D84ED6D42D3F 31 | 7FDF5C7A-131F-4ABB-9EDC-8C5F8F0B8A90 32 | C4A681B0-4A26-480E-93EC-1218098B9AA0 33 | AD68E85B-441B-4301-B564-A45E4919A6AD 34 | A16FF353-8441-459E-A50C-B071F53F51B7 35 | 9F75337B-21B4-4ADC-B558-F9CADF7073A7 36 | E969541F-E6F9-4D25-8158-72DC3545A6C6 37 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 38 | 7265231C-39B4-402C-89E1-16167C4CC990 39 | ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C 40 | DFFB3951-EB0A-4C09-9DAC-5F2D28CC839C 41 | CA351AD8-3176-41CB-875C-42A05C7CDEC7 42 | 43 | LSMinimumSystemVersion 44 | $(MACOSX_DEPLOYMENT_TARGET) 45 | NSPrincipalClass 46 | ESJsonFormat 47 | XC4Compatible 48 | 49 | XCPluginHasUI 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ESJsonFormat/Model/ESClassInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESClassInfo.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ESClassInfo : NSObject 12 | /** 13 | * 实体类的类名 14 | */ 15 | @property (nonatomic, copy) NSString *className; 16 | /** 17 | * 当前类在JSON里面对应的key 18 | */ 19 | @property (nonatomic, copy) NSString *classNameKey; 20 | /** 21 | * 当前类对应的字典 22 | */ 23 | @property (nonatomic, strong) NSDictionary *classDic; 24 | 25 | /** 26 | * 当前类里面属性对应为类的字典 [key->JSON字段的key : value->ESClassInfo对象] 27 | */ 28 | @property (nonatomic, strong) NSMutableDictionary *propertyClassDic; 29 | 30 | /** 31 | * 当前类里属性对应为集合(指定集合里面存某个模型,用作MJExtension) [key->JSON字段的key : value->ESClassInfo对象] 32 | */ 33 | @property (nonatomic, strong) NSMutableDictionary *propertyArrayDic; 34 | 35 | /** 36 | * @class 内容,用于在创建类文件的时候,指定当前类里面引用哪些类-->通过遍历propertyClassDic生成 37 | */ 38 | @property (nonatomic, copy) NSString *atClassContent; 39 | 40 | /** 41 | * 当前类的需要引用的calss集合 42 | */ 43 | @property (nonatomic, copy) NSArray *atClassArray; 44 | 45 | 46 | /** 47 | * 所有属性对应的格式化的内容 48 | */ 49 | @property (nonatomic, copy) NSString *propertyContent; 50 | 51 | /** 52 | * 整个类头文件的内容,包含头与尾 -- 会根据是否创建文件添加模板文字 53 | */ 54 | @property (nonatomic, copy) NSString *classContentForH; 55 | 56 | /** 57 | * 整个类实现文件里面的内容,在Swift情况下此参数无效 58 | */ 59 | @property (nonatomic, copy) NSString *classContentForM; 60 | 61 | 62 | /** 63 | * 直接插入到.h文件或者与.swift文件中内容 -- 不包含当前类里面属性字段,只有里面引用类的.h文件内容 64 | */ 65 | @property (nonatomic, copy) NSString *classInsertTextViewContentForH; 66 | 67 | /** 68 | * 直接插入到.m文件的内容,在Swift情况下此参数无效 69 | */ 70 | @property (nonatomic, copy) NSString *classInsertTextViewContentForM; 71 | 72 | 73 | - (instancetype)initWithClassNameKey:(NSString *)classNameKey ClassName:(NSString *)className classDic:(NSDictionary *)classDic; 74 | 75 | /** 76 | * 创建文件 77 | * 78 | * @param folderPath 文件路径 79 | */ 80 | - (void)createFileWithFolderPath:(NSString *)folderPath; 81 | 82 | @end 83 | 84 | -------------------------------------------------------------------------------- /ESJsonFormat/Model/ESClassInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESClassInfo.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESClassInfo.h" 10 | #import "ESJsonFormatManager.h" 11 | #import "ESJsonFormatSetting.h" 12 | 13 | @implementation ESClassInfo 14 | 15 | - (instancetype)initWithClassNameKey:(NSString *)classNameKey ClassName:(NSString *)className classDic:(NSDictionary *)classDic 16 | { 17 | self = [super init]; 18 | if (self) { 19 | self.classNameKey = classNameKey; 20 | self.className = className; 21 | self.classDic = classDic; 22 | } 23 | return self; 24 | } 25 | 26 | - (NSMutableDictionary *)propertyClassDic{ 27 | if (!_propertyClassDic) { 28 | _propertyClassDic = [NSMutableDictionary dictionary]; 29 | } 30 | return _propertyClassDic; 31 | } 32 | 33 | - (NSMutableDictionary *)propertyArrayDic{ 34 | if (!_propertyArrayDic) { 35 | _propertyArrayDic = [NSMutableDictionary dictionary]; 36 | } 37 | return _propertyArrayDic; 38 | } 39 | 40 | - (NSArray *)atClassArray{ 41 | NSMutableArray *result = [NSMutableArray array]; 42 | [self.propertyClassDic enumerateKeysAndObjectsUsingBlock:^(id key, ESClassInfo *classInfo, BOOL *stop) { 43 | [result addObject:classInfo]; 44 | [result addObjectsFromArray:classInfo.atClassArray]; 45 | }]; 46 | 47 | [self.propertyArrayDic enumerateKeysAndObjectsUsingBlock:^(id key, ESClassInfo *classInfo, BOOL *stop) { 48 | if ([ESJsonFormatSetting defaultSetting].useGeneric) { 49 | [result addObject:classInfo]; 50 | } 51 | [result addObjectsFromArray:classInfo.atClassArray]; 52 | }]; 53 | 54 | return [result copy]; 55 | } 56 | 57 | - (NSString *)atClassContent{ 58 | NSArray *atClassArray = self.atClassArray; 59 | if (atClassArray.count==0) { 60 | return @""; 61 | } 62 | 63 | NSMutableArray *array = [NSMutableArray arrayWithArray:atClassArray]; 64 | 65 | NSMutableString *resultStr = [NSMutableString stringWithFormat:@"@class "]; 66 | for (ESClassInfo *classInfo in array) { 67 | [resultStr appendFormat:@"%@,",classInfo.className]; 68 | } 69 | 70 | if ([resultStr hasSuffix:@","]) { 71 | resultStr = [NSMutableString stringWithString:[resultStr substringToIndex:resultStr.length-1]]; 72 | } 73 | [resultStr appendString:@";"]; 74 | return resultStr; 75 | } 76 | 77 | - (NSString *)propertyContent{ 78 | return [ESJsonFormatManager parsePropertyContentWithClassInfo:self]; 79 | } 80 | 81 | - (NSString *)classContentForH{ 82 | return [ESJsonFormatManager parseClassHeaderContentWithClassInfo:self]; 83 | } 84 | 85 | 86 | - (NSString *)classContentForM{ 87 | return [ESJsonFormatManager parseClassImpContentWithClassInfo:self]; 88 | } 89 | 90 | 91 | - (NSString *)classInsertTextViewContentForH{ 92 | NSMutableString *result = [NSMutableString stringWithFormat:@""]; 93 | for (NSString *key in self.propertyClassDic) { 94 | ESClassInfo *classInfo = self.propertyClassDic[key]; 95 | [result appendFormat:@"%@\n\n",classInfo.classContentForH]; 96 | [result appendString:classInfo.classInsertTextViewContentForH]; 97 | } 98 | 99 | for (NSString *key in self.propertyArrayDic) { 100 | ESClassInfo *classInfo = self.propertyArrayDic[key]; 101 | [result appendFormat:@"%@\n\n",classInfo.classContentForH]; 102 | [result appendString:classInfo.classInsertTextViewContentForH]; 103 | } 104 | return result; 105 | } 106 | 107 | - (NSString *)classInsertTextViewContentForM{ 108 | NSMutableString *result = [NSMutableString stringWithFormat:@""]; 109 | for (NSString *key in self.propertyClassDic) { 110 | ESClassInfo *classInfo = self.propertyClassDic[key]; 111 | [result appendFormat:@"%@\n\n",classInfo.classContentForM]; 112 | [result appendString:classInfo.classInsertTextViewContentForM]; 113 | } 114 | 115 | for (NSString *key in self.propertyArrayDic) { 116 | ESClassInfo *classInfo = self.propertyArrayDic[key]; 117 | [result appendFormat:@"%@\n\n",classInfo.classContentForM]; 118 | [result appendString:classInfo.classInsertTextViewContentForM]; 119 | } 120 | return result; 121 | 122 | } 123 | 124 | - (void)createFileWithFolderPath:(NSString *)folderPath{ 125 | for (NSString *key in self.propertyClassDic) { 126 | ESClassInfo *classInfo = self.propertyClassDic[key]; 127 | [classInfo createFileWithFolderPath:folderPath]; 128 | } 129 | 130 | for (NSString *key in self.propertyArrayDic) { 131 | ESClassInfo *classInfo = self.propertyArrayDic[key]; 132 | [classInfo createFileWithFolderPath:folderPath]; 133 | } 134 | [ESJsonFormatManager createFileWithFolderPath:folderPath classInfo:self]; 135 | } 136 | 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /ESJsonFormat/Model/ESFormatInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESFormatInfo.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ESFormatInfo : NSObject 12 | 13 | @property (nonatomic, copy) NSString *pasteboardContent; 14 | @property (nonatomic, copy) NSString *writeToMContent; 15 | @property (nonatomic, copy) NSString *rootClassImplementMethodOfMJExtensionContent; 16 | @property (nonatomic, strong) NSMutableArray *classInfos; 17 | 18 | /** 19 | * @class 内容,用于在不创建文件的模式下使用。 20 | */ 21 | @property (nonatomic, copy) NSString *atClassContent; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /ESJsonFormat/Model/ESFormatInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESFormatInfo.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESFormatInfo.h" 10 | #import "ESClassInfo.h" 11 | 12 | @implementation ESFormatInfo 13 | 14 | 15 | -(NSMutableArray *)classInfos{ 16 | if (!_classInfos) { 17 | _classInfos = [NSMutableArray array]; 18 | } 19 | return _classInfos; 20 | } 21 | 22 | -(NSString *)atClassContent{ 23 | if (!self.classInfos.count) return nil; 24 | NSMutableString *resultStr = [NSMutableString stringWithFormat:@"\n@class %@",[[self.classInfos firstObject] className]]; 25 | for (int i=0; i 10 | 11 | @interface ESPair : NSObject 12 | @property (nonatomic) id first; 13 | @property (nonatomic) id second; 14 | + (instancetype) createWithFirst:(id)first second:(id)second; 15 | @end 16 | -------------------------------------------------------------------------------- /ESJsonFormat/Model/ESPair.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESPair.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/5. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESPair.h" 10 | 11 | @implementation ESPair 12 | 13 | +(instancetype)createWithFirst:(id)first second:(id)second{ 14 | ESPair *pair = [[ESPair alloc] init]; 15 | pair.first = first; 16 | pair.second = second; 17 | return pair; 18 | } 19 | @end 20 | -------------------------------------------------------------------------------- /ESJsonFormat/Model/ESPbxprojInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESPbxprojInfo.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ESPbxprojInfo : NSObject 12 | @property (nonatomic, copy, readonly) NSString *classPrefix; 13 | @property (nonatomic, copy, readonly) NSString *organizationName; 14 | @property (nonatomic, copy, readonly) NSString *productName; 15 | 16 | +(instancetype)shareInstance; 17 | -(void)setParamsWithPath:(NSString *)path; 18 | @end 19 | -------------------------------------------------------------------------------- /ESJsonFormat/Model/ESPbxprojInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESPbxprojInfo.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/6/28. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESPbxprojInfo.h" 10 | 11 | 12 | static ESPbxprojInfo *instance; 13 | 14 | @implementation ESPbxprojInfo 15 | 16 | +(instancetype)shareInstance{ 17 | static dispatch_once_t predicate; 18 | dispatch_once(&predicate, ^{ 19 | instance = [[ESPbxprojInfo alloc] init]; 20 | }); 21 | return instance; 22 | } 23 | 24 | -(void)setParamsWithPath:(NSString *)path{ 25 | NSData *pbxprojData = [NSData dataWithContentsOfFile:path]; 26 | NSString *pbxprojStr = [[NSString alloc] initWithData:pbxprojData encoding:NSUTF8StringEncoding]; 27 | _classPrefix = [self matchStringWithKeyWord:@"CLASSPREFIX" matchInString:pbxprojStr]; 28 | _organizationName = [self matchStringWithKeyWord:@"ORGANIZATIONNAME" matchInString:pbxprojStr]; 29 | _productName = [self matchStringWithKeyWord:@"productName" matchInString:pbxprojStr]; 30 | } 31 | 32 | -(NSString *)matchStringWithKeyWord:(NSString *)keyWord matchInString:(NSString *)matchString{ 33 | NSString *resultStr = @""; 34 | NSError *error; 35 | // 创建NSRegularExpression对象并指定正则表达式 36 | NSString *prefixStr = [NSString stringWithFormat:@"%@ = ",keyWord]; 37 | NSRegularExpression *regex = [NSRegularExpression 38 | regularExpressionWithPattern:[NSString stringWithFormat:@"%@[a-zA-Z0-9\u4e00-\u9fa5]+;",prefixStr] 39 | options:0 40 | error:&error]; 41 | if (!error) { 42 | // 获取特特定字符串的范围 43 | NSTextCheckingResult *match = [regex firstMatchInString:matchString 44 | options:0 45 | range:NSMakeRange(0, [matchString length])]; 46 | if (match) { 47 | // 截获特定的字符串 48 | NSString *result = [matchString substringWithRange:match.range]; 49 | resultStr = [result substringWithRange:NSMakeRange(prefixStr.length, result.length-prefixStr.length-1)]; 50 | } 51 | }; 52 | return resultStr; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /ESJsonFormat/Setting/ESJsonFormatSetting.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESJsonFormatSetting.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/19. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ESJsonFormatSetting : NSObject 12 | 13 | + (ESJsonFormatSetting *)defaultSetting; 14 | 15 | @property BOOL useGeneric; 16 | @property BOOL impOjbClassInArray; 17 | @property BOOL outputToFiles; 18 | @property BOOL uppercaseKeyWordForId; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /ESJsonFormat/Setting/ESJsonFormatSetting.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESJsonFormatSetting.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/19. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESJsonFormatSetting.h" 10 | 11 | 12 | NSString *const kESJsonFormatGeneric = @"com.EnjoySR.ESJsonFormat.Generic"; 13 | NSString *const kESJsonFormatOutputToFiles = @"com.EnjoySR.ESJsonFormat.OutputToFiles"; 14 | NSString *const kESJsonFormatImpObjClassInArray = @"com.EnjoySR.ESJsonFormat.ImpObjClassInArray"; 15 | NSString *const kESJsonFormatUppercaseKeyWordForId = @"com.EnjoySR.ESJsonFormat.UppercaseKeyWordForId"; 16 | 17 | @implementation ESJsonFormatSetting 18 | 19 | + (ESJsonFormatSetting *)defaultSetting 20 | { 21 | static dispatch_once_t once; 22 | static ESJsonFormatSetting *defaultSetting; 23 | dispatch_once(&once, ^ { 24 | defaultSetting = [[ESJsonFormatSetting alloc] init]; 25 | NSDictionary *defaults = @{kESJsonFormatGeneric: @YES, 26 | kESJsonFormatOutputToFiles: @NO, 27 | kESJsonFormatImpObjClassInArray: @YES, 28 | kESJsonFormatUppercaseKeyWordForId: @NO}; 29 | [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; 30 | }); 31 | return defaultSetting; 32 | } 33 | 34 | - (void)setUseGeneric:(BOOL)useGeneric{ 35 | [[NSUserDefaults standardUserDefaults] setBool:useGeneric forKey:kESJsonFormatGeneric]; 36 | [[NSUserDefaults standardUserDefaults] synchronize]; 37 | } 38 | 39 | - (BOOL)useGeneric{ 40 | return [[NSUserDefaults standardUserDefaults] boolForKey:kESJsonFormatGeneric]; 41 | } 42 | 43 | - (void)setImpOjbClassInArray:(BOOL)impOjbClassInArray{ 44 | [[NSUserDefaults standardUserDefaults] setBool:impOjbClassInArray forKey:kESJsonFormatImpObjClassInArray]; 45 | [[NSUserDefaults standardUserDefaults] synchronize]; 46 | } 47 | 48 | - (BOOL)impOjbClassInArray{ 49 | return [[NSUserDefaults standardUserDefaults] boolForKey:kESJsonFormatImpObjClassInArray]; 50 | } 51 | 52 | - (void)setOutputToFiles:(BOOL)outputToFiles{ 53 | [[NSUserDefaults standardUserDefaults] setBool:outputToFiles forKey:kESJsonFormatOutputToFiles]; 54 | [[NSUserDefaults standardUserDefaults] synchronize]; 55 | } 56 | 57 | - (BOOL)outputToFiles{ 58 | return [[NSUserDefaults standardUserDefaults] boolForKey:kESJsonFormatOutputToFiles]; 59 | } 60 | 61 | - (void)setUppercaseKeyWordForId:(BOOL)uppercaseKeyWordForId{ 62 | [[NSUserDefaults standardUserDefaults] setBool:uppercaseKeyWordForId forKey:kESJsonFormatUppercaseKeyWordForId]; 63 | [[NSUserDefaults standardUserDefaults] synchronize]; 64 | } 65 | 66 | - (BOOL)uppercaseKeyWordForId{ 67 | return [[NSUserDefaults standardUserDefaults] boolForKey:kESJsonFormatUppercaseKeyWordForId]; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /ESJsonFormat/Utils/ESUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESUtils.h 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/12. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ESUtils : NSObject 12 | 13 | /** 14 | * 获取Xcode大版本 15 | * 16 | * @return 17 | */ 18 | + (NSInteger)XcodePreVsersion; 19 | 20 | /** 21 | * 是否是Xcode7或者之后 22 | * 23 | * @return 24 | */ 25 | + (BOOL)isXcode7AndLater; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ESJsonFormat/Utils/ESUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESUtils.m 3 | // ESJsonFormat 4 | // 5 | // Created by 尹桥印 on 15/7/12. 6 | // Copyright (c) 2015年 EnjoySR. All rights reserved. 7 | // 8 | 9 | #import "ESUtils.h" 10 | 11 | @implementation ESUtils 12 | 13 | + (NSInteger)XcodePreVsersion{ 14 | NSAppleScript *_script = [[NSAppleScript alloc] initWithSource:@"do shell script \"xcodebuild -version\""]; 15 | NSDictionary *_error = [NSDictionary new]; 16 | NSAppleEventDescriptor *des =[_script executeAndReturnError:&_error]; 17 | if (_error.count == 0) { 18 | NSString *desStr = des.stringValue; 19 | NSRange range = [desStr rangeOfString:@"Xcode "]; 20 | NSInteger version = 0; 21 | if (range.location != NSNotFound && desStr.length>range.length) { 22 | version = [[desStr substringWithRange:NSMakeRange(range.length, 1)] integerValue]; 23 | } 24 | return version; 25 | } 26 | else{ 27 | return 0; 28 | } 29 | } 30 | 31 | + (BOOL)isXcode7AndLater{ 32 | return [self XcodePreVsersion]>=7; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 EnjoySR 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### ESJsonFormat-Xcode 2 | 将JSON格式化输出为模型的属性    个人活动范围>[Weibo-EnjoySR](http://weibo.com/EnjoySR) 3 | 4 | **写在之前的注意** 5 | > * **JSON中的key对应的value为Null的话会格式化成NSString类型** 6 | > * **格式化之前光标放在你需要添加属性的地方** 7 | > * **如果不输出到文件,RootClass需要自己手动创建,插件只负责RootClass里面的属性生成** 8 | > * **生成的 MJExtension 框架中objectClassInArray方法(类方法)** 9 | > * **Xcode 8及之后使用插件见:[http://www.cocoachina.com/ios/20161207/18313.html](http://www.cocoachina.com/ios/20161207/18313.html)** 10 | 11 | 12 | #### 怎么安装: 13 | 14 | 方式1:下载-Xcode打开-Command+B-重启Xcode 15 | 16 | 方式2:通过[Alcatraz](http://alcatraz.io/)安装,搜索 `ESJsonFormat` 17 | 18 | 方式3:下载-解压plugin文件夹中zip到`~/Library/Application Support/Developer/Shared/Xcode/Plug-ins`-重启Xcode 19 | 20 | 21 | #### 怎么使用: 22 | 23 | Window-ESJsonFormat-输入Json-Enter **OR** 快捷键(Control+Shift+J)-输入JSON-Enter 24 | 25 | ![Screenshot](https://github.com/EnjoySR/ESJsonFormat-Xcode/blob/master/ScreenShot/ScreenShot1.png) 26 | 27 | 关于设置: 28 | 29 | ![Screenshot](https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/master/ScreenShot/Setting.png) 30 | 31 | 打开方式:Xcode菜单-Window-ESJsonFormat-Setting 32 | 33 | * 1)是否生成的 MJExtension 框架中objectClassInArray方法(类方法,默认勾选) 34 | * 2)是否格式化输出泛型(Xcode 7 及之后才有效,默认勾选) 35 | * 3)是否输出到文件(如果勾选,不用自己新建 RootClass。默认`不勾选`) 36 | * 4)key为id关键字的话是否大写(默认`不勾选`) 37 | * 注:输出到文件的内容还需要添加什么的可以联系我,人个认为不用像 JSON Accelerator 一样生成字典转模型的方法以及@synthesize修饰符,建议使用-> [MJExtension](https://github.com/CoderMJLee/MJExtension),保型模型清爽干净。 38 | 39 | 40 | #### 功能说明: 41 | > -0.1 42 | 43 | * 通过JSON字符串生成对应属性 44 | * 通过文件写入的方式生成到.m文件 45 | * 支持输入嵌套模型名称 46 | 47 | > -0.2 48 | 49 | * 支持Swift 50 | * 修复JSON的value的值为Null的时候多出来的空行 51 | * 修复BOOL类型值格式化失效问题 52 | 53 | > -0.3 54 | 55 | * 支持生成MJExtension框架中objectClassInArray方法 56 | * 修复数组嵌套多级,里面子数组不能格式化的Bug 57 | 58 | > -0.4 59 | 60 | * 支持格式输出到文件 61 | * 支持格式输出泛型(Xcode 7及之后) 62 | 63 | > -0.5 64 | 65 | * 支持更新 Xcode 9 66 | 67 | #### Alcatraz 68 | * 支持 [Alcatraz](http://alcatraz.io/) ,请搜索 `ESJsonFormat` 69 | 70 | ![Screenshot](https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/master/ScreenShot/ScreenShot4.jpeg) 71 | 72 | #### 效果: 73 | 简单模型 74 | 75 | ![Screenshot](https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/master/ScreenShot/ScreenShot3.gif) 76 | 77 | 复杂模型 78 | 79 | ![Screenshot](https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/master/ScreenShot/ScreenShot2.gif) 80 | 81 | 图中的JSON格式 82 | ~~~ 83 | { 84 | "name": "王五", 85 | "gender": "man", 86 | "age": 15, 87 | "height": "140cm" 88 | } 89 | ~~~ 90 | 91 | ~~~ 92 | { 93 | "name": "王五", 94 | "gender": "man", 95 | "age": 15, 96 | "height": "140cm", 97 | "addr": { 98 | "province": "fujian", 99 | "city": "quanzhou", 100 | "code": "300000" 101 | }, 102 | "hobby": [ 103 | { 104 | "name": "billiards", 105 | "code": "1" 106 | }, 107 | { 108 | "name": "computerGame", 109 | "code": "2" 110 | } 111 | ] 112 | } 113 | ~~~ 114 | 115 | #### 其他: 116 | 117 | * 如在使用过程中需要到问题,请你Issues我。 118 | * 有什么好的想法也可以Issues我。 119 | * 如果你半夜睡不着觉也可以Issues我。 120 | 121 | 122 | Thanks:[GsonFormat](https://github.com/zzz40500/GsonFormat)、[VVDocumenter-Xcode](https://github.com/onevcat/VVDocumenter-Xcode)、[MJExtension](https://github.com/CoderMJLee/MJExtension) 123 | -------------------------------------------------------------------------------- /ScreenShot/ScreenShot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/ScreenShot/ScreenShot1.png -------------------------------------------------------------------------------- /ScreenShot/ScreenShot2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/ScreenShot/ScreenShot2.gif -------------------------------------------------------------------------------- /ScreenShot/ScreenShot3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/ScreenShot/ScreenShot3.gif -------------------------------------------------------------------------------- /ScreenShot/ScreenShot4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/ScreenShot/ScreenShot4.jpeg -------------------------------------------------------------------------------- /ScreenShot/ScreenShot5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/ScreenShot/ScreenShot5.gif -------------------------------------------------------------------------------- /ScreenShot/ScreenShot6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/ScreenShot/ScreenShot6.gif -------------------------------------------------------------------------------- /ScreenShot/ScreenShot7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/ScreenShot/ScreenShot7.gif -------------------------------------------------------------------------------- /ScreenShot/Setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/ScreenShot/Setting.png -------------------------------------------------------------------------------- /plugin/ESJsonFormat.xcplugin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EnjoySR/ESJsonFormat-Xcode/761e20d0334233346748565e58affb4ab5b04c23/plugin/ESJsonFormat.xcplugin.zip --------------------------------------------------------------------------------