├── .gitignore ├── LICENSE.md ├── MRRouter.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── SuHe.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── MRRouter.xcscheme │ └── xcschememanagement.plist ├── MRRouter ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── FreeMarketViewController.h ├── FreeMarketViewController.m ├── HelloViewController.h ├── HelloViewController.m ├── Info.plist ├── MRRouter.h ├── MRRouter.m ├── SecondViewController.h ├── SecondViewController.m ├── TestViewController.h ├── TestViewController.m ├── ViewController.h ├── ViewController.m ├── main.m └── route_map.plist ├── MRRouterTests ├── Info.plist └── MRRouterTests.m ├── Products.zip └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X Finder 2 | .DS_Store 3 | 4 | # Xcode per-user config 5 | *.mode1 6 | *.mode1v3 7 | *.mode2v3 8 | *.perspective 9 | *.perspectivev3 10 | *.pbxuser 11 | xcuserdata 12 | *.xccheckout 13 | 14 | # Build products 15 | build/ 16 | *.o 17 | *.LinkFileList 18 | *.hmap 19 | 20 | # Automatic backup files 21 | *~.nib/ 22 | *.swp 23 | *~ 24 | *.dat 25 | *.dep 26 | 27 | # Cocoapods 28 | Pods 29 | 30 | # AppCode specific files 31 | .idea/ 32 | *.iml 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Zip Lee 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 | -------------------------------------------------------------------------------- /MRRouter.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8E35D6D91C3500F700EC2D34 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E35D6D81C3500F700EC2D34 /* main.m */; }; 11 | 8E35D6DC1C3500F700EC2D34 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E35D6DB1C3500F700EC2D34 /* AppDelegate.m */; }; 12 | 8E35D6DF1C3500F700EC2D34 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E35D6DE1C3500F700EC2D34 /* ViewController.m */; }; 13 | 8E35D6E21C3500F700EC2D34 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8E35D6E01C3500F700EC2D34 /* Main.storyboard */; }; 14 | 8E35D6E41C3500F700EC2D34 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8E35D6E31C3500F700EC2D34 /* Assets.xcassets */; }; 15 | 8E35D6E71C3500F700EC2D34 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8E35D6E51C3500F700EC2D34 /* LaunchScreen.storyboard */; }; 16 | 8E35D6F21C3500F700EC2D34 /* MRRouterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E35D6F11C3500F700EC2D34 /* MRRouterTests.m */; }; 17 | 8E35D7001C38D78C00EC2D34 /* route_map.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8E35D6FF1C38D78C00EC2D34 /* route_map.plist */; }; 18 | 8E94C2A31C8D189200D60077 /* MRRouter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E94C2A21C8D189200D60077 /* MRRouter.m */; }; 19 | 8EB2104D1C3B9B9F009A852F /* TestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EB2104C1C3B9B9F009A852F /* TestViewController.m */; }; 20 | 8EB210501C3BB20C009A852F /* SecondViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EB2104F1C3BB20C009A852F /* SecondViewController.m */; }; 21 | 8EB210531C3BB509009A852F /* FreeMarketViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EB210521C3BB509009A852F /* FreeMarketViewController.m */; }; 22 | 8EB210561C3BBD7C009A852F /* HelloViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EB210551C3BBD7C009A852F /* HelloViewController.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 8E35D6EE1C3500F700EC2D34 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 8E35D6CC1C3500F700EC2D34 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 8E35D6D31C3500F700EC2D34; 31 | remoteInfo = MRRouter; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 8E35D6D41C3500F700EC2D34 /* MRRouter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MRRouter.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 8E35D6D81C3500F700EC2D34 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 38 | 8E35D6DA1C3500F700EC2D34 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 39 | 8E35D6DB1C3500F700EC2D34 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 40 | 8E35D6DD1C3500F700EC2D34 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 41 | 8E35D6DE1C3500F700EC2D34 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 42 | 8E35D6E11C3500F700EC2D34 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 43 | 8E35D6E31C3500F700EC2D34 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 44 | 8E35D6E61C3500F700EC2D34 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 45 | 8E35D6E81C3500F700EC2D34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | 8E35D6ED1C3500F700EC2D34 /* MRRouterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MRRouterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 8E35D6F11C3500F700EC2D34 /* MRRouterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MRRouterTests.m; sourceTree = ""; }; 48 | 8E35D6F31C3500F700EC2D34 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | 8E35D6FF1C38D78C00EC2D34 /* route_map.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = route_map.plist; sourceTree = ""; }; 50 | 8E94C2A11C8D189200D60077 /* MRRouter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MRRouter.h; sourceTree = ""; }; 51 | 8E94C2A21C8D189200D60077 /* MRRouter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MRRouter.m; sourceTree = ""; }; 52 | 8EB2104B1C3B9B9F009A852F /* TestViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestViewController.h; sourceTree = ""; }; 53 | 8EB2104C1C3B9B9F009A852F /* TestViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestViewController.m; sourceTree = ""; }; 54 | 8EB2104E1C3BB20C009A852F /* SecondViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecondViewController.h; sourceTree = ""; }; 55 | 8EB2104F1C3BB20C009A852F /* SecondViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecondViewController.m; sourceTree = ""; }; 56 | 8EB210511C3BB509009A852F /* FreeMarketViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FreeMarketViewController.h; sourceTree = ""; }; 57 | 8EB210521C3BB509009A852F /* FreeMarketViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FreeMarketViewController.m; sourceTree = ""; }; 58 | 8EB210541C3BBD7C009A852F /* HelloViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HelloViewController.h; sourceTree = ""; }; 59 | 8EB210551C3BBD7C009A852F /* HelloViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HelloViewController.m; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 8E35D6D11C3500F700EC2D34 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 8E35D6EA1C3500F700EC2D34 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | /* End PBXFrameworksBuildPhase section */ 78 | 79 | /* Begin PBXGroup section */ 80 | 8E35D6CB1C3500F700EC2D34 = { 81 | isa = PBXGroup; 82 | children = ( 83 | 8E35D6D61C3500F700EC2D34 /* MRRouter */, 84 | 8E35D6F01C3500F700EC2D34 /* MRRouterTests */, 85 | 8E35D6D51C3500F700EC2D34 /* Products */, 86 | ); 87 | sourceTree = ""; 88 | }; 89 | 8E35D6D51C3500F700EC2D34 /* Products */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 8E35D6D41C3500F700EC2D34 /* MRRouter.app */, 93 | 8E35D6ED1C3500F700EC2D34 /* MRRouterTests.xctest */, 94 | ); 95 | name = Products; 96 | sourceTree = ""; 97 | }; 98 | 8E35D6D61C3500F700EC2D34 /* MRRouter */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 8E35D6DA1C3500F700EC2D34 /* AppDelegate.h */, 102 | 8E35D6DB1C3500F700EC2D34 /* AppDelegate.m */, 103 | 8E35D6DD1C3500F700EC2D34 /* ViewController.h */, 104 | 8E35D6DE1C3500F700EC2D34 /* ViewController.m */, 105 | 8EB2104B1C3B9B9F009A852F /* TestViewController.h */, 106 | 8EB2104C1C3B9B9F009A852F /* TestViewController.m */, 107 | 8EB2104E1C3BB20C009A852F /* SecondViewController.h */, 108 | 8EB2104F1C3BB20C009A852F /* SecondViewController.m */, 109 | 8EB210511C3BB509009A852F /* FreeMarketViewController.h */, 110 | 8EB210521C3BB509009A852F /* FreeMarketViewController.m */, 111 | 8EB210541C3BBD7C009A852F /* HelloViewController.h */, 112 | 8EB210551C3BBD7C009A852F /* HelloViewController.m */, 113 | 8E94C2A11C8D189200D60077 /* MRRouter.h */, 114 | 8E94C2A21C8D189200D60077 /* MRRouter.m */, 115 | 8E35D6E01C3500F700EC2D34 /* Main.storyboard */, 116 | 8E35D6E31C3500F700EC2D34 /* Assets.xcassets */, 117 | 8E35D6E51C3500F700EC2D34 /* LaunchScreen.storyboard */, 118 | 8E35D6E81C3500F700EC2D34 /* Info.plist */, 119 | 8E35D6D71C3500F700EC2D34 /* Supporting Files */, 120 | ); 121 | path = MRRouter; 122 | sourceTree = ""; 123 | }; 124 | 8E35D6D71C3500F700EC2D34 /* Supporting Files */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 8E35D6D81C3500F700EC2D34 /* main.m */, 128 | 8E35D6FF1C38D78C00EC2D34 /* route_map.plist */, 129 | ); 130 | name = "Supporting Files"; 131 | sourceTree = ""; 132 | }; 133 | 8E35D6F01C3500F700EC2D34 /* MRRouterTests */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 8E35D6F11C3500F700EC2D34 /* MRRouterTests.m */, 137 | 8E35D6F31C3500F700EC2D34 /* Info.plist */, 138 | ); 139 | path = MRRouterTests; 140 | sourceTree = ""; 141 | }; 142 | /* End PBXGroup section */ 143 | 144 | /* Begin PBXNativeTarget section */ 145 | 8E35D6D31C3500F700EC2D34 /* MRRouter */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = 8E35D6F61C3500F700EC2D34 /* Build configuration list for PBXNativeTarget "MRRouter" */; 148 | buildPhases = ( 149 | 8E35D6D01C3500F700EC2D34 /* Sources */, 150 | 8E35D6D11C3500F700EC2D34 /* Frameworks */, 151 | 8E35D6D21C3500F700EC2D34 /* Resources */, 152 | ); 153 | buildRules = ( 154 | ); 155 | dependencies = ( 156 | ); 157 | name = MRRouter; 158 | productName = MRRouter; 159 | productReference = 8E35D6D41C3500F700EC2D34 /* MRRouter.app */; 160 | productType = "com.apple.product-type.application"; 161 | }; 162 | 8E35D6EC1C3500F700EC2D34 /* MRRouterTests */ = { 163 | isa = PBXNativeTarget; 164 | buildConfigurationList = 8E35D6F91C3500F700EC2D34 /* Build configuration list for PBXNativeTarget "MRRouterTests" */; 165 | buildPhases = ( 166 | 8E35D6E91C3500F700EC2D34 /* Sources */, 167 | 8E35D6EA1C3500F700EC2D34 /* Frameworks */, 168 | 8E35D6EB1C3500F700EC2D34 /* Resources */, 169 | ); 170 | buildRules = ( 171 | ); 172 | dependencies = ( 173 | 8E35D6EF1C3500F700EC2D34 /* PBXTargetDependency */, 174 | ); 175 | name = MRRouterTests; 176 | productName = MRRouterTests; 177 | productReference = 8E35D6ED1C3500F700EC2D34 /* MRRouterTests.xctest */; 178 | productType = "com.apple.product-type.bundle.unit-test"; 179 | }; 180 | /* End PBXNativeTarget section */ 181 | 182 | /* Begin PBXProject section */ 183 | 8E35D6CC1C3500F700EC2D34 /* Project object */ = { 184 | isa = PBXProject; 185 | attributes = { 186 | LastUpgradeCheck = 0720; 187 | ORGANIZATIONNAME = juangua; 188 | TargetAttributes = { 189 | 8E35D6D31C3500F700EC2D34 = { 190 | CreatedOnToolsVersion = 7.2; 191 | }; 192 | 8E35D6EC1C3500F700EC2D34 = { 193 | CreatedOnToolsVersion = 7.2; 194 | TestTargetID = 8E35D6D31C3500F700EC2D34; 195 | }; 196 | }; 197 | }; 198 | buildConfigurationList = 8E35D6CF1C3500F700EC2D34 /* Build configuration list for PBXProject "MRRouter" */; 199 | compatibilityVersion = "Xcode 3.2"; 200 | developmentRegion = English; 201 | hasScannedForEncodings = 0; 202 | knownRegions = ( 203 | en, 204 | Base, 205 | ); 206 | mainGroup = 8E35D6CB1C3500F700EC2D34; 207 | productRefGroup = 8E35D6D51C3500F700EC2D34 /* Products */; 208 | projectDirPath = ""; 209 | projectRoot = ""; 210 | targets = ( 211 | 8E35D6D31C3500F700EC2D34 /* MRRouter */, 212 | 8E35D6EC1C3500F700EC2D34 /* MRRouterTests */, 213 | ); 214 | }; 215 | /* End PBXProject section */ 216 | 217 | /* Begin PBXResourcesBuildPhase section */ 218 | 8E35D6D21C3500F700EC2D34 /* Resources */ = { 219 | isa = PBXResourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | 8E35D6E71C3500F700EC2D34 /* LaunchScreen.storyboard in Resources */, 223 | 8E35D6E41C3500F700EC2D34 /* Assets.xcassets in Resources */, 224 | 8E35D7001C38D78C00EC2D34 /* route_map.plist in Resources */, 225 | 8E35D6E21C3500F700EC2D34 /* Main.storyboard in Resources */, 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | 8E35D6EB1C3500F700EC2D34 /* Resources */ = { 230 | isa = PBXResourcesBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | /* End PBXResourcesBuildPhase section */ 237 | 238 | /* Begin PBXSourcesBuildPhase section */ 239 | 8E35D6D01C3500F700EC2D34 /* Sources */ = { 240 | isa = PBXSourcesBuildPhase; 241 | buildActionMask = 2147483647; 242 | files = ( 243 | 8EB210501C3BB20C009A852F /* SecondViewController.m in Sources */, 244 | 8EB210531C3BB509009A852F /* FreeMarketViewController.m in Sources */, 245 | 8E35D6DF1C3500F700EC2D34 /* ViewController.m in Sources */, 246 | 8EB210561C3BBD7C009A852F /* HelloViewController.m in Sources */, 247 | 8E35D6DC1C3500F700EC2D34 /* AppDelegate.m in Sources */, 248 | 8E94C2A31C8D189200D60077 /* MRRouter.m in Sources */, 249 | 8E35D6D91C3500F700EC2D34 /* main.m in Sources */, 250 | 8EB2104D1C3B9B9F009A852F /* TestViewController.m in Sources */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | 8E35D6E91C3500F700EC2D34 /* Sources */ = { 255 | isa = PBXSourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | 8E35D6F21C3500F700EC2D34 /* MRRouterTests.m in Sources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | /* End PBXSourcesBuildPhase section */ 263 | 264 | /* Begin PBXTargetDependency section */ 265 | 8E35D6EF1C3500F700EC2D34 /* PBXTargetDependency */ = { 266 | isa = PBXTargetDependency; 267 | target = 8E35D6D31C3500F700EC2D34 /* MRRouter */; 268 | targetProxy = 8E35D6EE1C3500F700EC2D34 /* PBXContainerItemProxy */; 269 | }; 270 | /* End PBXTargetDependency section */ 271 | 272 | /* Begin PBXVariantGroup section */ 273 | 8E35D6E01C3500F700EC2D34 /* Main.storyboard */ = { 274 | isa = PBXVariantGroup; 275 | children = ( 276 | 8E35D6E11C3500F700EC2D34 /* Base */, 277 | ); 278 | name = Main.storyboard; 279 | sourceTree = ""; 280 | }; 281 | 8E35D6E51C3500F700EC2D34 /* LaunchScreen.storyboard */ = { 282 | isa = PBXVariantGroup; 283 | children = ( 284 | 8E35D6E61C3500F700EC2D34 /* Base */, 285 | ); 286 | name = LaunchScreen.storyboard; 287 | sourceTree = ""; 288 | }; 289 | /* End PBXVariantGroup section */ 290 | 291 | /* Begin XCBuildConfiguration section */ 292 | 8E35D6F41C3500F700EC2D34 /* Debug */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ALWAYS_SEARCH_USER_PATHS = NO; 296 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 297 | CLANG_CXX_LIBRARY = "libc++"; 298 | CLANG_ENABLE_MODULES = YES; 299 | CLANG_ENABLE_OBJC_ARC = YES; 300 | CLANG_WARN_BOOL_CONVERSION = YES; 301 | CLANG_WARN_CONSTANT_CONVERSION = YES; 302 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 303 | CLANG_WARN_EMPTY_BODY = YES; 304 | CLANG_WARN_ENUM_CONVERSION = YES; 305 | CLANG_WARN_INT_CONVERSION = YES; 306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 307 | CLANG_WARN_UNREACHABLE_CODE = YES; 308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 309 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 310 | COPY_PHASE_STRIP = NO; 311 | DEBUG_INFORMATION_FORMAT = dwarf; 312 | ENABLE_STRICT_OBJC_MSGSEND = YES; 313 | ENABLE_TESTABILITY = YES; 314 | GCC_C_LANGUAGE_STANDARD = gnu99; 315 | GCC_DYNAMIC_NO_PIC = NO; 316 | GCC_NO_COMMON_BLOCKS = YES; 317 | GCC_OPTIMIZATION_LEVEL = 0; 318 | GCC_PREPROCESSOR_DEFINITIONS = ( 319 | "DEBUG=1", 320 | "$(inherited)", 321 | ); 322 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 323 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 324 | GCC_WARN_UNDECLARED_SELECTOR = YES; 325 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 326 | GCC_WARN_UNUSED_FUNCTION = YES; 327 | GCC_WARN_UNUSED_VARIABLE = YES; 328 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 329 | MTL_ENABLE_DEBUG_INFO = YES; 330 | ONLY_ACTIVE_ARCH = YES; 331 | SDKROOT = iphoneos; 332 | TARGETED_DEVICE_FAMILY = "1,2"; 333 | }; 334 | name = Debug; 335 | }; 336 | 8E35D6F51C3500F700EC2D34 /* Release */ = { 337 | isa = XCBuildConfiguration; 338 | buildSettings = { 339 | ALWAYS_SEARCH_USER_PATHS = NO; 340 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 341 | CLANG_CXX_LIBRARY = "libc++"; 342 | CLANG_ENABLE_MODULES = YES; 343 | CLANG_ENABLE_OBJC_ARC = YES; 344 | CLANG_WARN_BOOL_CONVERSION = YES; 345 | CLANG_WARN_CONSTANT_CONVERSION = YES; 346 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 347 | CLANG_WARN_EMPTY_BODY = YES; 348 | CLANG_WARN_ENUM_CONVERSION = YES; 349 | CLANG_WARN_INT_CONVERSION = YES; 350 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 351 | CLANG_WARN_UNREACHABLE_CODE = YES; 352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 354 | COPY_PHASE_STRIP = NO; 355 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 356 | ENABLE_NS_ASSERTIONS = NO; 357 | ENABLE_STRICT_OBJC_MSGSEND = YES; 358 | GCC_C_LANGUAGE_STANDARD = gnu99; 359 | GCC_NO_COMMON_BLOCKS = YES; 360 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 361 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 362 | GCC_WARN_UNDECLARED_SELECTOR = YES; 363 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 364 | GCC_WARN_UNUSED_FUNCTION = YES; 365 | GCC_WARN_UNUSED_VARIABLE = YES; 366 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 367 | MTL_ENABLE_DEBUG_INFO = NO; 368 | SDKROOT = iphoneos; 369 | TARGETED_DEVICE_FAMILY = "1,2"; 370 | VALIDATE_PRODUCT = YES; 371 | }; 372 | name = Release; 373 | }; 374 | 8E35D6F71C3500F700EC2D34 /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 378 | CODE_SIGN_IDENTITY = ""; 379 | FRAMEWORK_SEARCH_PATHS = ( 380 | "$(inherited)", 381 | "$(PROJECT_DIR)/MRRouter", 382 | ); 383 | INFOPLIST_FILE = MRRouter/Info.plist; 384 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 385 | PRODUCT_BUNDLE_IDENTIFIER = juangua.MRRouter; 386 | PRODUCT_NAME = "$(TARGET_NAME)"; 387 | }; 388 | name = Debug; 389 | }; 390 | 8E35D6F81C3500F700EC2D34 /* Release */ = { 391 | isa = XCBuildConfiguration; 392 | buildSettings = { 393 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 394 | CODE_SIGN_IDENTITY = ""; 395 | FRAMEWORK_SEARCH_PATHS = ( 396 | "$(inherited)", 397 | "$(PROJECT_DIR)/MRRouter", 398 | ); 399 | INFOPLIST_FILE = MRRouter/Info.plist; 400 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 401 | PRODUCT_BUNDLE_IDENTIFIER = juangua.MRRouter; 402 | PRODUCT_NAME = "$(TARGET_NAME)"; 403 | }; 404 | name = Release; 405 | }; 406 | 8E35D6FA1C3500F700EC2D34 /* Debug */ = { 407 | isa = XCBuildConfiguration; 408 | buildSettings = { 409 | BUNDLE_LOADER = "$(TEST_HOST)"; 410 | INFOPLIST_FILE = MRRouterTests/Info.plist; 411 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 412 | PRODUCT_BUNDLE_IDENTIFIER = juangua.MRRouterTests; 413 | PRODUCT_NAME = "$(TARGET_NAME)"; 414 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MRRouter.app/MRRouter"; 415 | }; 416 | name = Debug; 417 | }; 418 | 8E35D6FB1C3500F700EC2D34 /* Release */ = { 419 | isa = XCBuildConfiguration; 420 | buildSettings = { 421 | BUNDLE_LOADER = "$(TEST_HOST)"; 422 | INFOPLIST_FILE = MRRouterTests/Info.plist; 423 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 424 | PRODUCT_BUNDLE_IDENTIFIER = juangua.MRRouterTests; 425 | PRODUCT_NAME = "$(TARGET_NAME)"; 426 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MRRouter.app/MRRouter"; 427 | }; 428 | name = Release; 429 | }; 430 | /* End XCBuildConfiguration section */ 431 | 432 | /* Begin XCConfigurationList section */ 433 | 8E35D6CF1C3500F700EC2D34 /* Build configuration list for PBXProject "MRRouter" */ = { 434 | isa = XCConfigurationList; 435 | buildConfigurations = ( 436 | 8E35D6F41C3500F700EC2D34 /* Debug */, 437 | 8E35D6F51C3500F700EC2D34 /* Release */, 438 | ); 439 | defaultConfigurationIsVisible = 0; 440 | defaultConfigurationName = Release; 441 | }; 442 | 8E35D6F61C3500F700EC2D34 /* Build configuration list for PBXNativeTarget "MRRouter" */ = { 443 | isa = XCConfigurationList; 444 | buildConfigurations = ( 445 | 8E35D6F71C3500F700EC2D34 /* Debug */, 446 | 8E35D6F81C3500F700EC2D34 /* Release */, 447 | ); 448 | defaultConfigurationIsVisible = 0; 449 | defaultConfigurationName = Release; 450 | }; 451 | 8E35D6F91C3500F700EC2D34 /* Build configuration list for PBXNativeTarget "MRRouterTests" */ = { 452 | isa = XCConfigurationList; 453 | buildConfigurations = ( 454 | 8E35D6FA1C3500F700EC2D34 /* Debug */, 455 | 8E35D6FB1C3500F700EC2D34 /* Release */, 456 | ); 457 | defaultConfigurationIsVisible = 0; 458 | defaultConfigurationName = Release; 459 | }; 460 | /* End XCConfigurationList section */ 461 | }; 462 | rootObject = 8E35D6CC1C3500F700EC2D34 /* Project object */; 463 | } 464 | -------------------------------------------------------------------------------- /MRRouter.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MRRouter.xcodeproj/xcuserdata/SuHe.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /MRRouter.xcodeproj/xcuserdata/SuHe.xcuserdatad/xcschemes/MRRouter.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /MRRouter.xcodeproj/xcuserdata/SuHe.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MRRouter.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 8E35D6D31C3500F700EC2D34 16 | 17 | primary 18 | 19 | 20 | 8E35D6EC1C3500F700EC2D34 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /MRRouter/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 15/12/31. 6 | // Copyright © 2015年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /MRRouter/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 15/12/31. 6 | // Copyright © 2015年 juangua. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /MRRouter/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /MRRouter/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /MRRouter/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /MRRouter/FreeMarketViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FreemarketViewController.h 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 16/1/5. 6 | // Copyright © 2016年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FreeMarketViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MRRouter/FreeMarketViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FreemarketViewController.m 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 16/1/5. 6 | // Copyright © 2016年 juangua. All rights reserved. 7 | // 8 | 9 | #import "FreeMarketViewController.h" 10 | #import "MRRouter.h" 11 | @interface FreeMarketViewController () 12 | 13 | @end 14 | 15 | @implementation FreeMarketViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | self.view.backgroundColor = [UIColor greenColor]; 20 | NSLog(@"%@", self.mr_parameters); 21 | } 22 | 23 | - (void)didReceiveMemoryWarning { 24 | [super didReceiveMemoryWarning]; 25 | // Dispose of any resources that can be recreated. 26 | } 27 | 28 | /* 29 | #pragma mark - Navigation 30 | 31 | // In a storyboard-based application, you will often want to do a little preparation before navigation 32 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 33 | // Get the new view controller using [segue destinationViewController]. 34 | // Pass the selected object to the new view controller. 35 | } 36 | */ 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /MRRouter/HelloViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HelloViewController.h 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 16/1/5. 6 | // Copyright © 2016年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HelloViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MRRouter/HelloViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HelloViewController.m 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 16/1/5. 6 | // Copyright © 2016年 juangua. All rights reserved. 7 | // 8 | 9 | #import "HelloViewController.h" 10 | #import "MRRouter.h" 11 | 12 | @interface HelloViewController () 13 | 14 | @end 15 | 16 | @implementation HelloViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.view.backgroundColor = [UIColor orangeColor]; 21 | NSLog(@"%@", self.mr_parameters); 22 | } 23 | 24 | - (void)didReceiveMemoryWarning { 25 | [super didReceiveMemoryWarning]; 26 | // Dispose of any resources that can be recreated. 27 | } 28 | 29 | /* 30 | #pragma mark - Navigation 31 | 32 | // In a storyboard-based application, you will often want to do a little preparation before navigation 33 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 34 | // Get the new view controller using [segue destinationViewController]. 35 | // Pass the selected object to the new view controller. 36 | } 37 | */ 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /MRRouter/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /MRRouter/MRRouter.h: -------------------------------------------------------------------------------- 1 | // 2 | // MRRouter.h 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 15/12/31. 6 | // Copyright © 2015年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void (^MRPrepareBlock)(id object); 12 | typedef void (^MRCompleteBlock)(id object); 13 | typedef void (^MRRouterRespondBlock)(id result); 14 | typedef id (^MRExecutingBlock)(NSString *sourceURL, NSDictionary *parameters); 15 | typedef void (^MRDefaultExecutingBlock)(id object, NSDictionary *parameters); 16 | 17 | @interface MRRouter : NSObject 18 | 19 | + (MRRouter *)sharedInstance; 20 | 21 | + (void)openURL:(NSString *)URLPattern; 22 | 23 | + (void)openURL:(NSString *)URLPattern parameters:(NSDictionary *)parameters; 24 | 25 | + (void)openURL:(NSString *)URLPattern parameters:(NSDictionary *)parameters respondBlock:(MRRouterRespondBlock)respondBlock; 26 | 27 | /** 28 | * Asks the router to execute some operations by a URL. 29 | * 30 | * @param URLPattern Some operations representing a URL. 31 | * @param parameters Information about the the URL. May be nil. 32 | * @param prepareBlock A block object containing the operation before open URL. May be nil. 33 | * @param completeBlock A block object containing the operation after open URL. May be nil. 34 | */ 35 | + (void)openURL:(NSString *)URLPattern parameters:(NSDictionary *)parameters prepareBlock:(MRPrepareBlock)prepareBlock completeBlock:(MRCompleteBlock)completeBlock; 36 | 37 | /** 38 | * Asks the router to execute some operations by a URL. 39 | * 40 | * @param URLPattern Some operations representing a URL. 41 | * @param parameters Information about the the URL. May be nil. 42 | * @param prepareBlock A block object containing the operation before open URL. May be nil. 43 | * @param completeBlock A block object containing the operation after open URL. May be nil. 44 | * @param respondBlock Target object will invoke this respond block which implenment by source object. 45 | */ 46 | + (void)openURL:(NSString *)URLPattern parameters:(NSDictionary *)parameters prepareBlock:(MRPrepareBlock)prepareBlock completeBlock:(MRCompleteBlock)completeBlock respondBlock:(MRRouterRespondBlock)respondBlock; 47 | 48 | 49 | /** 50 | * Return the object which match the URL. 51 | * 52 | * @param URLPattern Asks the router to get an object. 53 | * 54 | * @return The object which match the URL. May be nil; 55 | */ 56 | + (Class)matchClassWithURL:(NSString *)URLPattern; 57 | 58 | /** 59 | * Return the object which is alloc elsewhere by the URL. 60 | * 61 | * @param URLPattern Asks the router to get an object. 62 | * 63 | * @return The object which is alloced elsewhere, if it is not exist, return nil; 64 | */ 65 | + (id)existedInstanceWithURL:(NSString *)URLPattern; 66 | 67 | 68 | /** 69 | * Register some operations with URL. 70 | * 71 | * @param URLPattern Some operations representing a URL. If URLPattern already exists in the router, executingBlock takes its place. 72 | * @param executingBlock A block object containing the operation representing the URL. 73 | */ 74 | + (void)registerURL:(NSString *)URLPattern executingBlock:(MRExecutingBlock)executingBlock; 75 | 76 | /** 77 | * Map the URL to class name. 78 | * 79 | * @param URLPattern URL mapped with class name. If URLPattern already exists in the router, name takes its place. 80 | * @param name Class name mapped with URL. 81 | */ 82 | + (void)map:(NSString *)URLPattern toClassName:(NSString *)name; 83 | 84 | /** 85 | * Remove the URL from router. 86 | * 87 | * @param URLPattern Some operations representing a URL. 88 | */ 89 | + (void)removeURL:(NSString *)URLPattern; 90 | 91 | /** 92 | * Returns a Boolean value indicating whether the URL can be routed. 93 | * 94 | * @param URLPattern URL will be routed. 95 | */ 96 | + (BOOL)canOpenURL:(NSString *)URLPattern; 97 | 98 | /** 99 | * Load the Class-URL map when setting this property. 100 | */ 101 | @property (nonatomic, strong) NSString *mapFileName; 102 | 103 | /** 104 | * You could set the default execute block of router by yourself. If you register the URL with a executingBlock(see registerURL:URLPattern:executingBlock), defaultExecutingBlock will never be executed. 105 | */ 106 | @property (nonatomic, copy) MRDefaultExecutingBlock defaultExecutingBlock; 107 | 108 | /** 109 | * Prefix of class name which initialize in runtime. 110 | */ 111 | @property (nonatomic, copy) NSString * prefix; 112 | 113 | /** 114 | * Postfix of class name which initialize in runtime. 115 | */ 116 | @property (nonatomic, copy) NSString * postfix; 117 | 118 | /** 119 | * The super class type of router load with runtime. 120 | */ 121 | @property (nonatomic, assign) Class defaultClassType; 122 | 123 | @end 124 | 125 | @interface NSObject (MRParameters) 126 | 127 | @property (nonatomic, copy) NSDictionary *mr_parameters; 128 | @property (nonatomic, copy) NSString *mr_url; 129 | @property (nonatomic, copy) MRRouterRespondBlock mr_respondBlock; 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /MRRouter/MRRouter.m: -------------------------------------------------------------------------------- 1 | // 2 | // MRRouter.m 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 15/12/31. 6 | // Copyright © 2015年 juangua. All rights reserved. 7 | // 8 | 9 | #import "MRRouter.h" 10 | #import 11 | #import 12 | 13 | @implementation NSObject(Runtime) 14 | 15 | + (NSArray *)loadedClassNames { 16 | static dispatch_once_t once; 17 | static NSMutableArray * classNames; 18 | 19 | dispatch_once( &once, ^{ 20 | 21 | classNames = [[NSMutableArray alloc] init]; 22 | 23 | unsigned int classesCount = 0; 24 | Class * classes = objc_copyClassList( &classesCount ); 25 | 26 | for ( unsigned int i = 0; i < classesCount; ++i ) 27 | { 28 | Class classType = classes[i]; 29 | 30 | if ( class_isMetaClass( classType ) ) 31 | continue; 32 | 33 | Class superClass = class_getSuperclass( classType ); 34 | 35 | if ( nil == superClass ) 36 | continue; 37 | 38 | [classNames addObject:[NSString stringWithUTF8String:class_getName(classType)]]; 39 | } 40 | 41 | [classNames sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { 42 | return [obj1 compare:obj2]; 43 | }]; 44 | 45 | free( classes ); 46 | }); 47 | 48 | return classNames; 49 | } 50 | 51 | + (NSArray *)subClasses { 52 | NSMutableArray * results = [[NSMutableArray alloc] init]; 53 | 54 | for (NSString *className in [self loadedClassNames]) { 55 | Class classType = NSClassFromString( className ); 56 | if (classType == self) 57 | continue; 58 | //10.3beta版本的诡异crash,WKNS开头的类不是NSObject,无法调用isSubclassOfClass,暂时这么处理 59 | if ([NSStringFromClass(classType) containsString:@"WKNS"]) 60 | continue; 61 | if (NO == [classType isSubclassOfClass:self]) 62 | continue; 63 | 64 | [results addObject:[classType description]]; 65 | } 66 | 67 | return results; 68 | } 69 | 70 | - (void)parseParameters { 71 | [self.mr_parameters enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id _Nonnull value, BOOL * _Nonnull stop) { 72 | @try { 73 | objc_property_t property = class_getProperty(self.class, key.UTF8String); 74 | if (!property) 75 | { 76 | return; 77 | } 78 | //属性类型 79 | NSString *propertyAttribute = [NSString stringWithUTF8String:property_getAttributes(property)]; 80 | NSArray* attributeItems = [propertyAttribute componentsSeparatedByString:@","]; 81 | NSString *attributeString = [NSString stringWithUTF8String:property_getAttributes(property)]; 82 | NSString *typeString = [[attributeString componentsSeparatedByString:@","] objectAtIndex:0]; 83 | //类名,非基础类型 84 | NSString *classNameString = [self mr_getClassNameFromAttributeString:typeString]; 85 | 86 | if ([attributeItems containsObject:@"R"]) {//如果属性是只读的,就不要进行解析了 87 | return; 88 | } 89 | //基础类型 90 | if ([value isKindOfClass:[NSNumber class]]) { 91 | //当对应的属性为基础类型或者 NSNumber 时才处理 92 | if ([typeString isEqualToString:@"Td"] || [typeString isEqualToString:@"Ti"] || [typeString isEqualToString:@"Tf"] || [typeString isEqualToString:@"Tl"] || [typeString isEqualToString:@"Tc"] || [typeString isEqualToString:@"Ts"] || [typeString isEqualToString:@"TI"]|| [typeString isEqualToString:@"Tq"] || [typeString isEqualToString:@"TQ"] || [typeString isEqualToString:@"TB"] ||[classNameString isEqualToString:@"NSNumber"]) { 93 | [self setValue:value forKey:key]; 94 | } 95 | else { 96 | if ([classNameString isEqualToString:@"NSString"]) { 97 | [self setValue:[value stringValue] forKey:key]; 98 | } 99 | else{ 100 | NSLog(@"type error -- name:%@ attribute:%@ ", key, typeString); 101 | } 102 | } 103 | } 104 | //字符串 105 | else if ([value isKindOfClass:[NSString class]]) { 106 | if ([classNameString isEqualToString:@"NSString"]) { 107 | [self setValue:value forKey:key]; 108 | } 109 | else if ([classNameString isEqualToString:@"NSMutableString"]) { 110 | [self setValue:[NSMutableString stringWithString:value] forKey:key]; 111 | } 112 | //对应的属性为基础类型或者NSNumber时,先转成 nsnumber 113 | else if ([classNameString isEqualToString:@"NSNumber"] || [typeString isEqualToString:@"Td"] || [typeString isEqualToString:@"Ti"] || [typeString isEqualToString:@"Tf"] || [typeString isEqualToString:@"Tl"] || [typeString isEqualToString:@"Tc"] || [typeString isEqualToString:@"Ts"] || [typeString isEqualToString:@"TI"]|| [typeString isEqualToString:@"Tq"] || [typeString isEqualToString:@"TQ"] || [typeString isEqualToString:@"TB"]) { 114 | 115 | NSNumberFormatter *formater = [[NSNumberFormatter alloc] init]; 116 | NSNumber *number = [formater numberFromString:value]; 117 | if (number) 118 | { 119 | [self setValue:number forKey:key]; 120 | } 121 | } 122 | } 123 | 124 | //其它不处理 125 | else 126 | { 127 | [self setValue:value forKey:key]; 128 | } 129 | 130 | } @catch (NSException *exception) {} 131 | }]; 132 | } 133 | 134 | - (NSString *)mr_getClassNameFromAttributeString:(NSString *)attributeString { 135 | NSString *className = nil; 136 | NSScanner *scanner = [NSScanner scannerWithString: attributeString]; 137 | [scanner scanUpToString:@"T" intoString: nil]; 138 | [scanner scanString:@"T" intoString:nil]; 139 | if ([scanner scanString:@"@\"" intoString: &className]){ 140 | [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&className]; 141 | } 142 | return className; 143 | } 144 | 145 | @end 146 | 147 | @interface NSURL (MRBody) 148 | 149 | @property (nonatomic, readonly, copy) NSString *mr_body; 150 | 151 | @end 152 | 153 | @implementation NSURL (MRBody) 154 | 155 | - (NSString *)mr_body { 156 | return [NSString stringWithFormat:@"%@://%@%@", self.scheme, self.host?:@"", self.path?:@""]; 157 | } 158 | 159 | - (NSString *)mr_fullScheme { 160 | return self.scheme.length ? [NSString stringWithFormat:@"%@://", self.scheme] : self.scheme; 161 | } 162 | 163 | + (NSURL *)URLWithStringByAddingPercentEncoding:(NSString *)string { 164 | NSString* urlTextEscaped = [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; 165 | return [NSURL URLWithString:urlTextEscaped]; 166 | } 167 | 168 | @end 169 | 170 | @interface _MRRoute : NSObject 171 | 172 | @property (nonatomic, copy) NSString *pattern; 173 | @property (nonatomic, copy) NSString *scheme; 174 | @property (nonatomic, copy) NSString *host; 175 | @property (nonatomic, strong) NSArray *paths; 176 | @property (nonatomic, copy) NSString *className; 177 | @property (nonatomic, strong) NSDictionary *parameters; 178 | @property (nonatomic, copy) NSString *body; 179 | @property (nonatomic, copy) MRExecutingBlock executingBlock; 180 | 181 | - (void)parseUrl:(NSString *)URLPattern; 182 | 183 | @end 184 | 185 | @implementation _MRRoute 186 | 187 | + (_MRRoute *) routeWithURL:(NSString *)URLPattern { 188 | _MRRoute* route = [[_MRRoute alloc] initWithURL:URLPattern]; 189 | return route; 190 | } 191 | 192 | - (instancetype)initWithURL:(NSString *)URLPattern { 193 | if (!URLPattern.length) { 194 | return nil; 195 | } else { 196 | self = [super init]; 197 | if (self) { 198 | [self parseUrl:URLPattern]; 199 | } 200 | return self; 201 | } 202 | } 203 | 204 | - (void)parseUrl:(NSString *)URLPattern { 205 | _pattern = URLPattern; 206 | 207 | NSURL *URL = [NSURL URLWithStringByAddingPercentEncoding:URLPattern]; 208 | _scheme = URL.scheme.lowercaseString; 209 | _host = URL.host.lowercaseString; 210 | if (URL.pathComponents.count > 1) { 211 | _paths = [URL.pathComponents subarrayWithRange:NSMakeRange(1, URL.pathComponents.count-1)]; 212 | } 213 | _body = URL.mr_body.lowercaseString; 214 | } 215 | 216 | - (void)setParameters:(NSDictionary *)parameters 217 | { 218 | _parameters = parameters; 219 | if (self.body.length) 220 | { 221 | NSMutableString *URL = [[NSMutableString alloc] initWithString:self.body]; 222 | __block NSUInteger idx = 0; 223 | [parameters enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { 224 | if ([key isKindOfClass:[NSString class]] && 225 | ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]])) 226 | { 227 | if (idx == 0) 228 | { 229 | [URL appendString:@"?"]; 230 | } 231 | else 232 | { 233 | [URL appendString:@"&"]; 234 | } 235 | [URL appendFormat:@"%@=%@", key, obj]; 236 | } 237 | idx++; 238 | }]; 239 | self.pattern = [URL copy]; 240 | } 241 | } 242 | 243 | @end 244 | 245 | 246 | @interface MRRouter () 247 | 248 | @property (nonatomic, strong) NSMutableDictionary *plistMapDictionary; 249 | @property (nonatomic, strong) NSMutableDictionary *routes; 250 | @property (nonatomic, strong) NSMapTable *instanceMap; 251 | @property (nonatomic, strong) NSArray *defaultSubClasses; 252 | 253 | @end 254 | 255 | @implementation MRRouter 256 | 257 | + (MRRouter *)sharedInstance { 258 | static MRRouter *router; 259 | static dispatch_once_t onceToken; 260 | dispatch_once(&onceToken, ^{ 261 | router = [[MRRouter alloc] init]; 262 | }); 263 | return router; 264 | } 265 | 266 | - (instancetype)init { 267 | self = [super init]; 268 | if (self) { 269 | _routes = [NSMutableDictionary dictionary]; 270 | self.defaultClassType = [UIViewController class]; 271 | } 272 | return self; 273 | } 274 | 275 | + (void)openURL:(NSString *)URLPattern { 276 | return [self openURL:URLPattern parameters:nil]; 277 | } 278 | 279 | + (void)openURL:(NSString *)URLPattern parameters:(NSDictionary *)parameters { 280 | return [self openURL:URLPattern parameters:parameters prepareBlock:nil completeBlock:nil]; 281 | } 282 | 283 | + (void)openURL:(NSString *)URLPattern parameters:(NSDictionary *)parameters respondBlock:(MRRouterRespondBlock)respondBlock{ 284 | return [self openURL:URLPattern parameters:parameters prepareBlock:nil completeBlock:nil respondBlock:respondBlock]; 285 | } 286 | 287 | + (void)openURL:(NSString *)URLPattern parameters:(NSDictionary *)parameters prepareBlock:(MRPrepareBlock)prepareBlock completeBlock:(MRCompleteBlock)completeBlock{ 288 | return [self openURL:URLPattern parameters:parameters prepareBlock:prepareBlock completeBlock:completeBlock respondBlock:nil]; 289 | } 290 | 291 | + (void)openURL:(NSString *)URLPattern parameters:(NSDictionary *)parameters prepareBlock:(MRPrepareBlock)prepareBlock completeBlock:(MRCompleteBlock)completeBlock respondBlock:(MRRouterRespondBlock)respondBlock{ 292 | if (!URLPattern.length && ![self canOpenURL:URLPattern]) { 293 | return; 294 | } 295 | NSURL* URL = [NSURL URLWithStringByAddingPercentEncoding:URLPattern]; 296 | NSMutableDictionary *URLParameters = [NSMutableDictionary dictionary]; 297 | 298 | if (URL.query.length) { 299 | NSArray* paremeterDataArray = [URL.query componentsSeparatedByString:@"&"]; 300 | for (NSString* paramString in paremeterDataArray) { 301 | NSArray* paramArr = [paramString componentsSeparatedByString:@"="]; 302 | if (paramArr.count > 1) { 303 | NSString* key = [[paramArr objectAtIndex:0] stringByRemovingPercentEncoding] ?: @""; 304 | NSString* value = [[paramArr objectAtIndex:1] stringByRemovingPercentEncoding] ?: @""; 305 | [URLParameters setObject:value forKey:key]; 306 | } 307 | } 308 | } 309 | [URLParameters addEntriesFromDictionary:parameters]; 310 | 311 | _MRRoute* route = [[MRRouter sharedInstance] routeWithURL:URLPattern]; 312 | route.parameters = [URLParameters copy]; 313 | if (route.executingBlock) { 314 | if (prepareBlock) { 315 | prepareBlock(nil); 316 | } 317 | id object = route.executingBlock(URLPattern, URLParameters); 318 | [object setValue:URLParameters forKey:@"mr_parameters"]; 319 | if (![object valueForKey:@"mr_url"]) 320 | { 321 | [object setValue:URL.absoluteString forKey:@"mr_url"]; 322 | } 323 | if (respondBlock) 324 | { 325 | [object setValue:respondBlock forKey:@"mr_respondBlock"]; 326 | } 327 | [object parseParameters]; 328 | if (completeBlock) { 329 | completeBlock(object); 330 | } 331 | [[MRRouter sharedInstance].instanceMap setObject:object forKey:route.body]; 332 | } else { 333 | NSObject *object = [[MRRouter sharedInstance] executeDefaultBlock:route prepareBlock:prepareBlock completeBlock:completeBlock respondBlock:respondBlock]; 334 | [[MRRouter sharedInstance].instanceMap setObject:object forKey:route.body]; 335 | } 336 | } 337 | 338 | + (Class)matchClassWithURL:(NSString *)URLPattern { 339 | _MRRoute* route = [[MRRouter sharedInstance] routeWithURL:URLPattern]; 340 | if (route.className) { 341 | return [[MRRouter sharedInstance] matchObjectByName:route.className]; 342 | } else { 343 | return [[MRRouter sharedInstance] matchObjectByName:[[MRRouter sharedInstance] assembledClassNameWithString:route.host]]; 344 | } 345 | } 346 | 347 | + (id)existedInstanceWithURL:(NSString *)URLPattern 348 | { 349 | NSURL* URL = [NSURL URLWithStringByAddingPercentEncoding:URLPattern]; 350 | return [[MRRouter sharedInstance].instanceMap objectForKey:URL.mr_body]; 351 | } 352 | 353 | - (_MRRoute *) routeWithURL:(NSString *)URLPattern { 354 | if (!URLPattern.length) { 355 | return nil; 356 | } 357 | URLPattern = URLPattern.lowercaseString; 358 | NSMutableDictionary *routes = [MRRouter sharedInstance].routes; 359 | NSURL* URL = [NSURL URLWithStringByAddingPercentEncoding:URLPattern]; 360 | _MRRoute* route = routes[URL.mr_body] ? : routes[URL.mr_fullScheme]; 361 | if (!route) { 362 | route = [_MRRoute routeWithURL:URLPattern]; 363 | route.className = [[MRRouter sharedInstance] assembledClassNameWithString:route.host]; 364 | //Add the route to memory for next time. 365 | [[MRRouter sharedInstance].routes setObject:route forKey:URL.mr_body]; 366 | } 367 | return route; 368 | } 369 | 370 | - (Class)matchObjectByName:(NSString*) name { 371 | const char *className = [name cStringUsingEncoding:NSASCIIStringEncoding]; 372 | __block Class objetClass = objc_getClass(className); 373 | if (!objetClass) { 374 | [_defaultSubClasses enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 375 | if ([obj.lowercaseString isEqualToString:name.lowercaseString]) { 376 | objetClass = objc_getClass([obj cStringUsingEncoding:NSASCIIStringEncoding]); 377 | } 378 | }]; 379 | } 380 | return objetClass; 381 | } 382 | 383 | + (void)registerURL:(NSString *)URLPattern executingBlock:(MRExecutingBlock)executingBlock { 384 | if (!URLPattern.length) { 385 | return; 386 | } 387 | _MRRoute* route = [_MRRoute routeWithURL:URLPattern]; 388 | route.executingBlock = executingBlock; 389 | if (route.host) { 390 | route.className = [[MRRouter sharedInstance] assembledClassNameWithString:route.host]; 391 | } 392 | [[MRRouter sharedInstance].routes setObject:route forKey:[NSURL URLWithStringByAddingPercentEncoding:URLPattern].mr_body.lowercaseString]; 393 | } 394 | 395 | + (void)removeURL:(NSString *)URLPattern { 396 | [[MRRouter sharedInstance].routes removeObjectForKey:URLPattern]; 397 | } 398 | 399 | + (BOOL)canOpenURL:(NSString *)URLPattern { 400 | if (!URLPattern.length) { 401 | return NO; 402 | } 403 | NSMutableDictionary *routes = [MRRouter sharedInstance].routes; 404 | NSURL* URL = [NSURL URLWithStringByAddingPercentEncoding:URLPattern]; 405 | _MRRoute* route = routes[URL.mr_body] ? : routes[URL.mr_fullScheme]; 406 | if (!route) { 407 | NSString *className = [[MRRouter sharedInstance] assembledClassNameWithString:URL.host]; 408 | Class classType = [[MRRouter sharedInstance] matchObjectByName:className]; 409 | return classType != Nil; 410 | } else { 411 | return YES; 412 | } 413 | } 414 | 415 | + (void)map:(NSString *)URLPattern toClassName:(NSString *)name { 416 | _MRRoute* route = [_MRRoute routeWithURL:URLPattern]; 417 | route.className = name; 418 | [[MRRouter sharedInstance].routes setObject:route forKey:[NSURL URLWithStringByAddingPercentEncoding:URLPattern].mr_body]; 419 | } 420 | 421 | - (void)setMapFileName:(NSString *)mapFileName { 422 | NSString *plistPath; 423 | if (mapFileName.pathExtension.length == 0) { 424 | plistPath = [[NSBundle mainBundle] pathForResource:mapFileName ofType:@"plist"]; 425 | } else { 426 | plistPath = [[NSBundle mainBundle] pathForResource:[mapFileName substringToIndex:[mapFileName rangeOfString:@"."].location] ofType:mapFileName.pathExtension]; 427 | } 428 | if (plistPath.length) { 429 | self.plistMapDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath]; 430 | } 431 | } 432 | 433 | - (void)setPlistMapDictionary:(NSMutableDictionary *)plistMapDictionary { 434 | //remove the routes in memeory 435 | [_plistMapDictionary enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull key, NSString* _Nonnull obj, BOOL * _Nonnull stop) { 436 | [_routes removeObjectForKey:key]; 437 | }]; 438 | 439 | _plistMapDictionary = plistMapDictionary; 440 | [_plistMapDictionary enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) { 441 | _MRRoute* route = [_MRRoute routeWithURL:key]; 442 | route.className = obj; 443 | [[MRRouter sharedInstance].routes setObject:route forKey:key]; 444 | }]; 445 | } 446 | 447 | - (void)setRegisterMapDictionary:(NSMutableDictionary *)registerMapDictionary { 448 | 449 | } 450 | 451 | - (NSObject *)executeDefaultBlock:(_MRRoute *)route prepareBlock:(MRPrepareBlock)prepareBlock completeBlock:(MRCompleteBlock)completeBlock respondBlock:(MRRouterRespondBlock)respondBlock { 452 | NSObject *object = [self objectWithName:route.className parameters:route.parameters]; 453 | NSAssert(object, @"Could not initialize an instance from the url: %@", route.pattern); 454 | if (![object valueForKey:@"mr_url"]) 455 | { 456 | [object setValue:route.pattern forKey:@"mr_url"]; 457 | } 458 | if (respondBlock) 459 | { 460 | [object setValue:respondBlock forKey:@"mr_respondBlock"]; 461 | } 462 | [object parseParameters]; 463 | if (prepareBlock) { 464 | prepareBlock(object); 465 | } 466 | if (self.defaultExecutingBlock) { 467 | self.defaultExecutingBlock(object, route.parameters); 468 | } 469 | if (completeBlock) { 470 | completeBlock(object); 471 | } 472 | return object; 473 | } 474 | 475 | - (NSObject *)objectWithName:(NSString *)name parameters:(NSDictionary *)parameters { 476 | Class objetClass = [self matchObjectByName:name]; 477 | if (objetClass) { 478 | id object = [[objetClass alloc] init]; 479 | [object setValue:parameters forKey:@"mr_parameters"]; 480 | return object; 481 | } 482 | return nil; 483 | } 484 | 485 | - (NSString *) assembledClassNameWithString:(NSString *)string { 486 | NSAssert(string, @"Illegal url pattern!"); 487 | return [NSString stringWithFormat:@"%@%@%@", _prefix?:@"", string.capitalizedString, _postfix?:@""]; 488 | } 489 | 490 | - (void)setDefaultClassType:(Class)defaultClassType 491 | { 492 | _defaultClassType = defaultClassType; 493 | _defaultSubClasses = [defaultClassType subClasses]; 494 | } 495 | 496 | - (NSMapTable *)instanceMap 497 | { 498 | if (!_instanceMap) 499 | { 500 | _instanceMap = [NSMapTable strongToWeakObjectsMapTable]; 501 | } 502 | return _instanceMap; 503 | } 504 | 505 | @end 506 | 507 | @implementation NSObject (MRParameters) 508 | 509 | - (void)setMr_parameters:(NSDictionary *)mr_parameters { 510 | objc_setAssociatedObject(self, @selector(mr_parameters), mr_parameters, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 511 | } 512 | 513 | - (NSDictionary *)mr_parameters { 514 | return objc_getAssociatedObject(self, _cmd); 515 | } 516 | 517 | - (void)setMr_url:(NSString *)mr_url { 518 | objc_setAssociatedObject(self, @selector(mr_url), mr_url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 519 | } 520 | 521 | - (NSString *)mr_url { 522 | return objc_getAssociatedObject(self, _cmd); 523 | } 524 | 525 | - (void)setMr_respondBlock:(MRRouterRespondBlock)mr_respondBlock 526 | { 527 | objc_setAssociatedObject(self, @selector(mr_respondBlock), mr_respondBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 528 | } 529 | 530 | - (MRRouterRespondBlock)mr_respondBlock 531 | { 532 | return objc_getAssociatedObject(self, _cmd); 533 | } 534 | @end 535 | -------------------------------------------------------------------------------- /MRRouter/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 16/1/5. 6 | // Copyright © 2016年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SecondViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MRRouter/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 16/1/5. 6 | // Copyright © 2016年 juangua. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | #import "MRRouter.h" 11 | 12 | @interface SecondViewController () 13 | 14 | //@property (nonatomic, strong) NSString *ccc; 15 | @property (nonatomic, strong) NSString *ddd; 16 | 17 | @end 18 | 19 | @implementation SecondViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | self.view.backgroundColor = [UIColor redColor]; 24 | NSLog(@"%@", self.mr_parameters); 25 | } 26 | 27 | - (void)didReceiveMemoryWarning { 28 | [super didReceiveMemoryWarning]; 29 | // Dispose of any resources that can be recreated. 30 | } 31 | 32 | /* 33 | #pragma mark - Navigation 34 | 35 | // In a storyboard-based application, you will often want to do a little preparation before navigation 36 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 37 | // Get the new view controller using [segue destinationViewController]. 38 | // Pass the selected object to the new view controller. 39 | } 40 | */ 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /MRRouter/TestViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.h 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 16/1/5. 6 | // Copyright © 2016年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TestViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MRRouter/TestViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.m 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 16/1/5. 6 | // Copyright © 2016年 juangua. All rights reserved. 7 | // 8 | 9 | #import "TestViewController.h" 10 | #import "MRRouter.h" 11 | 12 | @interface TestViewController () 13 | 14 | @end 15 | 16 | @implementation TestViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.view.backgroundColor = [UIColor whiteColor]; 21 | NSLog(@"%@", self.mr_parameters); 22 | // Do any additional setup after loading the view. 23 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 24 | btn.frame = CGRectMake(100, 100, 50, 50); 25 | btn.backgroundColor = [UIColor redColor]; 26 | [self.view addSubview:btn]; 27 | [btn addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; 28 | } 29 | 30 | - (void)didReceiveMemoryWarning { 31 | [super didReceiveMemoryWarning]; 32 | // Dispose of any resources that can be recreated. 33 | } 34 | 35 | - (IBAction)buttonClicked:(id)sender { 36 | // id obj = [MRRouter existedInstanceWithURL:@"test://test"]; 37 | if (self.mr_respondBlock) 38 | { 39 | self.mr_respondBlock(@"test"); 40 | } 41 | 42 | } 43 | 44 | /* 45 | #pragma mark - Navigation 46 | 47 | // In a storyboard-based application, you will often want to do a little preparation before navigation 48 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 49 | // Get the new view controller using [segue destinationViewController]. 50 | // Pass the selected object to the new view controller. 51 | } 52 | */ 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /MRRouter/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 15/12/31. 6 | // Copyright © 2015年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UITableViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /MRRouter/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 15/12/31. 6 | // Copyright © 2015年 juangua. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "MRRouter.h" 11 | #import "FreeMarketViewController.h" 12 | 13 | #define TEST_URL2 @"mgj://test?aa=11&bb=22" 14 | #define TEST_URL3 @"mgj://second" 15 | #define TEST_URL4 @"mgj://hello" 16 | 17 | @interface ViewController () 18 | 19 | @end 20 | 21 | @implementation ViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | [MRRouter sharedInstance].mapFileName = @"route_map.plist"; 26 | [MRRouter sharedInstance].defaultExecutingBlock = ^(id object, NSDictionary *parameters) { 27 | [self.navigationController pushViewController:object animated:YES]; 28 | }; 29 | [MRRouter sharedInstance].postfix = @"ViewController"; 30 | } 31 | 32 | - (void)didReceiveMemoryWarning { 33 | [super didReceiveMemoryWarning]; 34 | // Dispose of any resources that can be recreated. 35 | } 36 | 37 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 38 | switch (indexPath.row) { 39 | case 0: 40 | { 41 | [MRRouter openURL:@"test://test?aa=11&bb=22"]; 42 | } 43 | break; 44 | case 1: 45 | { 46 | [MRRouter openURL:@"test://testforlist" parameters:@{@"ccc":@"333",@"ddd":@"444"}]; 47 | } 48 | break; 49 | case 2: 50 | { 51 | [MRRouter registerURL:@"mgj://freemarket/clothing/trousers?aa=11&bb=22" executingBlock:^(NSString *sourceURL, NSDictionary *parameters) { 52 | FreeMarketViewController *fvc = [[FreeMarketViewController alloc] init]; 53 | [self.navigationController pushViewController:fvc animated:YES]; 54 | return fvc; 55 | }]; 56 | [MRRouter openURL:@"mgj://freemarket/clothing/trousers?aa=11&bb=22"]; 57 | } 58 | break; 59 | case 3: 60 | { 61 | [MRRouter map:TEST_URL4 toClassName:@"HelloViewController"]; 62 | [MRRouter openURL:TEST_URL4]; 63 | } 64 | break; 65 | default: 66 | break; 67 | } 68 | } 69 | @end 70 | -------------------------------------------------------------------------------- /MRRouter/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MRRouter 4 | // 5 | // Created by 苏合 on 15/12/31. 6 | // Copyright © 2015年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MRRouter/route_map.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mgj://testforlist 6 | SecondViewController 7 | 8 | 9 | -------------------------------------------------------------------------------- /MRRouterTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /MRRouterTests/MRRouterTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MRRouterTests.m 3 | // MRRouterTests 4 | // 5 | // Created by 苏合 on 15/12/31. 6 | // Copyright © 2015年 juangua. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MRRouterTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MRRouterTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Products.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiaopen/MRRouter/0fe3b1cfbb629bdb3516d55c730b69de1824878d/Products.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MRRouter 2 | 3 | [![License](http://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/jiaopen/MRRouter/blob/master/LICENSE.md) 4 | 5 | ## About 6 | MRRouter以block的接口为基础,结合Objective-C的特性,提供了object和URL的映射关系,降低代码耦合。 7 | 8 | ## Features 9 | * API的设计很简单,功能相对齐全 10 | * 映射结合了runtime自动映射,代码映射,plist文件配置映射 11 | * 实现逻辑简单,调试方便 12 | * url和object的映射关系做了大小写不敏感匹配 13 | 14 | ## Usage 15 | ###runtime自动映射: 16 | 17 | 比如创建了一个叫TestViewController的类,不需要注册任何URL,只需要配置好默认的执行block,调用 18 | ```objc 19 | [MRRouter openURL:@"scheme://test"]; 20 | ``` 21 | 即可打开对应的页面。默认执行代码需要实现这个属性,之后通过runtime映射的URL就会默认执行这个操作 22 | ```objc 23 | [MRRouter sharedInstance].defaultExecutingBlock = ^(id object, NSDictionary *parameters) { 24 | [self.navigationController pushViewController:object animated:YES]; 25 | }; 26 | ``` 27 | 28 | 也可以注册特定的URL来实现特定的操作: 29 | ```objc 30 | [MRRouter registerURL:@"scheme://test2" executingBlock:^(NSString *sourceURL, NSDictionary *parameters) { 31 | //do sth. 32 | }]; 33 | ``` 34 | 35 | 支持参数解析和自定义参数传递,同时在下面这个例子中,对应的实例中如果定义了ccc和ddd名字的属性,将通过KVC自动赋值,实现跨页面参数传递: 36 | ```objc 37 | [MRRouter openURL:@"scheme://test3" parameters:@{@"ccc":@"333",@"ddd":@"444"}]; 38 | ``` 39 | 40 | 也可以直接获取到URL映射的类: 41 | ```objc 42 | + (Class)matchClassWithURL:(NSString *)URLPattern; 43 | ``` 44 | 45 | 46 | 47 | ## Requirements 48 | iOS 7.0+. 49 | 50 | ## License 51 | MRRouter is licensed under the [MIT License](http://opensource.org/licenses/mit-license.php). 52 | --------------------------------------------------------------------------------