├── .swift-version ├── Demo ├── Objective-C │ ├── JYRouterDemo.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcuserdata │ │ │ │ └── Job-Yang.xcuserdatad │ │ │ │ └── UserInterfaceState.xcuserstate │ │ └── xcuserdata │ │ │ └── Job-Yang.xcuserdatad │ │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ └── xcschemes │ │ │ ├── JYRouterDemo.xcscheme │ │ │ └── xcschememanagement.plist │ └── JYRouterDemo │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ │ ├── Info.plist │ │ ├── JYNavigationController.h │ │ ├── JYNavigationController.m │ │ ├── JYRouter │ │ ├── JYRouter.h │ │ └── JYRouter.m │ │ ├── JYViewController.h │ │ ├── JYViewController.m │ │ ├── dataList.json │ │ └── main.m └── Swift │ ├── JYRouterDemo-Swift.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── Job-Yang.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── Job-Yang.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── JYRouterDemo-Swift.xcscheme │ │ └── xcschememanagement.plist │ └── JYRouterDemo-Swift │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ └── LaunchScreen.storyboard │ ├── Info.plist │ ├── JYNavigationController.swift │ ├── JYRouter │ ├── JYRouter.h │ └── JYRouter.m │ ├── JYRouterDemo-Swift-Bridging-Header.h │ ├── JYViewController.swift │ └── dataList.json ├── JYRouter.podspec ├── JYRouter ├── JYRouter.h └── JYRouter.m ├── LICENSE └── README.md /.swift-version: -------------------------------------------------------------------------------- 1 | 2.3 2 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B112DCEE1E1B82E600D9237E /* JYRouter.m in Sources */ = {isa = PBXBuildFile; fileRef = B112DCE51E1B82E600D9237E /* JYRouter.m */; }; 11 | B17560AD1DFEA5BA0007E573 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B17560AC1DFEA5BA0007E573 /* main.m */; }; 12 | B17560B01DFEA5BA0007E573 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B17560AF1DFEA5BA0007E573 /* AppDelegate.m */; }; 13 | B17560B81DFEA5BA0007E573 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B17560B71DFEA5BA0007E573 /* Assets.xcassets */; }; 14 | B17560BB1DFEA5BA0007E573 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B17560B91DFEA5BA0007E573 /* LaunchScreen.storyboard */; }; 15 | B1DD3AA41DFFBC8900BCF83A /* JYNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1DD3AA31DFFBC8900BCF83A /* JYNavigationController.m */; }; 16 | B1DD3AA61DFFC94100BCF83A /* dataList.json in Resources */ = {isa = PBXBuildFile; fileRef = B1DD3AA51DFFC94100BCF83A /* dataList.json */; }; 17 | B1DD3AA91DFFD85600BCF83A /* JYViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1DD3AA81DFFD85600BCF83A /* JYViewController.m */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | B112DCE41E1B82E600D9237E /* JYRouter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JYRouter.h; sourceTree = ""; }; 22 | B112DCE51E1B82E600D9237E /* JYRouter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JYRouter.m; sourceTree = ""; }; 23 | B17560A81DFEA5BA0007E573 /* JYRouterDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JYRouterDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | B17560AC1DFEA5BA0007E573 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 25 | B17560AE1DFEA5BA0007E573 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 26 | B17560AF1DFEA5BA0007E573 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 27 | B17560B71DFEA5BA0007E573 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | B17560BA1DFEA5BA0007E573 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 29 | B17560BC1DFEA5BA0007E573 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | B1DD3AA21DFFBC8900BCF83A /* JYNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JYNavigationController.h; sourceTree = ""; }; 31 | B1DD3AA31DFFBC8900BCF83A /* JYNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JYNavigationController.m; sourceTree = ""; }; 32 | B1DD3AA51DFFC94100BCF83A /* dataList.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = dataList.json; sourceTree = ""; }; 33 | B1DD3AA71DFFD85600BCF83A /* JYViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JYViewController.h; sourceTree = ""; }; 34 | B1DD3AA81DFFD85600BCF83A /* JYViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JYViewController.m; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | B17560A51DFEA5BA0007E573 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | B112DCE31E1B82E600D9237E /* JYRouter */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | B112DCE41E1B82E600D9237E /* JYRouter.h */, 52 | B112DCE51E1B82E600D9237E /* JYRouter.m */, 53 | ); 54 | path = JYRouter; 55 | sourceTree = ""; 56 | }; 57 | B175609F1DFEA5BA0007E573 = { 58 | isa = PBXGroup; 59 | children = ( 60 | B17560AA1DFEA5BA0007E573 /* JYRouterDemo */, 61 | B17560A91DFEA5BA0007E573 /* Products */, 62 | ); 63 | sourceTree = ""; 64 | }; 65 | B17560A91DFEA5BA0007E573 /* Products */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | B17560A81DFEA5BA0007E573 /* JYRouterDemo.app */, 69 | ); 70 | name = Products; 71 | sourceTree = ""; 72 | }; 73 | B17560AA1DFEA5BA0007E573 /* JYRouterDemo */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | B112DCE31E1B82E600D9237E /* JYRouter */, 77 | B17560AE1DFEA5BA0007E573 /* AppDelegate.h */, 78 | B17560AF1DFEA5BA0007E573 /* AppDelegate.m */, 79 | B1DD3AA21DFFBC8900BCF83A /* JYNavigationController.h */, 80 | B1DD3AA31DFFBC8900BCF83A /* JYNavigationController.m */, 81 | B1DD3AA71DFFD85600BCF83A /* JYViewController.h */, 82 | B1DD3AA81DFFD85600BCF83A /* JYViewController.m */, 83 | B1DD3AA51DFFC94100BCF83A /* dataList.json */, 84 | B17560B71DFEA5BA0007E573 /* Assets.xcassets */, 85 | B17560B91DFEA5BA0007E573 /* LaunchScreen.storyboard */, 86 | B17560BC1DFEA5BA0007E573 /* Info.plist */, 87 | B17560AB1DFEA5BA0007E573 /* Supporting Files */, 88 | ); 89 | path = JYRouterDemo; 90 | sourceTree = ""; 91 | }; 92 | B17560AB1DFEA5BA0007E573 /* Supporting Files */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | B17560AC1DFEA5BA0007E573 /* main.m */, 96 | ); 97 | name = "Supporting Files"; 98 | sourceTree = ""; 99 | }; 100 | /* End PBXGroup section */ 101 | 102 | /* Begin PBXNativeTarget section */ 103 | B17560A71DFEA5BA0007E573 /* JYRouterDemo */ = { 104 | isa = PBXNativeTarget; 105 | buildConfigurationList = B17560BF1DFEA5BA0007E573 /* Build configuration list for PBXNativeTarget "JYRouterDemo" */; 106 | buildPhases = ( 107 | B17560A41DFEA5BA0007E573 /* Sources */, 108 | B17560A51DFEA5BA0007E573 /* Frameworks */, 109 | B17560A61DFEA5BA0007E573 /* Resources */, 110 | ); 111 | buildRules = ( 112 | ); 113 | dependencies = ( 114 | ); 115 | name = JYRouterDemo; 116 | productName = JYRouterDemo; 117 | productReference = B17560A81DFEA5BA0007E573 /* JYRouterDemo.app */; 118 | productType = "com.apple.product-type.application"; 119 | }; 120 | /* End PBXNativeTarget section */ 121 | 122 | /* Begin PBXProject section */ 123 | B17560A01DFEA5BA0007E573 /* Project object */ = { 124 | isa = PBXProject; 125 | attributes = { 126 | LastUpgradeCheck = 0900; 127 | ORGANIZATIONNAME = "Job-Yang"; 128 | TargetAttributes = { 129 | B17560A71DFEA5BA0007E573 = { 130 | CreatedOnToolsVersion = 8.1; 131 | DevelopmentTeam = ENALQ2C42Q; 132 | LastSwiftMigration = 0820; 133 | ProvisioningStyle = Automatic; 134 | }; 135 | }; 136 | }; 137 | buildConfigurationList = B17560A31DFEA5BA0007E573 /* Build configuration list for PBXProject "JYRouterDemo" */; 138 | compatibilityVersion = "Xcode 3.2"; 139 | developmentRegion = English; 140 | hasScannedForEncodings = 0; 141 | knownRegions = ( 142 | en, 143 | Base, 144 | ); 145 | mainGroup = B175609F1DFEA5BA0007E573; 146 | productRefGroup = B17560A91DFEA5BA0007E573 /* Products */; 147 | projectDirPath = ""; 148 | projectRoot = ""; 149 | targets = ( 150 | B17560A71DFEA5BA0007E573 /* JYRouterDemo */, 151 | ); 152 | }; 153 | /* End PBXProject section */ 154 | 155 | /* Begin PBXResourcesBuildPhase section */ 156 | B17560A61DFEA5BA0007E573 /* Resources */ = { 157 | isa = PBXResourcesBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | B17560BB1DFEA5BA0007E573 /* LaunchScreen.storyboard in Resources */, 161 | B17560B81DFEA5BA0007E573 /* Assets.xcassets in Resources */, 162 | B1DD3AA61DFFC94100BCF83A /* dataList.json in Resources */, 163 | ); 164 | runOnlyForDeploymentPostprocessing = 0; 165 | }; 166 | /* End PBXResourcesBuildPhase section */ 167 | 168 | /* Begin PBXSourcesBuildPhase section */ 169 | B17560A41DFEA5BA0007E573 /* Sources */ = { 170 | isa = PBXSourcesBuildPhase; 171 | buildActionMask = 2147483647; 172 | files = ( 173 | B1DD3AA91DFFD85600BCF83A /* JYViewController.m in Sources */, 174 | B1DD3AA41DFFBC8900BCF83A /* JYNavigationController.m in Sources */, 175 | B17560B01DFEA5BA0007E573 /* AppDelegate.m in Sources */, 176 | B112DCEE1E1B82E600D9237E /* JYRouter.m in Sources */, 177 | B17560AD1DFEA5BA0007E573 /* main.m in Sources */, 178 | ); 179 | runOnlyForDeploymentPostprocessing = 0; 180 | }; 181 | /* End PBXSourcesBuildPhase section */ 182 | 183 | /* Begin PBXVariantGroup section */ 184 | B17560B91DFEA5BA0007E573 /* LaunchScreen.storyboard */ = { 185 | isa = PBXVariantGroup; 186 | children = ( 187 | B17560BA1DFEA5BA0007E573 /* Base */, 188 | ); 189 | name = LaunchScreen.storyboard; 190 | sourceTree = ""; 191 | }; 192 | /* End PBXVariantGroup section */ 193 | 194 | /* Begin XCBuildConfiguration section */ 195 | B17560BD1DFEA5BA0007E573 /* Debug */ = { 196 | isa = XCBuildConfiguration; 197 | buildSettings = { 198 | ALWAYS_SEARCH_USER_PATHS = NO; 199 | CLANG_ANALYZER_NONNULL = YES; 200 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 201 | CLANG_CXX_LIBRARY = "libc++"; 202 | CLANG_ENABLE_MODULES = YES; 203 | CLANG_ENABLE_OBJC_ARC = YES; 204 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 205 | CLANG_WARN_BOOL_CONVERSION = YES; 206 | CLANG_WARN_COMMA = YES; 207 | CLANG_WARN_CONSTANT_CONVERSION = YES; 208 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 209 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 210 | CLANG_WARN_EMPTY_BODY = YES; 211 | CLANG_WARN_ENUM_CONVERSION = YES; 212 | CLANG_WARN_INFINITE_RECURSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 215 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 216 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 217 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 218 | CLANG_WARN_STRICT_PROTOTYPES = YES; 219 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 220 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 221 | CLANG_WARN_UNREACHABLE_CODE = YES; 222 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 223 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 224 | COPY_PHASE_STRIP = NO; 225 | DEBUG_INFORMATION_FORMAT = dwarf; 226 | ENABLE_STRICT_OBJC_MSGSEND = YES; 227 | ENABLE_TESTABILITY = YES; 228 | GCC_C_LANGUAGE_STANDARD = gnu99; 229 | GCC_DYNAMIC_NO_PIC = NO; 230 | GCC_NO_COMMON_BLOCKS = YES; 231 | GCC_OPTIMIZATION_LEVEL = 0; 232 | GCC_PREPROCESSOR_DEFINITIONS = ( 233 | "DEBUG=1", 234 | "$(inherited)", 235 | ); 236 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 237 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 238 | GCC_WARN_UNDECLARED_SELECTOR = YES; 239 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 240 | GCC_WARN_UNUSED_FUNCTION = YES; 241 | GCC_WARN_UNUSED_VARIABLE = YES; 242 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 243 | MTL_ENABLE_DEBUG_INFO = YES; 244 | ONLY_ACTIVE_ARCH = YES; 245 | SDKROOT = iphoneos; 246 | }; 247 | name = Debug; 248 | }; 249 | B17560BE1DFEA5BA0007E573 /* Release */ = { 250 | isa = XCBuildConfiguration; 251 | buildSettings = { 252 | ALWAYS_SEARCH_USER_PATHS = NO; 253 | CLANG_ANALYZER_NONNULL = YES; 254 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 255 | CLANG_CXX_LIBRARY = "libc++"; 256 | CLANG_ENABLE_MODULES = YES; 257 | CLANG_ENABLE_OBJC_ARC = YES; 258 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 259 | CLANG_WARN_BOOL_CONVERSION = YES; 260 | CLANG_WARN_COMMA = YES; 261 | CLANG_WARN_CONSTANT_CONVERSION = YES; 262 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 263 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INFINITE_RECURSION = YES; 267 | CLANG_WARN_INT_CONVERSION = YES; 268 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 269 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 270 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 271 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 272 | CLANG_WARN_STRICT_PROTOTYPES = YES; 273 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 274 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 275 | CLANG_WARN_UNREACHABLE_CODE = YES; 276 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 277 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 278 | COPY_PHASE_STRIP = NO; 279 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 280 | ENABLE_NS_ASSERTIONS = NO; 281 | ENABLE_STRICT_OBJC_MSGSEND = YES; 282 | GCC_C_LANGUAGE_STANDARD = gnu99; 283 | GCC_NO_COMMON_BLOCKS = YES; 284 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 285 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 286 | GCC_WARN_UNDECLARED_SELECTOR = YES; 287 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 288 | GCC_WARN_UNUSED_FUNCTION = YES; 289 | GCC_WARN_UNUSED_VARIABLE = YES; 290 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 291 | MTL_ENABLE_DEBUG_INFO = NO; 292 | SDKROOT = iphoneos; 293 | VALIDATE_PRODUCT = YES; 294 | }; 295 | name = Release; 296 | }; 297 | B17560C01DFEA5BA0007E573 /* Debug */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 301 | CLANG_ENABLE_MODULES = YES; 302 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 303 | DEVELOPMENT_TEAM = ENALQ2C42Q; 304 | INFOPLIST_FILE = JYRouterDemo/Info.plist; 305 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 306 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 307 | PRODUCT_BUNDLE_IDENTIFIER = "Job-Yang.JYRouterDemo"; 308 | PRODUCT_NAME = "$(TARGET_NAME)"; 309 | PROVISIONING_PROFILE_SPECIFIER = ""; 310 | SWIFT_OBJC_BRIDGING_HEADER = "JYRouterDemo/JYRouterDemo-Bridging-Header.h"; 311 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 312 | SWIFT_VERSION = 3.0; 313 | }; 314 | name = Debug; 315 | }; 316 | B17560C11DFEA5BA0007E573 /* Release */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 320 | CLANG_ENABLE_MODULES = YES; 321 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 322 | DEVELOPMENT_TEAM = ENALQ2C42Q; 323 | INFOPLIST_FILE = JYRouterDemo/Info.plist; 324 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 326 | PRODUCT_BUNDLE_IDENTIFIER = "Job-Yang.JYRouterDemo"; 327 | PRODUCT_NAME = "$(TARGET_NAME)"; 328 | PROVISIONING_PROFILE_SPECIFIER = ""; 329 | SWIFT_OBJC_BRIDGING_HEADER = "JYRouterDemo/JYRouterDemo-Bridging-Header.h"; 330 | SWIFT_VERSION = 3.0; 331 | }; 332 | name = Release; 333 | }; 334 | /* End XCBuildConfiguration section */ 335 | 336 | /* Begin XCConfigurationList section */ 337 | B17560A31DFEA5BA0007E573 /* Build configuration list for PBXProject "JYRouterDemo" */ = { 338 | isa = XCConfigurationList; 339 | buildConfigurations = ( 340 | B17560BD1DFEA5BA0007E573 /* Debug */, 341 | B17560BE1DFEA5BA0007E573 /* Release */, 342 | ); 343 | defaultConfigurationIsVisible = 0; 344 | defaultConfigurationName = Release; 345 | }; 346 | B17560BF1DFEA5BA0007E573 /* Build configuration list for PBXNativeTarget "JYRouterDemo" */ = { 347 | isa = XCConfigurationList; 348 | buildConfigurations = ( 349 | B17560C01DFEA5BA0007E573 /* Debug */, 350 | B17560C11DFEA5BA0007E573 /* Release */, 351 | ); 352 | defaultConfigurationIsVisible = 0; 353 | defaultConfigurationName = Release; 354 | }; 355 | /* End XCConfigurationList section */ 356 | }; 357 | rootObject = B17560A01DFEA5BA0007E573 /* Project object */; 358 | } 359 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo.xcodeproj/project.xcworkspace/xcuserdata/Job-Yang.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Job-Yang/JYRouter/d30ac364e08f2ec79cc940e8da412d1613f3a041/Demo/Objective-C/JYRouterDemo.xcodeproj/project.xcworkspace/xcuserdata/Job-Yang.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo.xcodeproj/xcuserdata/Job-Yang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo.xcodeproj/xcuserdata/Job-Yang.xcuserdatad/xcschemes/JYRouterDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 57 | 59 | 65 | 66 | 67 | 68 | 69 | 70 | 76 | 78 | 84 | 85 | 86 | 87 | 89 | 90 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo.xcodeproj/xcuserdata/Job-Yang.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JYRouterDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B17560A71DFEA5BA0007E573 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // JYRouterDemo 4 | // 5 | // Created by 杨权 on 2016/12/12. 6 | // Copyright © 2016年 Job-Yang. 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 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // JYRouterDemo 4 | // 5 | // Created by 杨权 on 2016/12/12. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "JYRouter.h" 11 | #import "JYNavigationController.h" 12 | #import "JYViewController.h" 13 | 14 | @interface AppDelegate () 15 | 16 | @end 17 | 18 | @implementation AppDelegate 19 | 20 | 21 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 22 | 23 | // 设置主窗口,并设置跟控制器 24 | self.window = [[UIWindow alloc] init]; 25 | self.window.frame = [UIScreen mainScreen].bounds; 26 | JYViewController *root = [[JYViewController alloc] init]; 27 | JYNavigationController *nav = [[JYNavigationController alloc] initWithRootViewController:root]; 28 | self.window.rootViewController = nav; 29 | [self.window makeKeyAndVisible]; 30 | 31 | //设置Router跳转时所显示的NavigationController 32 | [[JYRouter router] setCustomNavigationClass:[JYNavigationController class]]; 33 | 34 | return YES; 35 | } 36 | 37 | 38 | - (void)applicationWillResignActive:(UIApplication *)application { 39 | // 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. 40 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 41 | } 42 | 43 | 44 | - (void)applicationDidEnterBackground:(UIApplication *)application { 45 | // 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. 46 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 47 | } 48 | 49 | 50 | - (void)applicationWillEnterForeground:(UIApplication *)application { 51 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 52 | } 53 | 54 | 55 | - (void)applicationDidBecomeActive:(UIApplication *)application { 56 | // 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. 57 | } 58 | 59 | 60 | - (void)applicationWillTerminate:(UIApplication *)application { 61 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 62 | } 63 | 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/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 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/JYNavigationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JYNavigationController.h 3 | // JYRouterDemo 4 | // 5 | // Created by 杨权 on 2016/12/13. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JYNavigationController : UINavigationController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/JYNavigationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JYNavigationController.m 3 | // JYRouterDemo 4 | // 5 | // Created by 杨权 on 2016/12/13. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import "JYNavigationController.h" 10 | 11 | @interface JYNavigationController () 12 | 13 | @end 14 | 15 | @implementation JYNavigationController 16 | 17 | - (UIStatusBarStyle)preferredStatusBarStyle{ 18 | return UIStatusBarStyleLightContent; 19 | } 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | [self setNavigationBar]; 24 | } 25 | 26 | - (void)setNavigationBar { 27 | //设置NavigationBar背景颜色 28 | [[UINavigationBar appearance] setTranslucent:NO]; 29 | [[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]]; 30 | [[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] 31 | forBarPosition:UIBarPositionAny 32 | barMetrics:UIBarMetricsDefault]; 33 | [[UINavigationBar appearance] setShadowImage:[UIImage new]]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/JYRouter/JYRouter.h: -------------------------------------------------------------------------------- 1 | // 2 | // JYRouter.h 3 | // Job-Yang 4 | // 5 | // Created by 杨权 on 16/9/22. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void (^JYRouterOpenCallback)(NSDictionary *params); 13 | 14 | /** 15 | 跳转时属性自动复制的工具分类 16 | */ 17 | @interface NSObject (JYParams) 18 | @end 19 | 20 | /** 21 | 跳转时回调的分类 22 | */ 23 | @interface UINavigationController (JYCallBack) 24 | @end 25 | 26 | /** 27 | 跳转选项相关类 28 | */ 29 | @interface JYRouterOptions : NSObject 30 | @end 31 | 32 | /** 33 | 跳转参数相关类 34 | */ 35 | @interface JYRouterParams : NSObject 36 | @end 37 | 38 | 39 | @interface JYRouter : NSObject 40 | 41 | /** 42 | 是否忽略异常 43 | */ 44 | @property (nonatomic, assign) BOOL ignoresExceptions; 45 | 46 | /** 47 | 单例 48 | 49 | @return JYRouter单例对象 50 | */ 51 | + (instancetype)router; 52 | 53 | /** 54 | 获取一个新的Router对象 55 | 56 | @return JYRouter对象 57 | */ 58 | + (instancetype)newRouter; 59 | 60 | /** 61 | 获取当前显示的VC 62 | 63 | @return 当前显示的VC 64 | */ 65 | + (UIViewController *)currentVC; 66 | 67 | /** 68 | 设置自定义的Navigation,用于present时显示 69 | 如果您想全局设置,请在AppDelegate 的didFinishLaunchingWithOptions方法中设置 70 | [[JYRouter router] setCustomNavigationClass:[YourCustomNavigation class]]; 71 | 72 | @param navClass Navigation Class 73 | */ 74 | - (void)setCustomNavigationClass:(Class)navClass; 75 | 76 | /** 77 | 判断该URL是否可以路由跳转 78 | 79 | @param url url 80 | @return 是否可以跳转 81 | */ 82 | - (BOOL)hasRouter:(NSString *)url; 83 | 84 | /** 85 | 通过VC名称初始化VC 86 | 87 | @param viewController VC名称 88 | @return VC对象 89 | */ 90 | - (UIViewController *)controllerWithRouter:(NSString *)viewController; 91 | 92 | /** 93 | 通过VC名称初始化VC,并params映射将指定的属性赋值 94 | 95 | @param viewController VC名称 96 | @param params 属性映射 97 | @return VC对象 98 | */ 99 | - (UIViewController *)controllerWithRouter:(NSString *)viewController 100 | params:(NSDictionary *)params; 101 | 102 | 103 | #pragma mark - Push 104 | 105 | /** 106 | 通过VC名Push到指定的VC(默认显示push动画) 107 | 108 | @param viewController VC名称 109 | */ 110 | - (void)push:(NSString *)viewController; 111 | 112 | /** 113 | 通过VC名Push到指定的VC(是否显示push动画) 114 | 115 | @param viewController VC名称 116 | @param animated 是否显示动画 117 | */ 118 | - (void)push:(NSString *)viewController 119 | animated:(BOOL)animated; 120 | 121 | /** 122 | 通过VC名Push到指定的VC,并params映射将指定的属性赋值 123 | 124 | @param viewController VC名称 125 | @param animated 是否显示push动画 126 | @param params 属性映射 127 | */ 128 | - (void)push:(NSString *)viewController 129 | animated:(BOOL)animated 130 | params:(NSDictionary *)params; 131 | 132 | 133 | /** 134 | 通过VC名Push到指定的VC,并params映射将指定的属性赋值 135 | 136 | @param viewController VC名称 137 | @param animated 是否显示push动画 138 | @param params 属性映射 139 | @param completion 完成回调 140 | */ 141 | - (void)push:(NSString *)viewController 142 | animated:(BOOL)animated 143 | params:(NSDictionary *)params 144 | completion:(void(^)(void))completion; 145 | 146 | #pragma mark - Present 147 | 148 | /** 149 | 通过VC名Present到指定的VC(默认显示Present动画) 150 | 151 | @param viewController VC名称 152 | */ 153 | - (void)present:(NSString *)viewController; 154 | 155 | /** 156 | 通过VC名Present到指定的VC(是否显示Present动画) 157 | 158 | @param viewController VC名称 159 | @param animated 是否显示Present动画 160 | */ 161 | - (void)present:(NSString *)viewController 162 | animated:(BOOL)animated; 163 | 164 | /** 165 | 通过VC名Present指定的VC,并params映射将指定的属性赋值 166 | 167 | @param viewController VC名称 168 | @param animated 是否显示Present动画 169 | @param params 属性映射 170 | */ 171 | - (void)present:(NSString *)viewController 172 | animated:(BOOL)animated 173 | params:(NSDictionary *)params; 174 | 175 | 176 | /** 177 | 通过VC名Present指定的VC,并params映射将指定的属性赋值 178 | 179 | @param viewController VC名称 180 | @param animated 是否显示Present动画 181 | @param params 属性映射 182 | @param completion 完成回调 183 | */ 184 | - (void)present:(NSString *)viewController 185 | animated:(BOOL)animated 186 | params:(NSDictionary *)params 187 | completion:(void(^)(void))completion; 188 | 189 | #pragma mark - Pop 190 | 191 | /** 192 | Pop到上级VC(默认显示Pop动画) 193 | */ 194 | - (void)pop; 195 | 196 | /** 197 | Pop到上级VC(是否显示Pop动画) 198 | 199 | @param animated 是否显示Pop动画 200 | */ 201 | - (void)pop:(BOOL)animated; 202 | 203 | /** 204 | Pop到根控制器(默认显示Pop动画) 205 | */ 206 | - (void)popToRoot; 207 | 208 | /** 209 | Pop到根控制器(是否显示Pop动画) 210 | 211 | @param animated 是否显示Pop动画 212 | */ 213 | - (void)popToRoot:(BOOL)animated; 214 | 215 | /** 216 | Pop到根控制器(是否显示Pop动画) 217 | 218 | @param animated 是否显示Pop动画 219 | @param completion 完成回调 220 | */ 221 | - (void)popToRoot:(BOOL)animated 222 | completion:(void(^)(void))completion; 223 | 224 | /** 225 | 通过VC名Pop到指定的VC(默认显示Pop动画) 226 | 227 | @param viewController VC名称 228 | */ 229 | - (void)popTo:(NSString *)viewController; 230 | 231 | /** 232 | 通过VC名Pop到指定的VC(是否显示Pop动画) 233 | 234 | @param viewController VC名称 235 | @param animated 是否显示Pop动画 236 | */ 237 | - (void)popTo:(NSString *)viewController 238 | animated:(BOOL)animated; 239 | 240 | /** 241 | 通过VC名Pop到指定的VC(是否显示Pop动画) 242 | 243 | @param viewController VC名称 244 | @param animated 是否显示Pop动画 245 | @param completion 完成回调 246 | */ 247 | - (void)popTo:(NSString *)viewController 248 | animated:(BOOL)animated 249 | completion:(void(^)(void))completion; 250 | 251 | #pragma mark - Dismiss 252 | 253 | /** 254 | dismiss(默认显示Dismiss动画) 255 | */ 256 | - (void)dismiss; 257 | /** 258 | dismiss(是否显示Dismiss动画) 259 | 260 | @param animated 是否显示Dismiss动画 261 | */ 262 | - (void)dismiss:(BOOL)animated; 263 | 264 | /** 265 | dismiss(是否显示Dismiss动画) 266 | 267 | @param animated 是否显示Dismiss动画 268 | @param completion 完成回调 269 | */ 270 | - (void)dismiss:(BOOL)animated 271 | completion:(void(^)(void))completion; 272 | 273 | @end 274 | 275 | 276 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/JYRouter/JYRouter.m: -------------------------------------------------------------------------------- 1 | // 2 | // JYRouter.h 3 | // Job-Yang 4 | // 5 | // Created by 杨权 on 16/9/22. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import "JYRouter.h" 10 | #import 11 | #import 12 | 13 | @implementation NSObject (JYParams) 14 | 15 | - (void)modelWithDictionary:(NSDictionary *)dic { 16 | if (!dic) {return;} 17 | for (NSString *keyName in [dic allKeys]) { 18 | NSString *setterMethodName = [NSString stringWithFormat:@"set%@:",[self firstUpperString:keyName]]; 19 | SEL propertySelector = NSSelectorFromString(setterMethodName); 20 | 21 | if ([self respondsToSelector:propertySelector]) { 22 | id value = [dic objectForKey:keyName]; 23 | unsigned int count; 24 | Class class = [self class]; 25 | do { 26 | objc_property_t *properties = class_copyPropertyList(class, &count); 27 | for (NSInteger i = 0; i < count; i++) { 28 | objc_property_t property = properties[i]; 29 | const char *name = property_getName(property); 30 | NSString *proName = [[NSString alloc] initWithUTF8String:name]; 31 | if ([proName isEqualToString:keyName]) { 32 | const char *attributes = property_getAttributes(property); 33 | char *type = [self typeOfPropertyFromAttributes:attributes]; 34 | if (1 == strlen(type)) { 35 | [self encodeType:type[0] ofPropertySelector:propertySelector value:value]; 36 | } 37 | else { 38 | [self encodeStructureType:type ofPropertySelector:propertySelector value:value]; 39 | } 40 | break; 41 | } 42 | } 43 | class = [class superclass]; 44 | } while (class != [NSObject class]); 45 | } 46 | } 47 | } 48 | 49 | - (NSString *)firstUpperString:(NSString *)str { 50 | if (str && str.length > 0) { 51 | NSString *firstChar = [str substringToIndex:1]; 52 | NSString *result = [[firstChar uppercaseString] stringByAppendingString:[str substringFromIndex:1]]; 53 | return result; 54 | } 55 | return @""; 56 | } 57 | 58 | - (char *)typeOfPropertyFromAttributes:(const char *)attributes { 59 | if (!attributes || strlen(attributes) <= 1) { 60 | return 0x00; 61 | } 62 | char *result = NULL; 63 | if (!(attributes[1] == '{')){ 64 | result = malloc(sizeof(char) * 2); 65 | memset(result, 0, 2); 66 | strncpy(result, attributes + 1, 1); 67 | return result; 68 | } 69 | char *start = strstr(attributes, "{"); 70 | char *end = start; 71 | while (true) { 72 | char *tmp = strstr(end + 1, "}"); 73 | if (!tmp) break; 74 | end = tmp; 75 | } 76 | NSInteger len = end - start + 1; 77 | result = malloc(sizeof(char) * (len + 1)); 78 | memset(result, 0, len + 1); 79 | strncpy(result, start, len); 80 | return result; 81 | } 82 | 83 | - (void)encodeType:(char)type ofPropertySelector:(SEL)selector value:(id)value { 84 | if (!type) return; 85 | switch (type) { 86 | case 'B': { 87 | BOOL boolValue = [(NSNumber *)value boolValue]; 88 | ((void (*)(id, SEL, BOOL))(void *) objc_msgSend)((id)self, selector, boolValue); 89 | break; 90 | }; 91 | case 'c': { 92 | char charValue = [(NSNumber *)value charValue]; 93 | ((void (*)(id, SEL, char))(void *) objc_msgSend)((id)self, selector, charValue); 94 | break; 95 | } 96 | case 's': { 97 | short shortValue = [(NSNumber *)value shortValue]; 98 | ((void (*)(id, SEL, short))(void *) objc_msgSend)((id)self, selector, shortValue); 99 | break; 100 | } 101 | case 'i': { 102 | int intValue = [(NSNumber *)value intValue]; 103 | ((void (*)(id, SEL, int))(void *) objc_msgSend)((id)self, selector, intValue); 104 | break; 105 | } 106 | case 'C': { 107 | unsigned char unsignedCharValue = [(NSNumber *)value unsignedCharValue]; 108 | ((void (*)(id, SEL, unsigned char))(void *) objc_msgSend)((id)self, selector, unsignedCharValue); 109 | break; 110 | } 111 | case 'S': { 112 | unsigned short unsignedShortValue = [(NSNumber *)value unsignedShortValue]; 113 | ((void (*)(id, SEL, unsigned short))(void *) objc_msgSend)((id)self, selector, unsignedShortValue); 114 | break; 115 | } 116 | case 'I': { 117 | unsigned int unsignedIntValue = [(NSNumber *)value unsignedIntValue]; 118 | ((void (*)(id, SEL, unsigned int))(void *) objc_msgSend)((id)self, selector, unsignedIntValue); 119 | break; 120 | } 121 | case 'l': { 122 | long longValue = [(NSNumber *)value longValue]; 123 | ((void (*)(id, SEL, long))(void *) objc_msgSend)((id)self, selector, longValue); 124 | break; 125 | } 126 | case 'L': { 127 | unsigned long unsignedLongValue = [(NSNumber *)value unsignedLongValue]; 128 | ((void (*)(id, SEL, unsigned long))(void *) objc_msgSend)((id)self, selector, unsignedLongValue); 129 | break; 130 | } 131 | case 'q': { 132 | long long longLongValue = [(NSNumber *)value longLongValue]; 133 | ((void (*)(id, SEL, long long))(void *) objc_msgSend)((id)self, selector, longLongValue); 134 | break; 135 | } 136 | case 'Q': { 137 | unsigned long long unsignedLongLongValue = [(NSNumber *)value unsignedLongLongValue]; 138 | ((void (*)(id, SEL, unsigned long long))(void *) objc_msgSend)((id)self, selector, unsignedLongLongValue); 139 | break; 140 | } 141 | case 'f': { 142 | float floatValue = [(NSNumber *)value floatValue]; 143 | ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)self, selector, floatValue); 144 | break; 145 | } 146 | case 'd': { 147 | double doubleValue = [(NSNumber *)value doubleValue]; 148 | ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)self, selector, doubleValue); 149 | break; 150 | } 151 | default: { 152 | ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, selector, value); 153 | break; 154 | } 155 | } 156 | } 157 | 158 | - (void)encodeStructureType:(char *)type ofPropertySelector:(SEL)selector value:(id)value { 159 | if (!strcmp(type, @encode(CGPoint))) { 160 | CGPoint pointValue = [(NSValue *)value CGPointValue]; 161 | ((void (*)(id, SEL, CGPoint))(void *) objc_msgSend)((id)self, selector, pointValue); 162 | } 163 | else if (!strcmp(type, @encode(CGSize))) { 164 | CGSize sizeValue = [(NSValue *)value CGSizeValue]; 165 | ((void (*)(id, SEL, CGSize))(void *) objc_msgSend)((id)self, selector, sizeValue); 166 | } 167 | else if (!strcmp(type, @encode(CGRect))){ 168 | CGRect rectValue = [(NSValue *)value CGRectValue]; 169 | ((void (*)(id, SEL, CGRect))(void *) objc_msgSend)((id)self, selector, rectValue); 170 | } 171 | else if (!strcmp(type, @encode(CGAffineTransform))){ 172 | CGAffineTransform affineValue = [(NSValue*)value CGAffineTransformValue]; 173 | ((void (*)(id, SEL, CGAffineTransform))(void *) objc_msgSend)((id)self, selector, affineValue); 174 | } 175 | else if (!strcmp(type, @encode(UIEdgeInsets))){ 176 | UIEdgeInsets edgeInsetsValue = [(NSValue*)value UIEdgeInsetsValue]; 177 | ((void (*)(id, SEL, UIEdgeInsets))(void *) objc_msgSend)((id)self, selector, edgeInsetsValue); 178 | } 179 | else if (!strcmp(type, @encode(UIOffset))){ 180 | UIOffset offset = [(NSValue*)value UIOffsetValue]; 181 | ((void (*)(id, SEL, UIOffset))(void *) objc_msgSend)((id)self, selector, offset); 182 | } 183 | else { 184 | ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, selector, value); 185 | } 186 | } 187 | 188 | @end 189 | 190 | 191 | @implementation UINavigationController (JYCallBack) 192 | - (void)pushViewController:(UIViewController *)viewController 193 | animated:(BOOL)animated 194 | completion:(void(^)(void))completion { 195 | [CATransaction begin]; 196 | [CATransaction setCompletionBlock:completion]; 197 | [self pushViewController:viewController animated:animated]; 198 | [CATransaction commit]; 199 | } 200 | 201 | - (void)popToRootViewController:(BOOL)animated 202 | completion:(void(^)(void))completion { 203 | [CATransaction begin]; 204 | [CATransaction setCompletionBlock:completion]; 205 | [self popToRootViewControllerAnimated:animated]; 206 | [CATransaction commit]; 207 | } 208 | 209 | - (void)popToViewController:(UIViewController *)viewController 210 | animated:(BOOL)animated 211 | completion:(void(^)(void))completion { 212 | [CATransaction begin]; 213 | [CATransaction setCompletionBlock:completion]; 214 | [self popToViewController:viewController animated:animated]; 215 | [CATransaction commit]; 216 | } 217 | 218 | @end 219 | 220 | 221 | @interface JYRouterOptions() 222 | @property (nonatomic, assign) BOOL isModal; 223 | @property (nonatomic, assign) UIModalPresentationStyle presentationStyle; 224 | @property (nonatomic, assign) UIModalTransitionStyle transitionStyle; 225 | @property (nonatomic, strong) NSDictionary *defaultParams; 226 | @property (nonatomic, strong) Class openClass; 227 | @property (nonatomic, copy ) JYRouterOpenCallback callback; 228 | @end 229 | 230 | @implementation JYRouterOptions 231 | + (instancetype)routerOptionsWithModal:(BOOL)isModal { 232 | JYRouterOptions *options = [[JYRouterOptions alloc] init]; 233 | options.presentationStyle = UIModalPresentationNone; 234 | options.transitionStyle = UIModalTransitionStyleCoverVertical; 235 | options.isModal = isModal; 236 | return options; 237 | } 238 | 239 | + (instancetype)routerOptions { 240 | return [self routerOptionsWithModal:NO]; 241 | } 242 | 243 | + (instancetype)routerOptionsAsModal { 244 | return [self routerOptionsWithModal:YES]; 245 | } 246 | 247 | - (JYRouterOptions *)withPresentationStyle:(UIModalPresentationStyle)style { 248 | [self setPresentationStyle:style]; 249 | return self; 250 | } 251 | 252 | @end 253 | 254 | @interface JYRouterParams() 255 | @property (nonatomic, strong) JYRouterOptions *routerOptions; 256 | @property (nonatomic, strong) NSDictionary *openParams; 257 | @property (nonatomic, strong) NSDictionary *extraParams; 258 | @property (nonatomic, strong) NSDictionary *controllerParams; 259 | @end 260 | 261 | @implementation JYRouterParams 262 | - (instancetype)initWithRouterOptions:(JYRouterOptions *)routerOptions 263 | openParams:(NSDictionary *)openParams 264 | extraParams:(NSDictionary *)extraParams { 265 | [self setRouterOptions:routerOptions]; 266 | [self setExtraParams:extraParams]; 267 | [self setOpenParams:openParams]; 268 | return self; 269 | } 270 | 271 | @end 272 | 273 | 274 | #define ROUTE_NOT_FOUND_FORMAT @"No route found for URL %@" 275 | #define INVALID_CONTROLLER_FORMAT @"Your controller class %@ needs to implement either the static method %@ or the instance method %@" 276 | 277 | @interface JYRouter() 278 | @property (nonatomic, strong) UINavigationController *navigationController; 279 | @property (nonatomic, strong) NSMutableDictionary *routes; 280 | @property (nonatomic, strong) NSMutableDictionary *cachedRoutes; 281 | @property (nonatomic, strong) Class navClass; 282 | @end 283 | 284 | @implementation JYRouter 285 | 286 | + (instancetype)router { 287 | static JYRouter *_sharedRouter = nil; 288 | static dispatch_once_t onceToken; 289 | dispatch_once(&onceToken, ^{ 290 | _sharedRouter = [[JYRouter alloc] init]; 291 | }); 292 | return _sharedRouter; 293 | } 294 | 295 | + (instancetype)newRouter { 296 | return [[self alloc] init]; 297 | } 298 | 299 | - (instancetype)init { 300 | if (self = [super init]) { 301 | self.routes = [NSMutableDictionary dictionary]; 302 | self.cachedRoutes = [NSMutableDictionary dictionary]; 303 | } 304 | return self; 305 | } 306 | 307 | + (UIViewController *)currentVC { 308 | UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; 309 | while (topController.presentedViewController) { 310 | topController = topController.presentedViewController; 311 | } 312 | return topController; 313 | } 314 | 315 | - (void)setCustomNavigationClass:(Class)navClass { 316 | if (![navClass isSubclassOfClass:[UINavigationController class]]) { 317 | @throw [NSException exceptionWithName:@"NavClassTypeError" 318 | reason:@"navClass must be UINavigationController class or Subclass of UINavigationController" 319 | userInfo:nil]; 320 | } 321 | self.navClass = navClass; 322 | } 323 | 324 | - (BOOL)hasRouter:(NSString *)url { 325 | return [self.routes.allKeys containsObject:url]; 326 | } 327 | 328 | - (UIViewController *)controllerWithRouter:(NSString *)viewController { 329 | return [self controllerWithRouter:viewController 330 | params:nil]; 331 | } 332 | 333 | - (UIViewController *)controllerWithRouter:(NSString *)viewController 334 | params:(NSDictionary *)params { 335 | 336 | JYRouterOptions *options = [JYRouterOptions routerOptions]; 337 | 338 | if (![self hasRouter:viewController]) { 339 | [self map:viewController toController:[self classFromString:viewController] withOptions:options]; 340 | } 341 | JYRouterParams *extraParams = [self routerParamsForUrl:viewController extraParams:params]; 342 | 343 | options.openClass = [self classFromString:viewController]; 344 | extraParams.routerOptions = options; 345 | 346 | UIViewController *controller = [self controllerForRouterParams:extraParams]; 347 | [controller modelWithDictionary:params]; 348 | 349 | return controller; 350 | } 351 | 352 | - (void)push:(NSString *)viewController { 353 | [self push:viewController animated:YES]; 354 | } 355 | 356 | - (void)push:(NSString *)viewController animated:(BOOL)animated { 357 | [self push:viewController animated:animated params:nil]; 358 | } 359 | 360 | - (void)push:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params { 361 | [self push:viewController animated:animated params:params completion:nil]; 362 | } 363 | 364 | - (void)push:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 365 | [self open:viewController withOptions:nil animated:animated params:params completion:completion]; 366 | } 367 | 368 | - (void)present:(NSString *)viewController { 369 | [self present:viewController animated:YES]; 370 | } 371 | 372 | - (void)present:(NSString *)viewController animated:(BOOL)animated { 373 | [self present:viewController animated:animated params:nil]; 374 | } 375 | 376 | - (void)present:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params { 377 | [self present:viewController animated:animated params:params completion:nil]; 378 | } 379 | 380 | - (void)present:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 381 | [self open:viewController withOptions:[[JYRouterOptions routerOptionsAsModal] withPresentationStyle:UIModalPresentationFormSheet] animated:animated params:params completion:completion]; 382 | } 383 | 384 | - (void)present:(NSString *)viewController withOptions:(JYRouterOptions *)options animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 385 | [self open:viewController withOptions:options animated:animated params:params completion:completion]; 386 | } 387 | 388 | - (void)pop { 389 | [self popViewControllerFromRouterAnimated:YES]; 390 | } 391 | 392 | - (void)pop:(BOOL)animated { 393 | [self popViewControllerFromRouterAnimated:animated]; 394 | } 395 | 396 | - (void)popToRoot { 397 | [self popToRoot:YES]; 398 | } 399 | 400 | - (void)popToRoot:(BOOL)animated { 401 | [self popToRoot:animated completion:nil]; 402 | } 403 | 404 | - (void)popToRoot:(BOOL)animated completion:(void(^)(void))completion { 405 | [self.navigationController popToRootViewController:animated completion:completion]; 406 | } 407 | 408 | - (void)popTo:(NSString *)viewController { 409 | [self popTo:viewController animated:YES]; 410 | } 411 | 412 | - (void)popTo:(NSString *)viewController animated:(BOOL)animated { 413 | [self popTo:viewController animated:YES completion:nil]; 414 | } 415 | 416 | - (void)popTo:(NSString *)viewController animated:(BOOL)animated completion:(void(^)(void))completion { 417 | for (UIViewController *tempVC in self.navigationController.viewControllers) { 418 | if ([NSStringFromClass([tempVC class]) isEqualToString:viewController]) { 419 | [self.navigationController popToViewController:tempVC animated:animated completion:completion]; 420 | break; 421 | } 422 | } 423 | } 424 | 425 | - (void)dismiss { 426 | [self dismiss:YES]; 427 | } 428 | 429 | - (void)dismiss:(BOOL)animated { 430 | [self dismiss:animated completion:nil]; 431 | } 432 | 433 | - (void)dismiss:(BOOL)animated completion:(void(^)(void))completion { 434 | [self.navigationController dismissViewControllerAnimated:animated completion:completion]; 435 | } 436 | 437 | - (void)open:(NSString *)url withOptions:(JYRouterOptions *)options animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 438 | 439 | if (![self hasRouter:url]) { 440 | [self map:url toController:[self classFromString:url] withOptions:options]; 441 | } 442 | 443 | JYRouterParams *extraParams = [self routerParamsForUrl:url extraParams:params]; 444 | if (!options) { 445 | options = [JYRouterOptions routerOptions]; 446 | } 447 | options.openClass = [self classFromString:url]; 448 | extraParams.routerOptions = options; 449 | 450 | if (options.callback) { 451 | JYRouterOpenCallback callback = options.callback; 452 | callback([extraParams controllerParams]); 453 | return; 454 | } 455 | 456 | if (!self.navigationController) { 457 | @throw [NSException exceptionWithName:@"NavigationControllerNotProvided" 458 | reason:@"Router#navigationController has not been set to a UINavigationController instance" 459 | userInfo:nil]; 460 | } 461 | 462 | UIViewController *controller = [self controllerForRouterParams:extraParams]; 463 | [controller modelWithDictionary:params]; 464 | 465 | 466 | if ([options isModal]) { 467 | if ([controller.class isSubclassOfClass:UINavigationController.class]) { 468 | [self.navigationController presentViewController:controller 469 | animated:animated 470 | completion:completion]; 471 | } 472 | else { 473 | if (!self.navClass) { 474 | self.navClass = [UINavigationController class]; 475 | } 476 | UINavigationController *navigationController = [[self.navClass alloc] initWithRootViewController:controller]; 477 | navigationController.modalPresentationStyle = controller.modalPresentationStyle; 478 | navigationController.modalTransitionStyle = controller.modalTransitionStyle; 479 | 480 | [self.navigationController presentViewController:navigationController 481 | animated:animated 482 | completion:completion]; 483 | } 484 | } 485 | else { 486 | [self.navigationController pushViewController:controller animated:animated completion:completion]; 487 | } 488 | } 489 | 490 | - (Class)classFromString:(NSString *)className { 491 | Class class = NSClassFromString(className); 492 | if (!class) { 493 | class = [self swiftClassFromString:className]; 494 | } 495 | // NSLog(@"class = %@",class); 496 | return class; 497 | } 498 | 499 | - (Class)swiftClassFromString:(NSString *)className { 500 | NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"]; 501 | appName = [appName stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; 502 | NSString *classStringName = [NSString stringWithFormat:@"%@.%@", appName, className]; 503 | return NSClassFromString(classStringName); 504 | } 505 | 506 | - (UINavigationController *)navigationController { 507 | return [self navigationControllerWithController:[UIApplication sharedApplication].delegate.window.rootViewController]; 508 | } 509 | 510 | - (UINavigationController *)navigationControllerWithController:(UIViewController *)viewController { 511 | if (viewController.presentedViewController) { 512 | return [self navigationControllerWithController:viewController.presentedViewController]; 513 | } 514 | else if ([viewController isKindOfClass:[UITabBarController class]]) { 515 | UITabBarController *vc = (UITabBarController *)viewController; 516 | return vc.selectedViewController; 517 | } 518 | else { 519 | return (UINavigationController *)viewController; 520 | } 521 | } 522 | 523 | - (void)map:(NSString *)format toController:(Class)controllerClass withOptions:(JYRouterOptions *)options { 524 | if (!format) { 525 | @throw [NSException exceptionWithName:@"RouteNotProvided" 526 | reason:@"Route #format is not initialized" 527 | userInfo:nil]; 528 | return; 529 | } 530 | if (!options) { 531 | options = [JYRouterOptions routerOptions]; 532 | } 533 | options.openClass = controllerClass; 534 | [self.routes setObject:options forKey:format]; 535 | } 536 | 537 | 538 | - (void)popViewControllerFromRouterAnimated:(BOOL)animated { 539 | if (self.navigationController.presentedViewController) { 540 | [self.navigationController dismissViewControllerAnimated:animated completion:nil]; 541 | } 542 | else { 543 | [self.navigationController popViewControllerAnimated:animated]; 544 | } 545 | } 546 | 547 | 548 | - (JYRouterParams *)routerParamsForUrl:(NSString *)url extraParams: (NSDictionary *)extraParams { 549 | if (!url) { 550 | if (_ignoresExceptions) { 551 | return nil; 552 | } 553 | @throw [NSException exceptionWithName:@"RouteNotFoundException" 554 | reason:[NSString stringWithFormat:ROUTE_NOT_FOUND_FORMAT, url] 555 | userInfo:nil]; 556 | } 557 | 558 | if ([self.cachedRoutes objectForKey:url] && !extraParams) { 559 | return [self.cachedRoutes objectForKey:url]; 560 | } 561 | 562 | NSArray *givenParts = url.pathComponents; 563 | NSArray *legacyParts = [url componentsSeparatedByString:@"/"]; 564 | if ([legacyParts count] != [givenParts count]) { 565 | NSLog(@"Routable Warning - your URL %@ has empty path components - this will throw an error in an upcoming release", url); 566 | givenParts = legacyParts; 567 | } 568 | 569 | __block JYRouterParams *openParams = nil; 570 | [self.routes enumerateKeysAndObjectsUsingBlock: 571 | ^(NSString *routerUrl, JYRouterOptions *routerOptions, BOOL *stop) { 572 | 573 | NSArray *routerParts = [routerUrl pathComponents]; 574 | if ([routerParts count] == [givenParts count]) { 575 | 576 | NSDictionary *givenParams = [self paramsForUrlComponents:givenParts routerUrlComponents:routerParts]; 577 | if (givenParams) { 578 | openParams = [[JYRouterParams alloc] initWithRouterOptions:routerOptions 579 | openParams:givenParams 580 | extraParams:extraParams]; 581 | *stop = YES; 582 | } 583 | } 584 | }]; 585 | 586 | if (!openParams) { 587 | if (_ignoresExceptions) { 588 | return nil; 589 | } 590 | @throw [NSException exceptionWithName:@"RouteNotFoundException" 591 | reason:[NSString stringWithFormat:ROUTE_NOT_FOUND_FORMAT, url] 592 | userInfo:nil]; 593 | } 594 | [self.cachedRoutes setObject:openParams forKey:url]; 595 | return openParams; 596 | } 597 | 598 | - (NSDictionary *)paramsForUrlComponents:(NSArray *)givenUrlComponents 599 | routerUrlComponents:(NSArray *)routerUrlComponents { 600 | 601 | __block NSMutableDictionary *params = [NSMutableDictionary dictionary]; 602 | [routerUrlComponents enumerateObjectsUsingBlock: 603 | ^(NSString *routerComponent, NSUInteger idx, BOOL *stop) { 604 | 605 | NSString *givenComponent = givenUrlComponents[idx]; 606 | if ([routerComponent hasPrefix:@":"]) { 607 | NSString *key = [routerComponent substringFromIndex:1]; 608 | [params setObject:givenComponent forKey:key]; 609 | } 610 | else if (![routerComponent isEqualToString:givenComponent]) { 611 | params = nil; 612 | *stop = YES; 613 | } 614 | }]; 615 | return params; 616 | } 617 | 618 | - (UIViewController *)controllerForRouterParams:(JYRouterParams *)params { 619 | SEL CONTROLLER_CLASS_SELECTOR = sel_registerName("allocWithRouterParams:"); 620 | SEL CONTROLLER_SELECTOR = sel_registerName("initWithRouterParams:"); 621 | SEL CONTROLLER_INIT = sel_registerName("init"); 622 | UIViewController *controller = nil; 623 | Class controllerClass = params.routerOptions.openClass; 624 | #pragma clang diagnostic push 625 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 626 | if ([controllerClass respondsToSelector:CONTROLLER_CLASS_SELECTOR]) { 627 | controller = [controllerClass performSelector:CONTROLLER_CLASS_SELECTOR withObject:[params controllerParams]]; 628 | } 629 | else if ([params.routerOptions.openClass instancesRespondToSelector:CONTROLLER_SELECTOR]) { 630 | controller = [[params.routerOptions.openClass alloc] performSelector:CONTROLLER_SELECTOR withObject:[params controllerParams]]; 631 | } 632 | else { 633 | controller = [[params.routerOptions.openClass alloc] performSelector:CONTROLLER_INIT]; 634 | } 635 | #pragma clang diagnostic pop 636 | if (!controller) { 637 | if (_ignoresExceptions) { 638 | return controller; 639 | } 640 | @throw [NSException exceptionWithName:@"RoutableInitializerNotFound" 641 | reason:[NSString stringWithFormat:INVALID_CONTROLLER_FORMAT, NSStringFromClass(controllerClass), NSStringFromSelector(CONTROLLER_CLASS_SELECTOR), NSStringFromSelector(CONTROLLER_SELECTOR)] 642 | userInfo:nil]; 643 | } 644 | 645 | controller.modalTransitionStyle = params.routerOptions.transitionStyle; 646 | controller.modalPresentationStyle = params.routerOptions.presentationStyle; 647 | return controller; 648 | } 649 | 650 | 651 | @end 652 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/JYViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JYViewController.h 3 | // JYRouterDemo 4 | // 5 | // Created by 杨权 on 2016/12/13. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JYViewController : UIViewController 12 | 13 | //待传值的参数列表,这边参数既可以写在.h中,也可以写在.m中 14 | 15 | /** 16 | * 参数1 -- 字符串 17 | */ 18 | @property (copy, nonatomic) NSString *parameterString; 19 | /** 20 | * 参数2 -- 数值 21 | */ 22 | @property (strong, nonatomic) NSNumber *parameterNumber; 23 | /** 24 | * 参数3 -- 字典 25 | */ 26 | @property (strong, nonatomic) NSDictionary *parameterDictionary; 27 | /** 28 | * 参数4 -- 基本类型 29 | */ 30 | @property (assign, nonatomic) BOOL parameterBool; 31 | /** 32 | * 参数5 -- 结构体 33 | */ 34 | @property (assign, nonatomic) CGSize parameterSize; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/JYViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JYViewController.m 3 | // JYRouterDemo 4 | // 5 | // Created by 杨权 on 2016/12/13. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import "JYViewController.h" 10 | #import "JYRouter.h" 11 | 12 | #define kSCREEN_HEIGHT [[UIScreen mainScreen] bounds].size.height 13 | #define kSCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width 14 | 15 | @interface JYViewController () 16 | @property (strong, nonatomic) UITableView *tableView; 17 | @property (strong, nonatomic) NSArray *dataList; 18 | @end 19 | 20 | @implementation JYViewController 21 | 22 | #pragma mark - life cycle 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | [self setNavigation]; 26 | [self showParameter]; 27 | [self.view addSubview:self.tableView]; 28 | } 29 | 30 | #pragma mark - setup methods 31 | - (void)setNavigation { 32 | self.navigationItem.title = @"JYRouter"; 33 | CGFloat red = arc4random() % 255; 34 | CGFloat green = arc4random() % 255; 35 | CGFloat bule = arc4random() % 255; 36 | self.navigationController.navigationBar.barTintColor = [UIColor colorWithRed:red/255 green:green/255 blue:bule/255 alpha:1]; 37 | } 38 | 39 | - (void)showParameter { 40 | NSLog(@"-----------------------------------------------"); 41 | NSLog(@"⭕️parameterString = %@",self.parameterString); 42 | NSLog(@"⭕️parameterNumber = %@",self.parameterNumber); 43 | NSLog(@"⭕️parameterDictionary = %@",self.parameterDictionary); 44 | NSLog(@"⭕️parameterBool = %d",self.parameterBool); 45 | NSLog(@"⭕️parameterSize = %@",NSStringFromCGSize(self.parameterSize)); 46 | NSLog(@"-----------------------------------------------\n\n"); 47 | } 48 | 49 | #pragma mark - UITableViewDataSource 50 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 51 | return self.dataList.count; 52 | } 53 | 54 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 55 | return [self.dataList[section][@"list"] count]; 56 | } 57 | 58 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 59 | return 44; 60 | } 61 | 62 | - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 63 | return self.dataList[section][@"group"]; 64 | } 65 | 66 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 67 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellIdentifier"]; 68 | if (!cell) { 69 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellIdentifier"]; 70 | } 71 | NSString *title = self.dataList[indexPath.section][@"list"][indexPath.row]; 72 | cell.textLabel.text = title; 73 | return cell; 74 | } 75 | 76 | #pragma mark - UITableViewDelegate 77 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 78 | 79 | [self routerAtIndexPath:indexPath]; 80 | } 81 | 82 | #pragma mark - event & response 83 | - (void)routerAtIndexPath:(NSIndexPath *)indexPath { 84 | 85 | NSString *group = self.dataList[indexPath.section][@"group"]; 86 | NSDictionary *params = @{ 87 | @"parameterString" : [NSString stringWithFormat:@"%@-%@",@"我是一个字符串", group], 88 | @"parameterNumber" : @(123456789), 89 | @"parameterBool": @(YES), 90 | @"parameterSize": @(CGSizeMake(100, 200)), 91 | @"parameterDictionary" : @{ 92 | @"key1": [NSString stringWithFormat:@"%@-%@",@"Value1", group], 93 | @"key2": [NSString stringWithFormat:@"%@-%@",@"Value2", group], 94 | }, 95 | }; 96 | 97 | 98 | switch (indexPath.section) { 99 | // ---------------------- Push ---------------------- 100 | case 0: { 101 | switch (indexPath.row) { 102 | /** 103 | Push跳转 104 | */ 105 | case 0: { 106 | [[JYRouter router] push:@"JYViewController"]; 107 | break; 108 | } 109 | /** 110 | Push跳转,附带参数 111 | */ 112 | case 1: { 113 | [[JYRouter router] push:@"JYViewController" animated:YES params:params]; 114 | break; 115 | } 116 | /** 117 | Push跳转,附带参数,完成回调 118 | */ 119 | case 2: { 120 | [[JYRouter router] push:@"JYViewController" animated:YES params:params completion:^{ 121 | NSLog(@"🔥🔥🔥Push完成回调🔥🔥🔥"); 122 | }]; 123 | break; 124 | } 125 | default: 126 | break; 127 | } 128 | break; 129 | } 130 | 131 | // ---------------------- Pop ---------------------- 132 | case 1: { 133 | switch (indexPath.row) { 134 | /** 135 | Pop到上级 136 | */ 137 | case 0: { 138 | [[JYRouter router] pop]; 139 | break; 140 | } 141 | /** 142 | Pop到根控制器 143 | */ 144 | case 1: { 145 | [[JYRouter router] popToRoot]; 146 | break; 147 | } 148 | /** 149 | Pop到根控制器,完成回调 150 | */ 151 | case 2: { 152 | [[JYRouter router] popToRoot:YES completion:^{ 153 | NSLog(@"💧💧💧Pop完成回调💧💧💧"); 154 | }]; 155 | break; 156 | } 157 | /** 158 | Pop到指定控制器 159 | */ 160 | case 3: { 161 | [[JYRouter router] popTo:@"JYViewController"]; 162 | break; 163 | } 164 | /** 165 | Pop到指定控制器,完成回调 166 | */ 167 | case 4: { 168 | [[JYRouter router] popTo:@"JYViewController" animated:YES completion:^{ 169 | NSLog(@"💧💧💧Pop完成回调💧💧💧"); 170 | }]; 171 | break; 172 | } 173 | default: 174 | break; 175 | } 176 | break; 177 | } 178 | 179 | // ---------------------- Present ---------------------- 180 | case 2: { 181 | switch (indexPath.row) { 182 | /** 183 | present跳转 184 | */ 185 | case 0: { 186 | [[JYRouter router] present:@"JYViewController"]; 187 | break; 188 | } 189 | /** 190 | Present跳转,附带参数 191 | */ 192 | case 1: { 193 | [[JYRouter router] present:@"JYViewController" animated:YES params:params]; 194 | break; 195 | } 196 | /** 197 | Present跳转,附带参数,完成回调 198 | */ 199 | case 2: { 200 | [[JYRouter router] present:@"JYViewController" animated:YES params:params completion:^{ 201 | NSLog(@"🌧🌧🌧Pop完成回调🌧🌧🌧"); 202 | }]; 203 | break; 204 | } 205 | default: 206 | break; 207 | } 208 | break; 209 | } 210 | 211 | // ---------------------- Dismiss ---------------------- 212 | case 3: { 213 | switch (indexPath.row) { 214 | /** 215 | Dismiss 216 | */ 217 | case 0: { 218 | [[JYRouter router] dismiss]; 219 | break; 220 | } 221 | /** 222 | Dismiss,完成回调 223 | */ 224 | case 1: { 225 | [[JYRouter router] dismiss:YES completion:^{ 226 | NSLog(@"⚡️⚡️⚡️Dismiss完成回调⚡️⚡️⚡️"); 227 | }]; 228 | break; 229 | } 230 | default: 231 | break; 232 | } 233 | break; 234 | } 235 | default: 236 | break; 237 | } 238 | 239 | } 240 | 241 | #pragma mark - getter & setter 242 | - (UITableView *)tableView { 243 | if (!_tableView) { 244 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, kSCREEN_WIDTH, kSCREEN_HEIGHT-64) 245 | style:UITableViewStylePlain]; 246 | _tableView.delegate = self; 247 | _tableView.dataSource = self; 248 | } 249 | return _tableView; 250 | } 251 | 252 | - (NSArray *)dataList { 253 | if (!_dataList) { 254 | //配置数据 255 | NSError *error = nil; 256 | NSString *path = [[NSBundle mainBundle] pathForResource:@"dataList" ofType:@"json"]; 257 | NSData *data = [[NSData alloc] initWithContentsOfFile:path]; 258 | NSArray *array = [NSJSONSerialization JSONObjectWithData:data 259 | options:NSJSONReadingAllowFragments 260 | error:&error]; 261 | _dataList = array; 262 | } 263 | return _dataList; 264 | } 265 | 266 | @end 267 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/dataList.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "group": "Push", 4 | "list": [ 5 | "push跳转", 6 | "push跳转,附带参数", 7 | "push跳转,附带参数,完成回调" 8 | ] 9 | }, 10 | { 11 | "group": "Pop", 12 | "list": [ 13 | "Pop到上级", 14 | "Pop到根控制器", 15 | "Pop到根控制器,完成回调", 16 | "Pop到指定控制器", 17 | "Pop到指定控制器,完成回调" 18 | ] 19 | }, 20 | { 21 | "group": "Present", 22 | "list": [ 23 | "Present跳转", 24 | "Present跳转,附带参数", 25 | "Present跳转,附带参数,完成回调" 26 | ] 27 | }, 28 | { 29 | "group": "Dismiss", 30 | "list": [ 31 | "Dismiss", 32 | "Dismiss,完成回调" 33 | ] 34 | } 35 | ] 36 | -------------------------------------------------------------------------------- /Demo/Objective-C/JYRouterDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // JYRouterDemo 4 | // 5 | // Created by 杨权 on 2016/12/12. 6 | // Copyright © 2016年 Job-Yang. 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 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B16B94F41E1CEAA40080B79B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B16B94F31E1CEAA40080B79B /* AppDelegate.swift */; }; 11 | B16B94FB1E1CEAA40080B79B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B16B94FA1E1CEAA40080B79B /* Assets.xcassets */; }; 12 | B16B94FE1E1CEAA40080B79B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B16B94FC1E1CEAA40080B79B /* LaunchScreen.storyboard */; }; 13 | B16B95091E1CEB6A0080B79B /* dataList.json in Resources */ = {isa = PBXBuildFile; fileRef = B16B95051E1CEB6A0080B79B /* dataList.json */; }; 14 | B16B950A1E1CEB6A0080B79B /* JYNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B16B95061E1CEB6A0080B79B /* JYNavigationController.swift */; }; 15 | B16B950B1E1CEB6A0080B79B /* JYViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B16B95081E1CEB6A0080B79B /* JYViewController.swift */; }; 16 | B16B95171E1CEBBF0080B79B /* JYRouter.m in Sources */ = {isa = PBXBuildFile; fileRef = B16B950E1E1CEBBF0080B79B /* JYRouter.m */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | B16B94F01E1CEAA40080B79B /* JYRouterDemo-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "JYRouterDemo-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | B16B94F31E1CEAA40080B79B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 22 | B16B94FA1E1CEAA40080B79B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 23 | B16B94FD1E1CEAA40080B79B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 24 | B16B94FF1E1CEAA40080B79B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 25 | B16B95051E1CEB6A0080B79B /* dataList.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = dataList.json; sourceTree = ""; }; 26 | B16B95061E1CEB6A0080B79B /* JYNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JYNavigationController.swift; sourceTree = ""; }; 27 | B16B95071E1CEB6A0080B79B /* JYRouterDemo-Swift-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JYRouterDemo-Swift-Bridging-Header.h"; sourceTree = ""; }; 28 | B16B95081E1CEB6A0080B79B /* JYViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JYViewController.swift; sourceTree = ""; }; 29 | B16B950D1E1CEBBF0080B79B /* JYRouter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JYRouter.h; sourceTree = ""; }; 30 | B16B950E1E1CEBBF0080B79B /* JYRouter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JYRouter.m; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | B16B94ED1E1CEAA40080B79B /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | B16B94E71E1CEAA40080B79B = { 45 | isa = PBXGroup; 46 | children = ( 47 | B16B94F21E1CEAA40080B79B /* JYRouterDemo-Swift */, 48 | B16B94F11E1CEAA40080B79B /* Products */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | B16B94F11E1CEAA40080B79B /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | B16B94F01E1CEAA40080B79B /* JYRouterDemo-Swift.app */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | B16B94F21E1CEAA40080B79B /* JYRouterDemo-Swift */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | B16B950C1E1CEBBF0080B79B /* JYRouter */, 64 | B16B94F31E1CEAA40080B79B /* AppDelegate.swift */, 65 | B16B95061E1CEB6A0080B79B /* JYNavigationController.swift */, 66 | B16B95081E1CEB6A0080B79B /* JYViewController.swift */, 67 | B16B95071E1CEB6A0080B79B /* JYRouterDemo-Swift-Bridging-Header.h */, 68 | B16B95051E1CEB6A0080B79B /* dataList.json */, 69 | B16B94FA1E1CEAA40080B79B /* Assets.xcassets */, 70 | B16B94FC1E1CEAA40080B79B /* LaunchScreen.storyboard */, 71 | B16B94FF1E1CEAA40080B79B /* Info.plist */, 72 | ); 73 | path = "JYRouterDemo-Swift"; 74 | sourceTree = ""; 75 | }; 76 | B16B950C1E1CEBBF0080B79B /* JYRouter */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | B16B950D1E1CEBBF0080B79B /* JYRouter.h */, 80 | B16B950E1E1CEBBF0080B79B /* JYRouter.m */, 81 | ); 82 | path = JYRouter; 83 | sourceTree = ""; 84 | }; 85 | /* End PBXGroup section */ 86 | 87 | /* Begin PBXNativeTarget section */ 88 | B16B94EF1E1CEAA40080B79B /* JYRouterDemo-Swift */ = { 89 | isa = PBXNativeTarget; 90 | buildConfigurationList = B16B95021E1CEAA40080B79B /* Build configuration list for PBXNativeTarget "JYRouterDemo-Swift" */; 91 | buildPhases = ( 92 | B16B94EC1E1CEAA40080B79B /* Sources */, 93 | B16B94ED1E1CEAA40080B79B /* Frameworks */, 94 | B16B94EE1E1CEAA40080B79B /* Resources */, 95 | ); 96 | buildRules = ( 97 | ); 98 | dependencies = ( 99 | ); 100 | name = "JYRouterDemo-Swift"; 101 | productName = "JYRouterDemo-Swift"; 102 | productReference = B16B94F01E1CEAA40080B79B /* JYRouterDemo-Swift.app */; 103 | productType = "com.apple.product-type.application"; 104 | }; 105 | /* End PBXNativeTarget section */ 106 | 107 | /* Begin PBXProject section */ 108 | B16B94E81E1CEAA40080B79B /* Project object */ = { 109 | isa = PBXProject; 110 | attributes = { 111 | LastSwiftUpdateCheck = 0820; 112 | LastUpgradeCheck = 0910; 113 | ORGANIZATIONNAME = "Job-Yang"; 114 | TargetAttributes = { 115 | B16B94EF1E1CEAA40080B79B = { 116 | CreatedOnToolsVersion = 8.2; 117 | LastSwiftMigration = 0910; 118 | ProvisioningStyle = Manual; 119 | }; 120 | }; 121 | }; 122 | buildConfigurationList = B16B94EB1E1CEAA40080B79B /* Build configuration list for PBXProject "JYRouterDemo-Swift" */; 123 | compatibilityVersion = "Xcode 3.2"; 124 | developmentRegion = English; 125 | hasScannedForEncodings = 0; 126 | knownRegions = ( 127 | en, 128 | Base, 129 | ); 130 | mainGroup = B16B94E71E1CEAA40080B79B; 131 | productRefGroup = B16B94F11E1CEAA40080B79B /* Products */; 132 | projectDirPath = ""; 133 | projectRoot = ""; 134 | targets = ( 135 | B16B94EF1E1CEAA40080B79B /* JYRouterDemo-Swift */, 136 | ); 137 | }; 138 | /* End PBXProject section */ 139 | 140 | /* Begin PBXResourcesBuildPhase section */ 141 | B16B94EE1E1CEAA40080B79B /* Resources */ = { 142 | isa = PBXResourcesBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | B16B95091E1CEB6A0080B79B /* dataList.json in Resources */, 146 | B16B94FE1E1CEAA40080B79B /* LaunchScreen.storyboard in Resources */, 147 | B16B94FB1E1CEAA40080B79B /* Assets.xcassets in Resources */, 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | /* End PBXResourcesBuildPhase section */ 152 | 153 | /* Begin PBXSourcesBuildPhase section */ 154 | B16B94EC1E1CEAA40080B79B /* Sources */ = { 155 | isa = PBXSourcesBuildPhase; 156 | buildActionMask = 2147483647; 157 | files = ( 158 | B16B950B1E1CEB6A0080B79B /* JYViewController.swift in Sources */, 159 | B16B95171E1CEBBF0080B79B /* JYRouter.m in Sources */, 160 | B16B950A1E1CEB6A0080B79B /* JYNavigationController.swift in Sources */, 161 | B16B94F41E1CEAA40080B79B /* AppDelegate.swift in Sources */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | /* End PBXSourcesBuildPhase section */ 166 | 167 | /* Begin PBXVariantGroup section */ 168 | B16B94FC1E1CEAA40080B79B /* LaunchScreen.storyboard */ = { 169 | isa = PBXVariantGroup; 170 | children = ( 171 | B16B94FD1E1CEAA40080B79B /* Base */, 172 | ); 173 | name = LaunchScreen.storyboard; 174 | sourceTree = ""; 175 | }; 176 | /* End PBXVariantGroup section */ 177 | 178 | /* Begin XCBuildConfiguration section */ 179 | B16B95001E1CEAA40080B79B /* Debug */ = { 180 | isa = XCBuildConfiguration; 181 | buildSettings = { 182 | ALWAYS_SEARCH_USER_PATHS = NO; 183 | CLANG_ANALYZER_NONNULL = YES; 184 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 185 | CLANG_CXX_LIBRARY = "libc++"; 186 | CLANG_ENABLE_MODULES = YES; 187 | CLANG_ENABLE_OBJC_ARC = YES; 188 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 189 | CLANG_WARN_BOOL_CONVERSION = YES; 190 | CLANG_WARN_COMMA = YES; 191 | CLANG_WARN_CONSTANT_CONVERSION = YES; 192 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 193 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 194 | CLANG_WARN_EMPTY_BODY = YES; 195 | CLANG_WARN_ENUM_CONVERSION = YES; 196 | CLANG_WARN_INFINITE_RECURSION = YES; 197 | CLANG_WARN_INT_CONVERSION = YES; 198 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 199 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 200 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 201 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 202 | CLANG_WARN_STRICT_PROTOTYPES = YES; 203 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 204 | CLANG_WARN_UNREACHABLE_CODE = YES; 205 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 206 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 207 | COPY_PHASE_STRIP = NO; 208 | DEBUG_INFORMATION_FORMAT = dwarf; 209 | ENABLE_STRICT_OBJC_MSGSEND = YES; 210 | ENABLE_TESTABILITY = YES; 211 | GCC_C_LANGUAGE_STANDARD = gnu99; 212 | GCC_DYNAMIC_NO_PIC = NO; 213 | GCC_NO_COMMON_BLOCKS = YES; 214 | GCC_OPTIMIZATION_LEVEL = 0; 215 | GCC_PREPROCESSOR_DEFINITIONS = ( 216 | "DEBUG=1", 217 | "$(inherited)", 218 | ); 219 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 220 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 221 | GCC_WARN_UNDECLARED_SELECTOR = YES; 222 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 223 | GCC_WARN_UNUSED_FUNCTION = YES; 224 | GCC_WARN_UNUSED_VARIABLE = YES; 225 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 226 | MTL_ENABLE_DEBUG_INFO = YES; 227 | ONLY_ACTIVE_ARCH = YES; 228 | SDKROOT = iphoneos; 229 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 230 | SWIFT_OBJC_BRIDGING_HEADER = "JYRouterDemo-Swift/JYRouterDemo-Swift-Bridging-Header.h"; 231 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 232 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 233 | }; 234 | name = Debug; 235 | }; 236 | B16B95011E1CEAA40080B79B /* Release */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 242 | CLANG_CXX_LIBRARY = "libc++"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 246 | CLANG_WARN_BOOL_CONVERSION = YES; 247 | CLANG_WARN_COMMA = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 250 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 251 | CLANG_WARN_EMPTY_BODY = YES; 252 | CLANG_WARN_ENUM_CONVERSION = YES; 253 | CLANG_WARN_INFINITE_RECURSION = YES; 254 | CLANG_WARN_INT_CONVERSION = YES; 255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 257 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 258 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 259 | CLANG_WARN_STRICT_PROTOTYPES = YES; 260 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 261 | CLANG_WARN_UNREACHABLE_CODE = YES; 262 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 263 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 264 | COPY_PHASE_STRIP = NO; 265 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 266 | ENABLE_NS_ASSERTIONS = NO; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | GCC_C_LANGUAGE_STANDARD = gnu99; 269 | GCC_NO_COMMON_BLOCKS = YES; 270 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 271 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 272 | GCC_WARN_UNDECLARED_SELECTOR = YES; 273 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 274 | GCC_WARN_UNUSED_FUNCTION = YES; 275 | GCC_WARN_UNUSED_VARIABLE = YES; 276 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 277 | MTL_ENABLE_DEBUG_INFO = NO; 278 | SDKROOT = iphoneos; 279 | SWIFT_OBJC_BRIDGING_HEADER = "JYRouterDemo-Swift/JYRouterDemo-Swift-Bridging-Header.h"; 280 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 281 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 282 | VALIDATE_PRODUCT = YES; 283 | }; 284 | name = Release; 285 | }; 286 | B16B95031E1CEAA40080B79B /* Debug */ = { 287 | isa = XCBuildConfiguration; 288 | buildSettings = { 289 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 290 | DEVELOPMENT_TEAM = ""; 291 | INFOPLIST_FILE = "JYRouterDemo-Swift/Info.plist"; 292 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = "Job-Yang.JYRouterDemo-Swift"; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "JYRouterDemo-Swift/JYRouterDemo-Swift-Bridging-Header.h"; 297 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 298 | SWIFT_VERSION = 4.0; 299 | }; 300 | name = Debug; 301 | }; 302 | B16B95041E1CEAA40080B79B /* Release */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 306 | DEVELOPMENT_TEAM = ""; 307 | INFOPLIST_FILE = "JYRouterDemo-Swift/Info.plist"; 308 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 309 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 310 | PRODUCT_BUNDLE_IDENTIFIER = "Job-Yang.JYRouterDemo-Swift"; 311 | PRODUCT_NAME = "$(TARGET_NAME)"; 312 | SWIFT_OBJC_BRIDGING_HEADER = "JYRouterDemo-Swift/JYRouterDemo-Swift-Bridging-Header.h"; 313 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 314 | SWIFT_VERSION = 4.0; 315 | }; 316 | name = Release; 317 | }; 318 | /* End XCBuildConfiguration section */ 319 | 320 | /* Begin XCConfigurationList section */ 321 | B16B94EB1E1CEAA40080B79B /* Build configuration list for PBXProject "JYRouterDemo-Swift" */ = { 322 | isa = XCConfigurationList; 323 | buildConfigurations = ( 324 | B16B95001E1CEAA40080B79B /* Debug */, 325 | B16B95011E1CEAA40080B79B /* Release */, 326 | ); 327 | defaultConfigurationIsVisible = 0; 328 | defaultConfigurationName = Release; 329 | }; 330 | B16B95021E1CEAA40080B79B /* Build configuration list for PBXNativeTarget "JYRouterDemo-Swift" */ = { 331 | isa = XCConfigurationList; 332 | buildConfigurations = ( 333 | B16B95031E1CEAA40080B79B /* Debug */, 334 | B16B95041E1CEAA40080B79B /* Release */, 335 | ); 336 | defaultConfigurationIsVisible = 0; 337 | defaultConfigurationName = Release; 338 | }; 339 | /* End XCConfigurationList section */ 340 | }; 341 | rootObject = B16B94E81E1CEAA40080B79B /* Project object */; 342 | } 343 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift.xcodeproj/project.xcworkspace/xcuserdata/Job-Yang.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Job-Yang/JYRouter/d30ac364e08f2ec79cc940e8da412d1613f3a041/Demo/Swift/JYRouterDemo-Swift.xcodeproj/project.xcworkspace/xcuserdata/Job-Yang.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift.xcodeproj/xcuserdata/Job-Yang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift.xcodeproj/xcuserdata/Job-Yang.xcuserdatad/xcschemes/JYRouterDemo-Swift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift.xcodeproj/xcuserdata/Job-Yang.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JYRouterDemo-Swift.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B16B94EF1E1CEAA40080B79B 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // JYRouterDemo-Swift 4 | // 5 | // Created by 杨权 on 2017/1/4. 6 | // Copyright © 2017年 Job-Yang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | 19 | // 设置主窗口,并设置跟控制器 20 | self.window = UIWindow() 21 | self.window?.frame = UIScreen.main.bounds 22 | let nav = JYNavigationController(rootViewController:JYViewController()) 23 | self.window?.rootViewController = nav 24 | self.window?.makeKeyAndVisible() 25 | 26 | //设置Router跳转时所显示的NavigationController 27 | JYRouter().setCustomNavigationClass(JYNavigationController.self) 28 | 29 | return true 30 | } 31 | 32 | func applicationWillResignActive(_ application: UIApplication) { 33 | // 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. 34 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 35 | } 36 | 37 | func applicationDidEnterBackground(_ application: UIApplication) { 38 | // 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. 39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 40 | } 41 | 42 | func applicationWillEnterForeground(_ application: UIApplication) { 43 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 44 | } 45 | 46 | func applicationDidBecomeActive(_ application: UIApplication) { 47 | // 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. 48 | } 49 | 50 | func applicationWillTerminate(_ application: UIApplication) { 51 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 52 | } 53 | 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/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 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/JYNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JYNavigationController.swift 3 | // JYRouterDemoForSwift 4 | // 5 | // Created by 杨权 on 2017/1/3. 6 | // Copyright © 2017年 Job-Yang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class JYNavigationController: UINavigationController { 12 | 13 | override var preferredStatusBarStyle: UIStatusBarStyle { 14 | return UIStatusBarStyle.lightContent 15 | } 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | setNavigationBar() 20 | } 21 | 22 | func setNavigationBar() { 23 | //设置NavigationBar背景颜色 24 | UINavigationBar.appearance().isTranslucent = false; 25 | UINavigationBar.appearance().barTintColor = .white; 26 | UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .any, barMetrics: .default) 27 | UINavigationBar.appearance().shadowImage = UIImage(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/JYRouter/JYRouter.h: -------------------------------------------------------------------------------- 1 | // 2 | // JYRouter.h 3 | // Job-Yang 4 | // 5 | // Created by 杨权 on 16/9/22. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void (^JYRouterOpenCallback)(NSDictionary *params); 13 | 14 | /** 15 | 跳转时属性自动复制的工具分类 16 | */ 17 | @interface NSObject (JYParams) 18 | @end 19 | 20 | /** 21 | 跳转时回调的分类 22 | */ 23 | @interface UINavigationController (JYCallBack) 24 | @end 25 | 26 | /** 27 | 跳转选项相关类 28 | */ 29 | @interface JYRouterOptions : NSObject 30 | @end 31 | 32 | /** 33 | 跳转参数相关类 34 | */ 35 | @interface JYRouterParams : NSObject 36 | @end 37 | 38 | 39 | @interface JYRouter : NSObject 40 | 41 | /** 42 | 是否忽略异常 43 | */ 44 | @property (nonatomic, assign) BOOL ignoresExceptions; 45 | 46 | /** 47 | 单例 48 | 49 | @return JYRouter单例对象 50 | */ 51 | + (instancetype)router; 52 | 53 | /** 54 | 获取一个新的Router对象 55 | 56 | @return JYRouter对象 57 | */ 58 | + (instancetype)newRouter; 59 | 60 | /** 61 | 获取当前显示的VC 62 | 63 | @return 当前显示的VC 64 | */ 65 | + (UIViewController *)currentVC; 66 | 67 | /** 68 | 设置自定义的Navigation,用于present时显示 69 | 如果您想全局设置,请在AppDelegate 的didFinishLaunchingWithOptions方法中设置 70 | [[JYRouter router] setCustomNavigationClass:[YourCustomNavigation class]]; 71 | 72 | @param navClass Navigation Class 73 | */ 74 | - (void)setCustomNavigationClass:(Class)navClass; 75 | 76 | /** 77 | 判断该URL是否可以路由跳转 78 | 79 | @param url url 80 | @return 是否可以跳转 81 | */ 82 | - (BOOL)hasRouter:(NSString *)url; 83 | 84 | /** 85 | 通过VC名称初始化VC 86 | 87 | @param viewController VC名称 88 | @return VC对象 89 | */ 90 | - (UIViewController *)controllerWithRouter:(NSString *)viewController; 91 | 92 | /** 93 | 通过VC名称初始化VC,并params映射将指定的属性赋值 94 | 95 | @param viewController VC名称 96 | @param params 属性映射 97 | @return VC对象 98 | */ 99 | - (UIViewController *)controllerWithRouter:(NSString *)viewController 100 | params:(NSDictionary *)params; 101 | 102 | 103 | #pragma mark - Push 104 | 105 | /** 106 | 通过VC名Push到指定的VC(默认显示push动画) 107 | 108 | @param viewController VC名称 109 | */ 110 | - (void)push:(NSString *)viewController; 111 | 112 | /** 113 | 通过VC名Push到指定的VC(是否显示push动画) 114 | 115 | @param viewController VC名称 116 | @param animated 是否显示动画 117 | */ 118 | - (void)push:(NSString *)viewController 119 | animated:(BOOL)animated; 120 | 121 | /** 122 | 通过VC名Push到指定的VC,并params映射将指定的属性赋值 123 | 124 | @param viewController VC名称 125 | @param animated 是否显示push动画 126 | @param params 属性映射 127 | */ 128 | - (void)push:(NSString *)viewController 129 | animated:(BOOL)animated 130 | params:(NSDictionary *)params; 131 | 132 | 133 | /** 134 | 通过VC名Push到指定的VC,并params映射将指定的属性赋值 135 | 136 | @param viewController VC名称 137 | @param animated 是否显示push动画 138 | @param params 属性映射 139 | @param completion 完成回调 140 | */ 141 | - (void)push:(NSString *)viewController 142 | animated:(BOOL)animated 143 | params:(NSDictionary *)params 144 | completion:(void(^)(void))completion; 145 | 146 | #pragma mark - Present 147 | 148 | /** 149 | 通过VC名Present到指定的VC(默认显示Present动画) 150 | 151 | @param viewController VC名称 152 | */ 153 | - (void)present:(NSString *)viewController; 154 | 155 | /** 156 | 通过VC名Present到指定的VC(是否显示Present动画) 157 | 158 | @param viewController VC名称 159 | @param animated 是否显示Present动画 160 | */ 161 | - (void)present:(NSString *)viewController 162 | animated:(BOOL)animated; 163 | 164 | /** 165 | 通过VC名Present指定的VC,并params映射将指定的属性赋值 166 | 167 | @param viewController VC名称 168 | @param animated 是否显示Present动画 169 | @param params 属性映射 170 | */ 171 | - (void)present:(NSString *)viewController 172 | animated:(BOOL)animated 173 | params:(NSDictionary *)params; 174 | 175 | 176 | /** 177 | 通过VC名Present指定的VC,并params映射将指定的属性赋值 178 | 179 | @param viewController VC名称 180 | @param animated 是否显示Present动画 181 | @param params 属性映射 182 | @param completion 完成回调 183 | */ 184 | - (void)present:(NSString *)viewController 185 | animated:(BOOL)animated 186 | params:(NSDictionary *)params 187 | completion:(void(^)(void))completion; 188 | 189 | #pragma mark - Pop 190 | 191 | /** 192 | Pop到上级VC(默认显示Pop动画) 193 | */ 194 | - (void)pop; 195 | 196 | /** 197 | Pop到上级VC(是否显示Pop动画) 198 | 199 | @param animated 是否显示Pop动画 200 | */ 201 | - (void)pop:(BOOL)animated; 202 | 203 | /** 204 | Pop到根控制器(默认显示Pop动画) 205 | */ 206 | - (void)popToRoot; 207 | 208 | /** 209 | Pop到根控制器(是否显示Pop动画) 210 | 211 | @param animated 是否显示Pop动画 212 | */ 213 | - (void)popToRoot:(BOOL)animated; 214 | 215 | /** 216 | Pop到根控制器(是否显示Pop动画) 217 | 218 | @param animated 是否显示Pop动画 219 | @param completion 完成回调 220 | */ 221 | - (void)popToRoot:(BOOL)animated 222 | completion:(void(^)(void))completion; 223 | 224 | /** 225 | 通过VC名Pop到指定的VC(默认显示Pop动画) 226 | 227 | @param viewController VC名称 228 | */ 229 | - (void)popTo:(NSString *)viewController; 230 | 231 | /** 232 | 通过VC名Pop到指定的VC(是否显示Pop动画) 233 | 234 | @param viewController VC名称 235 | @param animated 是否显示Pop动画 236 | */ 237 | - (void)popTo:(NSString *)viewController 238 | animated:(BOOL)animated; 239 | 240 | /** 241 | 通过VC名Pop到指定的VC(是否显示Pop动画) 242 | 243 | @param viewController VC名称 244 | @param animated 是否显示Pop动画 245 | @param completion 完成回调 246 | */ 247 | - (void)popTo:(NSString *)viewController 248 | animated:(BOOL)animated 249 | completion:(void(^)(void))completion; 250 | 251 | #pragma mark - Dismiss 252 | 253 | /** 254 | dismiss(默认显示Dismiss动画) 255 | */ 256 | - (void)dismiss; 257 | /** 258 | dismiss(是否显示Dismiss动画) 259 | 260 | @param animated 是否显示Dismiss动画 261 | */ 262 | - (void)dismiss:(BOOL)animated; 263 | 264 | /** 265 | dismiss(是否显示Dismiss动画) 266 | 267 | @param animated 是否显示Dismiss动画 268 | @param completion 完成回调 269 | */ 270 | - (void)dismiss:(BOOL)animated 271 | completion:(void(^)(void))completion; 272 | 273 | @end 274 | 275 | 276 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/JYRouter/JYRouter.m: -------------------------------------------------------------------------------- 1 | // 2 | // JYRouter.h 3 | // Job-Yang 4 | // 5 | // Created by 杨权 on 16/9/22. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import "JYRouter.h" 10 | #import 11 | #import 12 | 13 | @implementation NSObject (JYParams) 14 | 15 | - (void)modelWithDictionary:(NSDictionary *)dic { 16 | if (!dic) {return;} 17 | for (NSString *keyName in [dic allKeys]) { 18 | NSString *setterMethodName = [NSString stringWithFormat:@"set%@:",[self firstUpperString:keyName]]; 19 | SEL propertySelector = NSSelectorFromString(setterMethodName); 20 | 21 | if ([self respondsToSelector:propertySelector]) { 22 | id value = [dic objectForKey:keyName]; 23 | unsigned int count; 24 | Class class = [self class]; 25 | do { 26 | objc_property_t *properties = class_copyPropertyList(class, &count); 27 | for (NSInteger i = 0; i < count; i++) { 28 | objc_property_t property = properties[i]; 29 | const char *name = property_getName(property); 30 | NSString *proName = [[NSString alloc] initWithUTF8String:name]; 31 | if ([proName isEqualToString:keyName]) { 32 | const char *attributes = property_getAttributes(property); 33 | char *type = [self typeOfPropertyFromAttributes:attributes]; 34 | if (1 == strlen(type)) { 35 | [self encodeType:type[0] ofPropertySelector:propertySelector value:value]; 36 | } 37 | else { 38 | [self encodeStructureType:type ofPropertySelector:propertySelector value:value]; 39 | } 40 | break; 41 | } 42 | } 43 | class = [class superclass]; 44 | } while (class != [NSObject class]); 45 | } 46 | } 47 | } 48 | 49 | - (NSString *)firstUpperString:(NSString *)str { 50 | if (str && str.length > 0) { 51 | NSString *firstChar = [str substringToIndex:1]; 52 | NSString *result = [[firstChar uppercaseString] stringByAppendingString:[str substringFromIndex:1]]; 53 | return result; 54 | } 55 | return @""; 56 | } 57 | 58 | - (char *)typeOfPropertyFromAttributes:(const char *)attributes { 59 | if (!attributes || strlen(attributes) <= 1) { 60 | return 0x00; 61 | } 62 | char *result = NULL; 63 | if (!(attributes[1] == '{')){ 64 | result = malloc(sizeof(char) * 2); 65 | memset(result, 0, 2); 66 | strncpy(result, attributes + 1, 1); 67 | return result; 68 | } 69 | char *start = strstr(attributes, "{"); 70 | char *end = start; 71 | while (true) { 72 | char *tmp = strstr(end + 1, "}"); 73 | if (!tmp) break; 74 | end = tmp; 75 | } 76 | NSInteger len = end - start + 1; 77 | result = malloc(sizeof(char) * (len + 1)); 78 | memset(result, 0, len + 1); 79 | strncpy(result, start, len); 80 | return result; 81 | } 82 | 83 | - (void)encodeType:(char)type ofPropertySelector:(SEL)selector value:(id)value { 84 | if (!type) return; 85 | switch (type) { 86 | case 'B': { 87 | BOOL boolValue = [(NSNumber *)value boolValue]; 88 | ((void (*)(id, SEL, BOOL))(void *) objc_msgSend)((id)self, selector, boolValue); 89 | break; 90 | }; 91 | case 'c': { 92 | char charValue = [(NSNumber *)value charValue]; 93 | ((void (*)(id, SEL, char))(void *) objc_msgSend)((id)self, selector, charValue); 94 | break; 95 | } 96 | case 's': { 97 | short shortValue = [(NSNumber *)value shortValue]; 98 | ((void (*)(id, SEL, short))(void *) objc_msgSend)((id)self, selector, shortValue); 99 | break; 100 | } 101 | case 'i': { 102 | int intValue = [(NSNumber *)value intValue]; 103 | ((void (*)(id, SEL, int))(void *) objc_msgSend)((id)self, selector, intValue); 104 | break; 105 | } 106 | case 'C': { 107 | unsigned char unsignedCharValue = [(NSNumber *)value unsignedCharValue]; 108 | ((void (*)(id, SEL, unsigned char))(void *) objc_msgSend)((id)self, selector, unsignedCharValue); 109 | break; 110 | } 111 | case 'S': { 112 | unsigned short unsignedShortValue = [(NSNumber *)value unsignedShortValue]; 113 | ((void (*)(id, SEL, unsigned short))(void *) objc_msgSend)((id)self, selector, unsignedShortValue); 114 | break; 115 | } 116 | case 'I': { 117 | unsigned int unsignedIntValue = [(NSNumber *)value unsignedIntValue]; 118 | ((void (*)(id, SEL, unsigned int))(void *) objc_msgSend)((id)self, selector, unsignedIntValue); 119 | break; 120 | } 121 | case 'l': { 122 | long longValue = [(NSNumber *)value longValue]; 123 | ((void (*)(id, SEL, long))(void *) objc_msgSend)((id)self, selector, longValue); 124 | break; 125 | } 126 | case 'L': { 127 | unsigned long unsignedLongValue = [(NSNumber *)value unsignedLongValue]; 128 | ((void (*)(id, SEL, unsigned long))(void *) objc_msgSend)((id)self, selector, unsignedLongValue); 129 | break; 130 | } 131 | case 'q': { 132 | long long longLongValue = [(NSNumber *)value longLongValue]; 133 | ((void (*)(id, SEL, long long))(void *) objc_msgSend)((id)self, selector, longLongValue); 134 | break; 135 | } 136 | case 'Q': { 137 | unsigned long long unsignedLongLongValue = [(NSNumber *)value unsignedLongLongValue]; 138 | ((void (*)(id, SEL, unsigned long long))(void *) objc_msgSend)((id)self, selector, unsignedLongLongValue); 139 | break; 140 | } 141 | case 'f': { 142 | float floatValue = [(NSNumber *)value floatValue]; 143 | ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)self, selector, floatValue); 144 | break; 145 | } 146 | case 'd': { 147 | double doubleValue = [(NSNumber *)value doubleValue]; 148 | ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)self, selector, doubleValue); 149 | break; 150 | } 151 | default: { 152 | ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, selector, value); 153 | break; 154 | } 155 | } 156 | } 157 | 158 | - (void)encodeStructureType:(char *)type ofPropertySelector:(SEL)selector value:(id)value { 159 | if (!strcmp(type, @encode(CGPoint))) { 160 | CGPoint pointValue = [(NSValue *)value CGPointValue]; 161 | ((void (*)(id, SEL, CGPoint))(void *) objc_msgSend)((id)self, selector, pointValue); 162 | } 163 | else if (!strcmp(type, @encode(CGSize))) { 164 | CGSize sizeValue = [(NSValue *)value CGSizeValue]; 165 | ((void (*)(id, SEL, CGSize))(void *) objc_msgSend)((id)self, selector, sizeValue); 166 | } 167 | else if (!strcmp(type, @encode(CGRect))){ 168 | CGRect rectValue = [(NSValue *)value CGRectValue]; 169 | ((void (*)(id, SEL, CGRect))(void *) objc_msgSend)((id)self, selector, rectValue); 170 | } 171 | else if (!strcmp(type, @encode(CGAffineTransform))){ 172 | CGAffineTransform affineValue = [(NSValue*)value CGAffineTransformValue]; 173 | ((void (*)(id, SEL, CGAffineTransform))(void *) objc_msgSend)((id)self, selector, affineValue); 174 | } 175 | else if (!strcmp(type, @encode(UIEdgeInsets))){ 176 | UIEdgeInsets edgeInsetsValue = [(NSValue*)value UIEdgeInsetsValue]; 177 | ((void (*)(id, SEL, UIEdgeInsets))(void *) objc_msgSend)((id)self, selector, edgeInsetsValue); 178 | } 179 | else if (!strcmp(type, @encode(UIOffset))){ 180 | UIOffset offset = [(NSValue*)value UIOffsetValue]; 181 | ((void (*)(id, SEL, UIOffset))(void *) objc_msgSend)((id)self, selector, offset); 182 | } 183 | else { 184 | ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, selector, value); 185 | } 186 | } 187 | 188 | @end 189 | 190 | 191 | @implementation UINavigationController (JYCallBack) 192 | - (void)pushViewController:(UIViewController *)viewController 193 | animated:(BOOL)animated 194 | completion:(void(^)(void))completion { 195 | [CATransaction begin]; 196 | [CATransaction setCompletionBlock:completion]; 197 | [self pushViewController:viewController animated:animated]; 198 | [CATransaction commit]; 199 | } 200 | 201 | - (void)popToRootViewController:(BOOL)animated 202 | completion:(void(^)(void))completion { 203 | [CATransaction begin]; 204 | [CATransaction setCompletionBlock:completion]; 205 | [self popToRootViewControllerAnimated:animated]; 206 | [CATransaction commit]; 207 | } 208 | 209 | - (void)popToViewController:(UIViewController *)viewController 210 | animated:(BOOL)animated 211 | completion:(void(^)(void))completion { 212 | [CATransaction begin]; 213 | [CATransaction setCompletionBlock:completion]; 214 | [self popToViewController:viewController animated:animated]; 215 | [CATransaction commit]; 216 | } 217 | 218 | @end 219 | 220 | 221 | @interface JYRouterOptions() 222 | @property (nonatomic, assign) BOOL isModal; 223 | @property (nonatomic, assign) UIModalPresentationStyle presentationStyle; 224 | @property (nonatomic, assign) UIModalTransitionStyle transitionStyle; 225 | @property (nonatomic, strong) NSDictionary *defaultParams; 226 | @property (nonatomic, strong) Class openClass; 227 | @property (nonatomic, copy ) JYRouterOpenCallback callback; 228 | @end 229 | 230 | @implementation JYRouterOptions 231 | + (instancetype)routerOptionsWithModal:(BOOL)isModal { 232 | JYRouterOptions *options = [[JYRouterOptions alloc] init]; 233 | options.presentationStyle = UIModalPresentationNone; 234 | options.transitionStyle = UIModalTransitionStyleCoverVertical; 235 | options.isModal = isModal; 236 | return options; 237 | } 238 | 239 | + (instancetype)routerOptions { 240 | return [self routerOptionsWithModal:NO]; 241 | } 242 | 243 | + (instancetype)routerOptionsAsModal { 244 | return [self routerOptionsWithModal:YES]; 245 | } 246 | 247 | - (JYRouterOptions *)withPresentationStyle:(UIModalPresentationStyle)style { 248 | [self setPresentationStyle:style]; 249 | return self; 250 | } 251 | 252 | @end 253 | 254 | @interface JYRouterParams() 255 | @property (nonatomic, strong) JYRouterOptions *routerOptions; 256 | @property (nonatomic, strong) NSDictionary *openParams; 257 | @property (nonatomic, strong) NSDictionary *extraParams; 258 | @property (nonatomic, strong) NSDictionary *controllerParams; 259 | @end 260 | 261 | @implementation JYRouterParams 262 | - (instancetype)initWithRouterOptions:(JYRouterOptions *)routerOptions 263 | openParams:(NSDictionary *)openParams 264 | extraParams:(NSDictionary *)extraParams { 265 | [self setRouterOptions:routerOptions]; 266 | [self setExtraParams:extraParams]; 267 | [self setOpenParams:openParams]; 268 | return self; 269 | } 270 | 271 | @end 272 | 273 | 274 | #define ROUTE_NOT_FOUND_FORMAT @"No route found for URL %@" 275 | #define INVALID_CONTROLLER_FORMAT @"Your controller class %@ needs to implement either the static method %@ or the instance method %@" 276 | 277 | @interface JYRouter() 278 | @property (nonatomic, strong) UINavigationController *navigationController; 279 | @property (nonatomic, strong) NSMutableDictionary *routes; 280 | @property (nonatomic, strong) NSMutableDictionary *cachedRoutes; 281 | @property (nonatomic, strong) Class navClass; 282 | @end 283 | 284 | @implementation JYRouter 285 | 286 | + (instancetype)router { 287 | static JYRouter *_sharedRouter = nil; 288 | static dispatch_once_t onceToken; 289 | dispatch_once(&onceToken, ^{ 290 | _sharedRouter = [[JYRouter alloc] init]; 291 | }); 292 | return _sharedRouter; 293 | } 294 | 295 | + (instancetype)newRouter { 296 | return [[self alloc] init]; 297 | } 298 | 299 | - (instancetype)init { 300 | if (self = [super init]) { 301 | self.routes = [NSMutableDictionary dictionary]; 302 | self.cachedRoutes = [NSMutableDictionary dictionary]; 303 | } 304 | return self; 305 | } 306 | 307 | + (UIViewController *)currentVC { 308 | UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; 309 | while (topController.presentedViewController) { 310 | topController = topController.presentedViewController; 311 | } 312 | return topController; 313 | } 314 | 315 | - (void)setCustomNavigationClass:(Class)navClass { 316 | if (![navClass isSubclassOfClass:[UINavigationController class]]) { 317 | @throw [NSException exceptionWithName:@"NavClassTypeError" 318 | reason:@"navClass must be UINavigationController class or Subclass of UINavigationController" 319 | userInfo:nil]; 320 | } 321 | self.navClass = navClass; 322 | } 323 | 324 | - (BOOL)hasRouter:(NSString *)url { 325 | return [self.routes.allKeys containsObject:url]; 326 | } 327 | 328 | - (UIViewController *)controllerWithRouter:(NSString *)viewController { 329 | return [self controllerWithRouter:viewController 330 | params:nil]; 331 | } 332 | 333 | - (UIViewController *)controllerWithRouter:(NSString *)viewController 334 | params:(NSDictionary *)params { 335 | 336 | JYRouterOptions *options = [JYRouterOptions routerOptions]; 337 | 338 | if (![self hasRouter:viewController]) { 339 | [self map:viewController toController:[self classFromString:viewController] withOptions:options]; 340 | } 341 | JYRouterParams *extraParams = [self routerParamsForUrl:viewController extraParams:params]; 342 | 343 | options.openClass = [self classFromString:viewController]; 344 | extraParams.routerOptions = options; 345 | 346 | UIViewController *controller = [self controllerForRouterParams:extraParams]; 347 | [controller modelWithDictionary:params]; 348 | 349 | return controller; 350 | } 351 | 352 | - (void)push:(NSString *)viewController { 353 | [self push:viewController animated:YES]; 354 | } 355 | 356 | - (void)push:(NSString *)viewController animated:(BOOL)animated { 357 | [self push:viewController animated:animated params:nil]; 358 | } 359 | 360 | - (void)push:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params { 361 | [self push:viewController animated:animated params:params completion:nil]; 362 | } 363 | 364 | - (void)push:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 365 | [self open:viewController withOptions:nil animated:animated params:params completion:completion]; 366 | } 367 | 368 | - (void)present:(NSString *)viewController { 369 | [self present:viewController animated:YES]; 370 | } 371 | 372 | - (void)present:(NSString *)viewController animated:(BOOL)animated { 373 | [self present:viewController animated:animated params:nil]; 374 | } 375 | 376 | - (void)present:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params { 377 | [self present:viewController animated:animated params:params completion:nil]; 378 | } 379 | 380 | - (void)present:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 381 | [self open:viewController withOptions:[[JYRouterOptions routerOptionsAsModal] withPresentationStyle:UIModalPresentationFormSheet] animated:animated params:params completion:completion]; 382 | } 383 | 384 | - (void)present:(NSString *)viewController withOptions:(JYRouterOptions *)options animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 385 | [self open:viewController withOptions:options animated:animated params:params completion:completion]; 386 | } 387 | 388 | - (void)pop { 389 | [self popViewControllerFromRouterAnimated:YES]; 390 | } 391 | 392 | - (void)pop:(BOOL)animated { 393 | [self popViewControllerFromRouterAnimated:animated]; 394 | } 395 | 396 | - (void)popToRoot { 397 | [self popToRoot:YES]; 398 | } 399 | 400 | - (void)popToRoot:(BOOL)animated { 401 | [self popToRoot:animated completion:nil]; 402 | } 403 | 404 | - (void)popToRoot:(BOOL)animated completion:(void(^)(void))completion { 405 | [self.navigationController popToRootViewController:animated completion:completion]; 406 | } 407 | 408 | - (void)popTo:(NSString *)viewController { 409 | [self popTo:viewController animated:YES]; 410 | } 411 | 412 | - (void)popTo:(NSString *)viewController animated:(BOOL)animated { 413 | [self popTo:viewController animated:YES completion:nil]; 414 | } 415 | 416 | - (void)popTo:(NSString *)viewController animated:(BOOL)animated completion:(void(^)(void))completion { 417 | for (UIViewController *tempVC in self.navigationController.viewControllers) { 418 | if ([NSStringFromClass([tempVC class]) isEqualToString:viewController]) { 419 | [self.navigationController popToViewController:tempVC animated:animated completion:completion]; 420 | break; 421 | } 422 | } 423 | } 424 | 425 | - (void)dismiss { 426 | [self dismiss:YES]; 427 | } 428 | 429 | - (void)dismiss:(BOOL)animated { 430 | [self dismiss:animated completion:nil]; 431 | } 432 | 433 | - (void)dismiss:(BOOL)animated completion:(void(^)(void))completion { 434 | [self.navigationController dismissViewControllerAnimated:animated completion:completion]; 435 | } 436 | 437 | - (void)open:(NSString *)url withOptions:(JYRouterOptions *)options animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 438 | 439 | if (![self hasRouter:url]) { 440 | [self map:url toController:[self classFromString:url] withOptions:options]; 441 | } 442 | 443 | JYRouterParams *extraParams = [self routerParamsForUrl:url extraParams:params]; 444 | if (!options) { 445 | options = [JYRouterOptions routerOptions]; 446 | } 447 | options.openClass = [self classFromString:url]; 448 | extraParams.routerOptions = options; 449 | 450 | if (options.callback) { 451 | JYRouterOpenCallback callback = options.callback; 452 | callback([extraParams controllerParams]); 453 | return; 454 | } 455 | 456 | if (!self.navigationController) { 457 | @throw [NSException exceptionWithName:@"NavigationControllerNotProvided" 458 | reason:@"Router#navigationController has not been set to a UINavigationController instance" 459 | userInfo:nil]; 460 | } 461 | 462 | UIViewController *controller = [self controllerForRouterParams:extraParams]; 463 | [controller modelWithDictionary:params]; 464 | 465 | 466 | if ([options isModal]) { 467 | if ([controller.class isSubclassOfClass:UINavigationController.class]) { 468 | [self.navigationController presentViewController:controller 469 | animated:animated 470 | completion:completion]; 471 | } 472 | else { 473 | if (!self.navClass) { 474 | self.navClass = [UINavigationController class]; 475 | } 476 | UINavigationController *navigationController = [[self.navClass alloc] initWithRootViewController:controller]; 477 | navigationController.modalPresentationStyle = controller.modalPresentationStyle; 478 | navigationController.modalTransitionStyle = controller.modalTransitionStyle; 479 | 480 | [self.navigationController presentViewController:navigationController 481 | animated:animated 482 | completion:completion]; 483 | } 484 | } 485 | else { 486 | [self.navigationController pushViewController:controller animated:animated completion:completion]; 487 | } 488 | } 489 | 490 | - (Class)classFromString:(NSString *)className { 491 | Class class = NSClassFromString(className); 492 | if (!class) { 493 | class = [self swiftClassFromString:className]; 494 | } 495 | // NSLog(@"class = %@",class); 496 | return class; 497 | } 498 | 499 | - (Class)swiftClassFromString:(NSString *)className { 500 | NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"]; 501 | appName = [appName stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; 502 | NSString *classStringName = [NSString stringWithFormat:@"%@.%@", appName, className]; 503 | return NSClassFromString(classStringName); 504 | } 505 | 506 | - (UINavigationController *)navigationController { 507 | return [self navigationControllerWithController:[UIApplication sharedApplication].delegate.window.rootViewController]; 508 | } 509 | 510 | - (UINavigationController *)navigationControllerWithController:(UIViewController *)viewController { 511 | if (viewController.presentedViewController) { 512 | return [self navigationControllerWithController:viewController.presentedViewController]; 513 | } 514 | else if ([viewController isKindOfClass:[UITabBarController class]]) { 515 | UITabBarController *vc = (UITabBarController *)viewController; 516 | return vc.selectedViewController; 517 | } 518 | else { 519 | return (UINavigationController *)viewController; 520 | } 521 | } 522 | 523 | - (void)map:(NSString *)format toController:(Class)controllerClass withOptions:(JYRouterOptions *)options { 524 | if (!format) { 525 | @throw [NSException exceptionWithName:@"RouteNotProvided" 526 | reason:@"Route #format is not initialized" 527 | userInfo:nil]; 528 | return; 529 | } 530 | if (!options) { 531 | options = [JYRouterOptions routerOptions]; 532 | } 533 | options.openClass = controllerClass; 534 | [self.routes setObject:options forKey:format]; 535 | } 536 | 537 | 538 | - (void)popViewControllerFromRouterAnimated:(BOOL)animated { 539 | if (self.navigationController.presentedViewController) { 540 | [self.navigationController dismissViewControllerAnimated:animated completion:nil]; 541 | } 542 | else { 543 | [self.navigationController popViewControllerAnimated:animated]; 544 | } 545 | } 546 | 547 | 548 | - (JYRouterParams *)routerParamsForUrl:(NSString *)url extraParams: (NSDictionary *)extraParams { 549 | if (!url) { 550 | if (_ignoresExceptions) { 551 | return nil; 552 | } 553 | @throw [NSException exceptionWithName:@"RouteNotFoundException" 554 | reason:[NSString stringWithFormat:ROUTE_NOT_FOUND_FORMAT, url] 555 | userInfo:nil]; 556 | } 557 | 558 | if ([self.cachedRoutes objectForKey:url] && !extraParams) { 559 | return [self.cachedRoutes objectForKey:url]; 560 | } 561 | 562 | NSArray *givenParts = url.pathComponents; 563 | NSArray *legacyParts = [url componentsSeparatedByString:@"/"]; 564 | if ([legacyParts count] != [givenParts count]) { 565 | NSLog(@"Routable Warning - your URL %@ has empty path components - this will throw an error in an upcoming release", url); 566 | givenParts = legacyParts; 567 | } 568 | 569 | __block JYRouterParams *openParams = nil; 570 | [self.routes enumerateKeysAndObjectsUsingBlock: 571 | ^(NSString *routerUrl, JYRouterOptions *routerOptions, BOOL *stop) { 572 | 573 | NSArray *routerParts = [routerUrl pathComponents]; 574 | if ([routerParts count] == [givenParts count]) { 575 | 576 | NSDictionary *givenParams = [self paramsForUrlComponents:givenParts routerUrlComponents:routerParts]; 577 | if (givenParams) { 578 | openParams = [[JYRouterParams alloc] initWithRouterOptions:routerOptions 579 | openParams:givenParams 580 | extraParams:extraParams]; 581 | *stop = YES; 582 | } 583 | } 584 | }]; 585 | 586 | if (!openParams) { 587 | if (_ignoresExceptions) { 588 | return nil; 589 | } 590 | @throw [NSException exceptionWithName:@"RouteNotFoundException" 591 | reason:[NSString stringWithFormat:ROUTE_NOT_FOUND_FORMAT, url] 592 | userInfo:nil]; 593 | } 594 | [self.cachedRoutes setObject:openParams forKey:url]; 595 | return openParams; 596 | } 597 | 598 | - (NSDictionary *)paramsForUrlComponents:(NSArray *)givenUrlComponents 599 | routerUrlComponents:(NSArray *)routerUrlComponents { 600 | 601 | __block NSMutableDictionary *params = [NSMutableDictionary dictionary]; 602 | [routerUrlComponents enumerateObjectsUsingBlock: 603 | ^(NSString *routerComponent, NSUInteger idx, BOOL *stop) { 604 | 605 | NSString *givenComponent = givenUrlComponents[idx]; 606 | if ([routerComponent hasPrefix:@":"]) { 607 | NSString *key = [routerComponent substringFromIndex:1]; 608 | [params setObject:givenComponent forKey:key]; 609 | } 610 | else if (![routerComponent isEqualToString:givenComponent]) { 611 | params = nil; 612 | *stop = YES; 613 | } 614 | }]; 615 | return params; 616 | } 617 | 618 | - (UIViewController *)controllerForRouterParams:(JYRouterParams *)params { 619 | SEL CONTROLLER_CLASS_SELECTOR = sel_registerName("allocWithRouterParams:"); 620 | SEL CONTROLLER_SELECTOR = sel_registerName("initWithRouterParams:"); 621 | SEL CONTROLLER_INIT = sel_registerName("init"); 622 | UIViewController *controller = nil; 623 | Class controllerClass = params.routerOptions.openClass; 624 | #pragma clang diagnostic push 625 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 626 | if ([controllerClass respondsToSelector:CONTROLLER_CLASS_SELECTOR]) { 627 | controller = [controllerClass performSelector:CONTROLLER_CLASS_SELECTOR withObject:[params controllerParams]]; 628 | } 629 | else if ([params.routerOptions.openClass instancesRespondToSelector:CONTROLLER_SELECTOR]) { 630 | controller = [[params.routerOptions.openClass alloc] performSelector:CONTROLLER_SELECTOR withObject:[params controllerParams]]; 631 | } 632 | else { 633 | controller = [[params.routerOptions.openClass alloc] performSelector:CONTROLLER_INIT]; 634 | } 635 | #pragma clang diagnostic pop 636 | if (!controller) { 637 | if (_ignoresExceptions) { 638 | return controller; 639 | } 640 | @throw [NSException exceptionWithName:@"RoutableInitializerNotFound" 641 | reason:[NSString stringWithFormat:INVALID_CONTROLLER_FORMAT, NSStringFromClass(controllerClass), NSStringFromSelector(CONTROLLER_CLASS_SELECTOR), NSStringFromSelector(CONTROLLER_SELECTOR)] 642 | userInfo:nil]; 643 | } 644 | 645 | controller.modalTransitionStyle = params.routerOptions.transitionStyle; 646 | controller.modalPresentationStyle = params.routerOptions.presentationStyle; 647 | return controller; 648 | } 649 | 650 | 651 | @end 652 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/JYRouterDemo-Swift-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | 6 | #import "JYRouter.h" 7 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/JYViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JYViewController.swift 3 | // JYRouterDemoForSwift 4 | // 5 | // Created by 杨权 on 2017/1/3. 6 | // Copyright © 2017年 Job-Yang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let fullScreenSize = UIScreen.main.bounds.size 12 | let cellIdentifier:String = "cell" 13 | 14 | 15 | class JYViewController: UIViewController { 16 | 17 | // MARK: - 18 | var parameterString:String = "" 19 | var parameterNumber:NSNumber = 0 20 | var parameterDictionary:[AnyHashable: Any] = [:] 21 | var parameterBool:Bool = false 22 | var parameterSize:CGSize = CGSize(width: 0, height: 0) 23 | 24 | 25 | // MARK: - life cycle 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | setNavigation() 29 | showParameter() 30 | view.addSubview(tableView) 31 | print(String(describing:JYViewController.self)) 32 | } 33 | 34 | // MARK: - setup methods 35 | func setNavigation() { 36 | navigationItem.title = "JYRouter" 37 | let red = CGFloat(arc4random() % 255) 38 | let green = CGFloat(arc4random() % 255) 39 | let bule = CGFloat(arc4random() % 255) 40 | navigationController?.navigationBar.barTintColor = UIColor(red: red/255.0, green: green/255.0, blue: bule/255.0, alpha: 1) 41 | } 42 | 43 | func showParameter() { 44 | print("-----------------------------------------------") 45 | print("⭕️parameterString = \(parameterString)") 46 | print("⭕️parameterNumber = \(parameterNumber)") 47 | print("⭕️parameterBool = \(parameterBool)") 48 | print("⭕️parameterSize = \(parameterSize)") 49 | print("⭕️parameterDictionary = \(parameterDictionary)") 50 | print("-----------------------------------------------\n\n"); 51 | } 52 | 53 | // MARK: - event & response 54 | func routerAtIndexPath(indexPath: IndexPath) { 55 | 56 | let group = dataList[indexPath.section]["group"] as! String? 57 | let params = [ 58 | "parameterString" : "我是一个字符串-\(String(describing: group))", 59 | "parameterNumber" : 123456789, 60 | "parameterBool" : true, 61 | "parameterSize" : CGSize(width: 100, height: 200), 62 | "parameterDictionary" : [ 63 | "key1": "Value1-\(String(describing: group))", 64 | "key2": "Value2-\(String(describing: group))" 65 | ] 66 | ] as [String : Any] 67 | 68 | 69 | switch indexPath.section { 70 | case 0: break 71 | 72 | default: break 73 | 74 | } 75 | 76 | switch indexPath.section { 77 | // ---------------------- Push ---------------------- 78 | case 0: 79 | switch indexPath.row { 80 | /** 81 | Push跳转 82 | */ 83 | case 0: 84 | JYRouter().push("JYViewController") 85 | break 86 | /** 87 | Push跳转,附带参数 88 | */ 89 | case 1: 90 | JYRouter().push("JYViewController", animated: true, params: params) 91 | break 92 | /** 93 | Push跳转,附带参数,完成回调 94 | */ 95 | case 2: 96 | JYRouter().push("JYViewController", animated: true, params: params, completion: { 97 | print("🔥🔥🔥Push完成回调🔥🔥🔥") 98 | }) 99 | break 100 | default: break 101 | } 102 | break 103 | 104 | 105 | // ---------------------- Pop ---------------------- 106 | case 1: 107 | switch indexPath.row { 108 | /** 109 | Pop到上级 110 | */ 111 | case 0: 112 | JYRouter().pop() 113 | break 114 | /** 115 | Pop到根控制器 116 | */ 117 | case 1: 118 | JYRouter().popToRoot() 119 | break 120 | /** 121 | Pop到根控制器,完成回调 122 | */ 123 | case 2: 124 | JYRouter().pop(toRoot: true, completion: { 125 | print("💧💧💧Pop完成回调💧💧💧") 126 | }) 127 | break 128 | /** 129 | Pop到指定控制器 130 | */ 131 | case 3: 132 | JYRouter().pop(to: "JYViewController") 133 | break 134 | /** 135 | Pop到指定控制器,完成回调 136 | */ 137 | case 4: 138 | JYRouter().pop(to: "JYViewController", animated: true, completion: { 139 | print("💧💧💧Pop完成回调💧💧💧") 140 | }) 141 | break 142 | default: break 143 | } 144 | break 145 | 146 | // ---------------------- Present ---------------------- 147 | case 2: 148 | switch indexPath.row { 149 | /** 150 | present跳转 151 | */ 152 | case 0: 153 | JYRouter().present("JYViewController") 154 | break 155 | /** 156 | Present跳转,附带参数 157 | */ 158 | case 1: 159 | JYRouter().present("JYViewController", animated: true, params: params) 160 | break 161 | /** 162 | Present跳转,附带参数,完成回调 163 | */ 164 | case 2: 165 | JYRouter().present("JYViewController", animated: true, params: params, completion: { 166 | print("🌧🌧🌧Pop完成回调🌧🌧🌧") 167 | }) 168 | break 169 | default: break 170 | } 171 | break 172 | 173 | // ---------------------- Dismiss ---------------------- 174 | case 3: 175 | switch indexPath.row { 176 | /** 177 | Dismiss 178 | */ 179 | case 0: 180 | JYRouter().dismiss() 181 | break 182 | /** 183 | Dismiss,完成回调 184 | */ 185 | case 1: 186 | JYRouter().dismiss(true, completion: { 187 | print("⚡️⚡️⚡️Dismiss完成回调⚡️⚡️⚡️") 188 | }) 189 | break 190 | default: break 191 | } 192 | break; 193 | default: break; 194 | } 195 | } 196 | 197 | // MARK: - getter & setter 198 | lazy var dataList: [[String: AnyObject]] = { 199 | let path = Bundle.main.path(forResource: "dataList", ofType: "json") 200 | let data = NSData(contentsOfFile: path!) 201 | if let result = try? JSONSerialization.jsonObject(with: data! as Data, options: .allowFragments) as? [[String: AnyObject]] { 202 | return result! 203 | } 204 | return [] 205 | }() 206 | 207 | lazy var tableView: UITableView = { 208 | var tableView: UITableView 209 | tableView = UITableView(frame: CGRect(x: 0, y: 0, width: fullScreenSize.width, height: fullScreenSize.height-64), style: .plain) 210 | tableView.delegate = self 211 | tableView.dataSource = self 212 | return tableView 213 | }() 214 | } 215 | 216 | 217 | //MARK: - UITableViewDelegate AND UITableViewDataSource 218 | extension JYViewController: UITableViewDataSource, UITableViewDelegate { 219 | 220 | func numberOfSections(in tableView: UITableView) -> Int { 221 | return dataList.count 222 | } 223 | 224 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 225 | return ((dataList[section]["list"])?.count)! 226 | } 227 | 228 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 229 | return 44 230 | } 231 | 232 | func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 233 | return dataList[section]["group"] as! String? 234 | } 235 | 236 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 237 | let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellIdentifier) 238 | cell.textLabel?.text = (dataList[indexPath.section]["list"] as! NSArray)[indexPath.row] as? String 239 | return cell 240 | } 241 | 242 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 243 | routerAtIndexPath(indexPath: indexPath) 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /Demo/Swift/JYRouterDemo-Swift/dataList.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "group": "Push", 4 | "list": [ 5 | "push跳转", 6 | "push跳转,附带参数", 7 | "push跳转,附带参数,完成回调" 8 | ] 9 | }, 10 | { 11 | "group": "Pop", 12 | "list": [ 13 | "Pop到上级", 14 | "Pop到根控制器", 15 | "Pop到根控制器,完成回调", 16 | "Pop到指定控制器", 17 | "Pop到指定控制器,完成回调" 18 | ] 19 | }, 20 | { 21 | "group": "Present", 22 | "list": [ 23 | "Present跳转", 24 | "Present跳转,附带参数", 25 | "Present跳转,附带参数,完成回调" 26 | ] 27 | }, 28 | { 29 | "group": "Dismiss", 30 | "list": [ 31 | "Dismiss", 32 | "Dismiss,完成回调" 33 | ] 34 | } 35 | ] 36 | -------------------------------------------------------------------------------- /JYRouter.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'JYRouter' 3 | s.summary = 'Router framework is based on runtime to push/present/pop/dismiss for iOS' 4 | s.version = '2.1.4' 5 | s.license = { :type => 'MIT', :file => 'LICENSE' } 6 | s.author = { "Job-Yang" => "578093143@qq.com" } 7 | s.homepage = 'https://github.com/Job-Yang/JYRouter' 8 | s.platform = :ios, '8.0' 9 | s.ios.deployment_target = '8.0' 10 | s.source = { :git => 'https://github.com/Job-Yang/JYRouter.git', :tag => s.version} 11 | 12 | s.requires_arc = true 13 | s.source_files = 'JYRouter/**/*.{h,m}' 14 | 15 | end -------------------------------------------------------------------------------- /JYRouter/JYRouter.h: -------------------------------------------------------------------------------- 1 | // 2 | // JYRouter.h 3 | // Job-Yang 4 | // 5 | // Created by 杨权 on 16/9/22. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void (^JYRouterOpenCallback)(NSDictionary *params); 13 | 14 | /** 15 | 跳转时属性自动复制的工具分类 16 | */ 17 | @interface NSObject (JYParams) 18 | @end 19 | 20 | /** 21 | 跳转时回调的分类 22 | */ 23 | @interface UINavigationController (JYCallBack) 24 | @end 25 | 26 | /** 27 | 跳转选项相关类 28 | */ 29 | @interface JYRouterOptions : NSObject 30 | @end 31 | 32 | /** 33 | 跳转参数相关类 34 | */ 35 | @interface JYRouterParams : NSObject 36 | @end 37 | 38 | 39 | @interface JYRouter : NSObject 40 | 41 | /** 42 | 是否忽略异常 43 | */ 44 | @property (nonatomic, assign) BOOL ignoresExceptions; 45 | 46 | /** 47 | 单例 48 | 49 | @return JYRouter单例对象 50 | */ 51 | + (instancetype)router; 52 | 53 | /** 54 | 获取一个新的Router对象 55 | 56 | @return JYRouter对象 57 | */ 58 | + (instancetype)newRouter; 59 | 60 | /** 61 | 获取当前显示的VC 62 | 63 | @return 当前显示的VC 64 | */ 65 | + (UIViewController *)currentVC; 66 | 67 | /** 68 | 设置自定义的Navigation,用于present时显示 69 | 如果您想全局设置,请在AppDelegate 的didFinishLaunchingWithOptions方法中设置 70 | [[JYRouter router] setCustomNavigationClass:[YourCustomNavigation class]]; 71 | 72 | @param navClass Navigation Class 73 | */ 74 | - (void)setCustomNavigationClass:(Class)navClass; 75 | 76 | /** 77 | 判断该URL是否可以路由跳转 78 | 79 | @param url url 80 | @return 是否可以跳转 81 | */ 82 | - (BOOL)hasRouter:(NSString *)url; 83 | 84 | /** 85 | 通过VC名称初始化VC 86 | 87 | @param viewController VC名称 88 | @return VC对象 89 | */ 90 | - (UIViewController *)controllerWithRouter:(NSString *)viewController; 91 | 92 | /** 93 | 通过VC名称初始化VC,并params映射将指定的属性赋值 94 | 95 | @param viewController VC名称 96 | @param params 属性映射 97 | @return VC对象 98 | */ 99 | - (UIViewController *)controllerWithRouter:(NSString *)viewController 100 | params:(NSDictionary *)params; 101 | 102 | 103 | #pragma mark - Push 104 | 105 | /** 106 | 通过VC名Push到指定的VC(默认显示push动画) 107 | 108 | @param viewController VC名称 109 | */ 110 | - (void)push:(NSString *)viewController; 111 | 112 | /** 113 | 通过VC名Push到指定的VC(是否显示push动画) 114 | 115 | @param viewController VC名称 116 | @param animated 是否显示动画 117 | */ 118 | - (void)push:(NSString *)viewController 119 | animated:(BOOL)animated; 120 | 121 | /** 122 | 通过VC名Push到指定的VC,并params映射将指定的属性赋值 123 | 124 | @param viewController VC名称 125 | @param animated 是否显示push动画 126 | @param params 属性映射 127 | */ 128 | - (void)push:(NSString *)viewController 129 | animated:(BOOL)animated 130 | params:(NSDictionary *)params; 131 | 132 | 133 | /** 134 | 通过VC名Push到指定的VC,并params映射将指定的属性赋值 135 | 136 | @param viewController VC名称 137 | @param animated 是否显示push动画 138 | @param params 属性映射 139 | @param completion 完成回调 140 | */ 141 | - (void)push:(NSString *)viewController 142 | animated:(BOOL)animated 143 | params:(NSDictionary *)params 144 | completion:(void(^)(void))completion; 145 | 146 | #pragma mark - Present 147 | 148 | /** 149 | 通过VC名Present到指定的VC(默认显示Present动画) 150 | 151 | @param viewController VC名称 152 | */ 153 | - (void)present:(NSString *)viewController; 154 | 155 | /** 156 | 通过VC名Present到指定的VC(是否显示Present动画) 157 | 158 | @param viewController VC名称 159 | @param animated 是否显示Present动画 160 | */ 161 | - (void)present:(NSString *)viewController 162 | animated:(BOOL)animated; 163 | 164 | /** 165 | 通过VC名Present指定的VC,并params映射将指定的属性赋值 166 | 167 | @param viewController VC名称 168 | @param animated 是否显示Present动画 169 | @param params 属性映射 170 | */ 171 | - (void)present:(NSString *)viewController 172 | animated:(BOOL)animated 173 | params:(NSDictionary *)params; 174 | 175 | 176 | /** 177 | 通过VC名Present指定的VC,并params映射将指定的属性赋值 178 | 179 | @param viewController VC名称 180 | @param animated 是否显示Present动画 181 | @param params 属性映射 182 | @param completion 完成回调 183 | */ 184 | - (void)present:(NSString *)viewController 185 | animated:(BOOL)animated 186 | params:(NSDictionary *)params 187 | completion:(void(^)(void))completion; 188 | 189 | #pragma mark - Pop 190 | 191 | /** 192 | Pop到上级VC(默认显示Pop动画) 193 | */ 194 | - (void)pop; 195 | 196 | /** 197 | Pop到上级VC(是否显示Pop动画) 198 | 199 | @param animated 是否显示Pop动画 200 | */ 201 | - (void)pop:(BOOL)animated; 202 | 203 | /** 204 | Pop到根控制器(默认显示Pop动画) 205 | */ 206 | - (void)popToRoot; 207 | 208 | /** 209 | Pop到根控制器(是否显示Pop动画) 210 | 211 | @param animated 是否显示Pop动画 212 | */ 213 | - (void)popToRoot:(BOOL)animated; 214 | 215 | /** 216 | Pop到根控制器(是否显示Pop动画) 217 | 218 | @param animated 是否显示Pop动画 219 | @param completion 完成回调 220 | */ 221 | - (void)popToRoot:(BOOL)animated 222 | completion:(void(^)(void))completion; 223 | 224 | /** 225 | 通过VC名Pop到指定的VC(默认显示Pop动画) 226 | 227 | @param viewController VC名称 228 | */ 229 | - (void)popTo:(NSString *)viewController; 230 | 231 | /** 232 | 通过VC名Pop到指定的VC(是否显示Pop动画) 233 | 234 | @param viewController VC名称 235 | @param animated 是否显示Pop动画 236 | */ 237 | - (void)popTo:(NSString *)viewController 238 | animated:(BOOL)animated; 239 | 240 | /** 241 | 通过VC名Pop到指定的VC(是否显示Pop动画) 242 | 243 | @param viewController VC名称 244 | @param animated 是否显示Pop动画 245 | @param completion 完成回调 246 | */ 247 | - (void)popTo:(NSString *)viewController 248 | animated:(BOOL)animated 249 | completion:(void(^)(void))completion; 250 | 251 | #pragma mark - Dismiss 252 | 253 | /** 254 | dismiss(默认显示Dismiss动画) 255 | */ 256 | - (void)dismiss; 257 | /** 258 | dismiss(是否显示Dismiss动画) 259 | 260 | @param animated 是否显示Dismiss动画 261 | */ 262 | - (void)dismiss:(BOOL)animated; 263 | 264 | /** 265 | dismiss(是否显示Dismiss动画) 266 | 267 | @param animated 是否显示Dismiss动画 268 | @param completion 完成回调 269 | */ 270 | - (void)dismiss:(BOOL)animated 271 | completion:(void(^)(void))completion; 272 | 273 | @end 274 | 275 | 276 | -------------------------------------------------------------------------------- /JYRouter/JYRouter.m: -------------------------------------------------------------------------------- 1 | // 2 | // JYRouter.h 3 | // Job-Yang 4 | // 5 | // Created by 杨权 on 16/9/22. 6 | // Copyright © 2016年 Job-Yang. All rights reserved. 7 | // 8 | 9 | #import "JYRouter.h" 10 | #import 11 | #import 12 | 13 | @implementation NSObject (JYParams) 14 | 15 | - (void)modelWithDictionary:(NSDictionary *)dic { 16 | if (!dic) {return;} 17 | for (NSString *keyName in [dic allKeys]) { 18 | NSString *setterMethodName = [NSString stringWithFormat:@"set%@:",[self firstUpperString:keyName]]; 19 | SEL propertySelector = NSSelectorFromString(setterMethodName); 20 | 21 | if ([self respondsToSelector:propertySelector]) { 22 | id value = [dic objectForKey:keyName]; 23 | unsigned int count; 24 | Class class = [self class]; 25 | do { 26 | objc_property_t *properties = class_copyPropertyList(class, &count); 27 | for (NSInteger i = 0; i < count; i++) { 28 | objc_property_t property = properties[i]; 29 | const char *name = property_getName(property); 30 | NSString *proName = [[NSString alloc] initWithUTF8String:name]; 31 | if ([proName isEqualToString:keyName]) { 32 | const char *attributes = property_getAttributes(property); 33 | char *type = [self typeOfPropertyFromAttributes:attributes]; 34 | if (1 == strlen(type)) { 35 | [self encodeType:type[0] ofPropertySelector:propertySelector value:value]; 36 | } 37 | else { 38 | [self encodeStructureType:type ofPropertySelector:propertySelector value:value]; 39 | } 40 | break; 41 | } 42 | } 43 | class = [class superclass]; 44 | } while (class != [NSObject class]); 45 | } 46 | } 47 | } 48 | 49 | - (NSString *)firstUpperString:(NSString *)str { 50 | if (str && str.length > 0) { 51 | NSString *firstChar = [str substringToIndex:1]; 52 | NSString *result = [[firstChar uppercaseString] stringByAppendingString:[str substringFromIndex:1]]; 53 | return result; 54 | } 55 | return @""; 56 | } 57 | 58 | - (char *)typeOfPropertyFromAttributes:(const char *)attributes { 59 | if (!attributes || strlen(attributes) <= 1) { 60 | return 0x00; 61 | } 62 | char *result = NULL; 63 | if (!(attributes[1] == '{')){ 64 | result = malloc(sizeof(char) * 2); 65 | memset(result, 0, 2); 66 | strncpy(result, attributes + 1, 1); 67 | return result; 68 | } 69 | char *start = strstr(attributes, "{"); 70 | char *end = start; 71 | while (true) { 72 | char *tmp = strstr(end + 1, "}"); 73 | if (!tmp) break; 74 | end = tmp; 75 | } 76 | NSInteger len = end - start + 1; 77 | result = malloc(sizeof(char) * (len + 1)); 78 | memset(result, 0, len + 1); 79 | strncpy(result, start, len); 80 | return result; 81 | } 82 | 83 | - (void)encodeType:(char)type ofPropertySelector:(SEL)selector value:(id)value { 84 | if (!type) return; 85 | switch (type) { 86 | case 'B': { 87 | BOOL boolValue = [(NSNumber *)value boolValue]; 88 | ((void (*)(id, SEL, BOOL))(void *) objc_msgSend)((id)self, selector, boolValue); 89 | break; 90 | }; 91 | case 'c': { 92 | char charValue = [(NSNumber *)value charValue]; 93 | ((void (*)(id, SEL, char))(void *) objc_msgSend)((id)self, selector, charValue); 94 | break; 95 | } 96 | case 's': { 97 | short shortValue = [(NSNumber *)value shortValue]; 98 | ((void (*)(id, SEL, short))(void *) objc_msgSend)((id)self, selector, shortValue); 99 | break; 100 | } 101 | case 'i': { 102 | int intValue = [(NSNumber *)value intValue]; 103 | ((void (*)(id, SEL, int))(void *) objc_msgSend)((id)self, selector, intValue); 104 | break; 105 | } 106 | case 'C': { 107 | unsigned char unsignedCharValue = [(NSNumber *)value unsignedCharValue]; 108 | ((void (*)(id, SEL, unsigned char))(void *) objc_msgSend)((id)self, selector, unsignedCharValue); 109 | break; 110 | } 111 | case 'S': { 112 | unsigned short unsignedShortValue = [(NSNumber *)value unsignedShortValue]; 113 | ((void (*)(id, SEL, unsigned short))(void *) objc_msgSend)((id)self, selector, unsignedShortValue); 114 | break; 115 | } 116 | case 'I': { 117 | unsigned int unsignedIntValue = [(NSNumber *)value unsignedIntValue]; 118 | ((void (*)(id, SEL, unsigned int))(void *) objc_msgSend)((id)self, selector, unsignedIntValue); 119 | break; 120 | } 121 | case 'l': { 122 | long longValue = [(NSNumber *)value longValue]; 123 | ((void (*)(id, SEL, long))(void *) objc_msgSend)((id)self, selector, longValue); 124 | break; 125 | } 126 | case 'L': { 127 | unsigned long unsignedLongValue = [(NSNumber *)value unsignedLongValue]; 128 | ((void (*)(id, SEL, unsigned long))(void *) objc_msgSend)((id)self, selector, unsignedLongValue); 129 | break; 130 | } 131 | case 'q': { 132 | long long longLongValue = [(NSNumber *)value longLongValue]; 133 | ((void (*)(id, SEL, long long))(void *) objc_msgSend)((id)self, selector, longLongValue); 134 | break; 135 | } 136 | case 'Q': { 137 | unsigned long long unsignedLongLongValue = [(NSNumber *)value unsignedLongLongValue]; 138 | ((void (*)(id, SEL, unsigned long long))(void *) objc_msgSend)((id)self, selector, unsignedLongLongValue); 139 | break; 140 | } 141 | case 'f': { 142 | float floatValue = [(NSNumber *)value floatValue]; 143 | ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)self, selector, floatValue); 144 | break; 145 | } 146 | case 'd': { 147 | double doubleValue = [(NSNumber *)value doubleValue]; 148 | ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)self, selector, doubleValue); 149 | break; 150 | } 151 | default: { 152 | ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, selector, value); 153 | break; 154 | } 155 | } 156 | } 157 | 158 | - (void)encodeStructureType:(char *)type ofPropertySelector:(SEL)selector value:(id)value { 159 | if (!strcmp(type, @encode(CGPoint))) { 160 | CGPoint pointValue = [(NSValue *)value CGPointValue]; 161 | ((void (*)(id, SEL, CGPoint))(void *) objc_msgSend)((id)self, selector, pointValue); 162 | } 163 | else if (!strcmp(type, @encode(CGSize))) { 164 | CGSize sizeValue = [(NSValue *)value CGSizeValue]; 165 | ((void (*)(id, SEL, CGSize))(void *) objc_msgSend)((id)self, selector, sizeValue); 166 | } 167 | else if (!strcmp(type, @encode(CGRect))){ 168 | CGRect rectValue = [(NSValue *)value CGRectValue]; 169 | ((void (*)(id, SEL, CGRect))(void *) objc_msgSend)((id)self, selector, rectValue); 170 | } 171 | else if (!strcmp(type, @encode(CGAffineTransform))){ 172 | CGAffineTransform affineValue = [(NSValue*)value CGAffineTransformValue]; 173 | ((void (*)(id, SEL, CGAffineTransform))(void *) objc_msgSend)((id)self, selector, affineValue); 174 | } 175 | else if (!strcmp(type, @encode(UIEdgeInsets))){ 176 | UIEdgeInsets edgeInsetsValue = [(NSValue*)value UIEdgeInsetsValue]; 177 | ((void (*)(id, SEL, UIEdgeInsets))(void *) objc_msgSend)((id)self, selector, edgeInsetsValue); 178 | } 179 | else if (!strcmp(type, @encode(UIOffset))){ 180 | UIOffset offset = [(NSValue*)value UIOffsetValue]; 181 | ((void (*)(id, SEL, UIOffset))(void *) objc_msgSend)((id)self, selector, offset); 182 | } 183 | else { 184 | ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, selector, value); 185 | } 186 | } 187 | 188 | @end 189 | 190 | 191 | @implementation UINavigationController (JYCallBack) 192 | - (void)pushViewController:(UIViewController *)viewController 193 | animated:(BOOL)animated 194 | completion:(void(^)(void))completion { 195 | [CATransaction begin]; 196 | [CATransaction setCompletionBlock:completion]; 197 | [self pushViewController:viewController animated:animated]; 198 | [CATransaction commit]; 199 | } 200 | 201 | - (void)popToRootViewController:(BOOL)animated 202 | completion:(void(^)(void))completion { 203 | [CATransaction begin]; 204 | [CATransaction setCompletionBlock:completion]; 205 | [self popToRootViewControllerAnimated:animated]; 206 | [CATransaction commit]; 207 | } 208 | 209 | - (void)popToViewController:(UIViewController *)viewController 210 | animated:(BOOL)animated 211 | completion:(void(^)(void))completion { 212 | [CATransaction begin]; 213 | [CATransaction setCompletionBlock:completion]; 214 | [self popToViewController:viewController animated:animated]; 215 | [CATransaction commit]; 216 | } 217 | 218 | @end 219 | 220 | 221 | @interface JYRouterOptions() 222 | @property (nonatomic, assign) BOOL isModal; 223 | @property (nonatomic, assign) UIModalPresentationStyle presentationStyle; 224 | @property (nonatomic, assign) UIModalTransitionStyle transitionStyle; 225 | @property (nonatomic, strong) NSDictionary *defaultParams; 226 | @property (nonatomic, strong) Class openClass; 227 | @property (nonatomic, copy ) JYRouterOpenCallback callback; 228 | @end 229 | 230 | @implementation JYRouterOptions 231 | + (instancetype)routerOptionsWithModal:(BOOL)isModal { 232 | JYRouterOptions *options = [[JYRouterOptions alloc] init]; 233 | options.presentationStyle = UIModalPresentationNone; 234 | options.transitionStyle = UIModalTransitionStyleCoverVertical; 235 | options.isModal = isModal; 236 | return options; 237 | } 238 | 239 | + (instancetype)routerOptions { 240 | return [self routerOptionsWithModal:NO]; 241 | } 242 | 243 | + (instancetype)routerOptionsAsModal { 244 | return [self routerOptionsWithModal:YES]; 245 | } 246 | 247 | - (JYRouterOptions *)withPresentationStyle:(UIModalPresentationStyle)style { 248 | [self setPresentationStyle:style]; 249 | return self; 250 | } 251 | 252 | @end 253 | 254 | @interface JYRouterParams() 255 | @property (nonatomic, strong) JYRouterOptions *routerOptions; 256 | @property (nonatomic, strong) NSDictionary *openParams; 257 | @property (nonatomic, strong) NSDictionary *extraParams; 258 | @property (nonatomic, strong) NSDictionary *controllerParams; 259 | @end 260 | 261 | @implementation JYRouterParams 262 | - (instancetype)initWithRouterOptions:(JYRouterOptions *)routerOptions 263 | openParams:(NSDictionary *)openParams 264 | extraParams:(NSDictionary *)extraParams { 265 | [self setRouterOptions:routerOptions]; 266 | [self setExtraParams:extraParams]; 267 | [self setOpenParams:openParams]; 268 | return self; 269 | } 270 | 271 | @end 272 | 273 | 274 | #define ROUTE_NOT_FOUND_FORMAT @"No route found for URL %@" 275 | #define INVALID_CONTROLLER_FORMAT @"Your controller class %@ needs to implement either the static method %@ or the instance method %@" 276 | 277 | @interface JYRouter() 278 | @property (nonatomic, strong) UINavigationController *navigationController; 279 | @property (nonatomic, strong) NSMutableDictionary *routes; 280 | @property (nonatomic, strong) NSMutableDictionary *cachedRoutes; 281 | @property (nonatomic, strong) Class navClass; 282 | @end 283 | 284 | @implementation JYRouter 285 | 286 | + (instancetype)router { 287 | static JYRouter *_sharedRouter = nil; 288 | static dispatch_once_t onceToken; 289 | dispatch_once(&onceToken, ^{ 290 | _sharedRouter = [[JYRouter alloc] init]; 291 | }); 292 | return _sharedRouter; 293 | } 294 | 295 | + (instancetype)newRouter { 296 | return [[self alloc] init]; 297 | } 298 | 299 | - (instancetype)init { 300 | if (self = [super init]) { 301 | self.routes = [NSMutableDictionary dictionary]; 302 | self.cachedRoutes = [NSMutableDictionary dictionary]; 303 | } 304 | return self; 305 | } 306 | 307 | + (UIViewController *)currentVC { 308 | UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; 309 | while (topController.presentedViewController) { 310 | topController = topController.presentedViewController; 311 | } 312 | return topController; 313 | } 314 | 315 | - (void)setCustomNavigationClass:(Class)navClass { 316 | if (![navClass isSubclassOfClass:[UINavigationController class]]) { 317 | @throw [NSException exceptionWithName:@"NavClassTypeError" 318 | reason:@"navClass must be UINavigationController class or Subclass of UINavigationController" 319 | userInfo:nil]; 320 | } 321 | self.navClass = navClass; 322 | } 323 | 324 | - (BOOL)hasRouter:(NSString *)url { 325 | return [self.routes.allKeys containsObject:url]; 326 | } 327 | 328 | - (UIViewController *)controllerWithRouter:(NSString *)viewController { 329 | return [self controllerWithRouter:viewController 330 | params:nil]; 331 | } 332 | 333 | - (UIViewController *)controllerWithRouter:(NSString *)viewController 334 | params:(NSDictionary *)params { 335 | 336 | JYRouterOptions *options = [JYRouterOptions routerOptions]; 337 | 338 | if (![self hasRouter:viewController]) { 339 | [self map:viewController toController:[self classFromString:viewController] withOptions:options]; 340 | } 341 | JYRouterParams *extraParams = [self routerParamsForUrl:viewController extraParams:params]; 342 | 343 | options.openClass = [self classFromString:viewController]; 344 | extraParams.routerOptions = options; 345 | 346 | UIViewController *controller = [self controllerForRouterParams:extraParams]; 347 | [controller modelWithDictionary:params]; 348 | 349 | return controller; 350 | } 351 | 352 | - (void)push:(NSString *)viewController { 353 | [self push:viewController animated:YES]; 354 | } 355 | 356 | - (void)push:(NSString *)viewController animated:(BOOL)animated { 357 | [self push:viewController animated:animated params:nil]; 358 | } 359 | 360 | - (void)push:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params { 361 | [self push:viewController animated:animated params:params completion:nil]; 362 | } 363 | 364 | - (void)push:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 365 | [self open:viewController withOptions:nil animated:animated params:params completion:completion]; 366 | } 367 | 368 | - (void)present:(NSString *)viewController { 369 | [self present:viewController animated:YES]; 370 | } 371 | 372 | - (void)present:(NSString *)viewController animated:(BOOL)animated { 373 | [self present:viewController animated:animated params:nil]; 374 | } 375 | 376 | - (void)present:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params { 377 | [self present:viewController animated:animated params:params completion:nil]; 378 | } 379 | 380 | - (void)present:(NSString *)viewController animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 381 | [self open:viewController withOptions:[[JYRouterOptions routerOptionsAsModal] withPresentationStyle:UIModalPresentationFormSheet] animated:animated params:params completion:completion]; 382 | } 383 | 384 | - (void)present:(NSString *)viewController withOptions:(JYRouterOptions *)options animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 385 | [self open:viewController withOptions:options animated:animated params:params completion:completion]; 386 | } 387 | 388 | - (void)pop { 389 | [self popViewControllerFromRouterAnimated:YES]; 390 | } 391 | 392 | - (void)pop:(BOOL)animated { 393 | [self popViewControllerFromRouterAnimated:animated]; 394 | } 395 | 396 | - (void)popToRoot { 397 | [self popToRoot:YES]; 398 | } 399 | 400 | - (void)popToRoot:(BOOL)animated { 401 | [self popToRoot:animated completion:nil]; 402 | } 403 | 404 | - (void)popToRoot:(BOOL)animated completion:(void(^)(void))completion { 405 | [self.navigationController popToRootViewController:animated completion:completion]; 406 | } 407 | 408 | - (void)popTo:(NSString *)viewController { 409 | [self popTo:viewController animated:YES]; 410 | } 411 | 412 | - (void)popTo:(NSString *)viewController animated:(BOOL)animated { 413 | [self popTo:viewController animated:YES completion:nil]; 414 | } 415 | 416 | - (void)popTo:(NSString *)viewController animated:(BOOL)animated completion:(void(^)(void))completion { 417 | for (UIViewController *tempVC in self.navigationController.viewControllers) { 418 | if ([NSStringFromClass([tempVC class]) isEqualToString:viewController]) { 419 | [self.navigationController popToViewController:tempVC animated:animated completion:completion]; 420 | break; 421 | } 422 | } 423 | } 424 | 425 | - (void)dismiss { 426 | [self dismiss:YES]; 427 | } 428 | 429 | - (void)dismiss:(BOOL)animated { 430 | [self dismiss:animated completion:nil]; 431 | } 432 | 433 | - (void)dismiss:(BOOL)animated completion:(void(^)(void))completion { 434 | [self.navigationController dismissViewControllerAnimated:animated completion:completion]; 435 | } 436 | 437 | - (void)open:(NSString *)url withOptions:(JYRouterOptions *)options animated:(BOOL)animated params:(NSDictionary *)params completion:(void(^)(void))completion { 438 | 439 | if (![self hasRouter:url]) { 440 | [self map:url toController:[self classFromString:url] withOptions:options]; 441 | } 442 | 443 | JYRouterParams *extraParams = [self routerParamsForUrl:url extraParams:params]; 444 | if (!options) { 445 | options = [JYRouterOptions routerOptions]; 446 | } 447 | options.openClass = [self classFromString:url]; 448 | extraParams.routerOptions = options; 449 | 450 | if (options.callback) { 451 | JYRouterOpenCallback callback = options.callback; 452 | callback([extraParams controllerParams]); 453 | return; 454 | } 455 | 456 | if (!self.navigationController) { 457 | @throw [NSException exceptionWithName:@"NavigationControllerNotProvided" 458 | reason:@"Router#navigationController has not been set to a UINavigationController instance" 459 | userInfo:nil]; 460 | } 461 | 462 | UIViewController *controller = [self controllerForRouterParams:extraParams]; 463 | [controller modelWithDictionary:params]; 464 | 465 | 466 | if ([options isModal]) { 467 | if ([controller.class isSubclassOfClass:UINavigationController.class]) { 468 | [self.navigationController presentViewController:controller 469 | animated:animated 470 | completion:completion]; 471 | } 472 | else { 473 | if (!self.navClass) { 474 | self.navClass = [UINavigationController class]; 475 | } 476 | UINavigationController *navigationController = [[self.navClass alloc] initWithRootViewController:controller]; 477 | navigationController.modalPresentationStyle = controller.modalPresentationStyle; 478 | navigationController.modalTransitionStyle = controller.modalTransitionStyle; 479 | 480 | [self.navigationController presentViewController:navigationController 481 | animated:animated 482 | completion:completion]; 483 | } 484 | } 485 | else { 486 | [self.navigationController pushViewController:controller animated:animated completion:completion]; 487 | } 488 | } 489 | 490 | - (Class)classFromString:(NSString *)className { 491 | Class class = NSClassFromString(className); 492 | if (!class) { 493 | class = [self swiftClassFromString:className]; 494 | } 495 | // NSLog(@"class = %@",class); 496 | return class; 497 | } 498 | 499 | - (Class)swiftClassFromString:(NSString *)className { 500 | NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"]; 501 | appName = [appName stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; 502 | NSString *classStringName = [NSString stringWithFormat:@"%@.%@", appName, className]; 503 | return NSClassFromString(classStringName); 504 | } 505 | 506 | - (UINavigationController *)navigationController { 507 | return [self navigationControllerWithController:[UIApplication sharedApplication].delegate.window.rootViewController]; 508 | } 509 | 510 | - (UINavigationController *)navigationControllerWithController:(UIViewController *)viewController { 511 | if (viewController.presentedViewController) { 512 | return [self navigationControllerWithController:viewController.presentedViewController]; 513 | } 514 | else if ([viewController isKindOfClass:[UITabBarController class]]) { 515 | UITabBarController *vc = (UITabBarController *)viewController; 516 | return vc.selectedViewController; 517 | } 518 | else { 519 | return (UINavigationController *)viewController; 520 | } 521 | } 522 | 523 | - (void)map:(NSString *)format toController:(Class)controllerClass withOptions:(JYRouterOptions *)options { 524 | if (!format) { 525 | @throw [NSException exceptionWithName:@"RouteNotProvided" 526 | reason:@"Route #format is not initialized" 527 | userInfo:nil]; 528 | return; 529 | } 530 | if (!options) { 531 | options = [JYRouterOptions routerOptions]; 532 | } 533 | options.openClass = controllerClass; 534 | [self.routes setObject:options forKey:format]; 535 | } 536 | 537 | 538 | - (void)popViewControllerFromRouterAnimated:(BOOL)animated { 539 | if (self.navigationController.presentedViewController) { 540 | [self.navigationController dismissViewControllerAnimated:animated completion:nil]; 541 | } 542 | else { 543 | [self.navigationController popViewControllerAnimated:animated]; 544 | } 545 | } 546 | 547 | 548 | - (JYRouterParams *)routerParamsForUrl:(NSString *)url extraParams: (NSDictionary *)extraParams { 549 | if (!url) { 550 | if (_ignoresExceptions) { 551 | return nil; 552 | } 553 | @throw [NSException exceptionWithName:@"RouteNotFoundException" 554 | reason:[NSString stringWithFormat:ROUTE_NOT_FOUND_FORMAT, url] 555 | userInfo:nil]; 556 | } 557 | 558 | if ([self.cachedRoutes objectForKey:url] && !extraParams) { 559 | return [self.cachedRoutes objectForKey:url]; 560 | } 561 | 562 | NSArray *givenParts = url.pathComponents; 563 | NSArray *legacyParts = [url componentsSeparatedByString:@"/"]; 564 | if ([legacyParts count] != [givenParts count]) { 565 | NSLog(@"Routable Warning - your URL %@ has empty path components - this will throw an error in an upcoming release", url); 566 | givenParts = legacyParts; 567 | } 568 | 569 | __block JYRouterParams *openParams = nil; 570 | [self.routes enumerateKeysAndObjectsUsingBlock: 571 | ^(NSString *routerUrl, JYRouterOptions *routerOptions, BOOL *stop) { 572 | 573 | NSArray *routerParts = [routerUrl pathComponents]; 574 | if ([routerParts count] == [givenParts count]) { 575 | 576 | NSDictionary *givenParams = [self paramsForUrlComponents:givenParts routerUrlComponents:routerParts]; 577 | if (givenParams) { 578 | openParams = [[JYRouterParams alloc] initWithRouterOptions:routerOptions 579 | openParams:givenParams 580 | extraParams:extraParams]; 581 | *stop = YES; 582 | } 583 | } 584 | }]; 585 | 586 | if (!openParams) { 587 | if (_ignoresExceptions) { 588 | return nil; 589 | } 590 | @throw [NSException exceptionWithName:@"RouteNotFoundException" 591 | reason:[NSString stringWithFormat:ROUTE_NOT_FOUND_FORMAT, url] 592 | userInfo:nil]; 593 | } 594 | [self.cachedRoutes setObject:openParams forKey:url]; 595 | return openParams; 596 | } 597 | 598 | - (NSDictionary *)paramsForUrlComponents:(NSArray *)givenUrlComponents 599 | routerUrlComponents:(NSArray *)routerUrlComponents { 600 | 601 | __block NSMutableDictionary *params = [NSMutableDictionary dictionary]; 602 | [routerUrlComponents enumerateObjectsUsingBlock: 603 | ^(NSString *routerComponent, NSUInteger idx, BOOL *stop) { 604 | 605 | NSString *givenComponent = givenUrlComponents[idx]; 606 | if ([routerComponent hasPrefix:@":"]) { 607 | NSString *key = [routerComponent substringFromIndex:1]; 608 | [params setObject:givenComponent forKey:key]; 609 | } 610 | else if (![routerComponent isEqualToString:givenComponent]) { 611 | params = nil; 612 | *stop = YES; 613 | } 614 | }]; 615 | return params; 616 | } 617 | 618 | - (UIViewController *)controllerForRouterParams:(JYRouterParams *)params { 619 | SEL CONTROLLER_CLASS_SELECTOR = sel_registerName("allocWithRouterParams:"); 620 | SEL CONTROLLER_SELECTOR = sel_registerName("initWithRouterParams:"); 621 | SEL CONTROLLER_INIT = sel_registerName("init"); 622 | UIViewController *controller = nil; 623 | Class controllerClass = params.routerOptions.openClass; 624 | #pragma clang diagnostic push 625 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 626 | if ([controllerClass respondsToSelector:CONTROLLER_CLASS_SELECTOR]) { 627 | controller = [controllerClass performSelector:CONTROLLER_CLASS_SELECTOR withObject:[params controllerParams]]; 628 | } 629 | else if ([params.routerOptions.openClass instancesRespondToSelector:CONTROLLER_SELECTOR]) { 630 | controller = [[params.routerOptions.openClass alloc] performSelector:CONTROLLER_SELECTOR withObject:[params controllerParams]]; 631 | } 632 | else { 633 | controller = [[params.routerOptions.openClass alloc] performSelector:CONTROLLER_INIT]; 634 | } 635 | #pragma clang diagnostic pop 636 | if (!controller) { 637 | if (_ignoresExceptions) { 638 | return controller; 639 | } 640 | @throw [NSException exceptionWithName:@"RoutableInitializerNotFound" 641 | reason:[NSString stringWithFormat:INVALID_CONTROLLER_FORMAT, NSStringFromClass(controllerClass), NSStringFromSelector(CONTROLLER_CLASS_SELECTOR), NSStringFromSelector(CONTROLLER_SELECTOR)] 642 | userInfo:nil]; 643 | } 644 | 645 | controller.modalTransitionStyle = params.routerOptions.transitionStyle; 646 | controller.modalPresentationStyle = params.routerOptions.presentationStyle; 647 | return controller; 648 | } 649 | 650 | 651 | @end 652 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Job-Yang <578093143@qq.com> 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JYRouter 2 | ============== 3 | 4 | [![License MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/Job-Yang/JYRouter/master/LICENSE)  5 | [![CocoaPods](http://img.shields.io/cocoapods/v/JYRouter.svg?style=flat)](http://cocoapods.org/?q=JYRouter)  6 | [![CocoaPods](http://img.shields.io/cocoapods/p/JYRouter.svg?style=flat)](http://cocoapods.org/?q=JYRouter)  7 | [![Support](https://img.shields.io/badge/support-iOS%208%2B%20-blue.svg?style=flat)](https://www.apple.com/nl/ios/)  8 | 9 | 10 | Router framework is based on runtime to push/present/pop/dismiss for iOS 11 | 12 | 13 | 14 | Features 15 | ============== 16 | 17 | - **Compatibility:** Support for Objective-C and Swift 18 | 19 | - **Ease of use:** Support property auto assignment and completion callback 20 | 21 | - **Low coupling:** No need to inherit the base class or follow the protocol, plug and play 22 | 23 | - **Applicability:** Supports jumps other than UIViewController 24 | 25 | 26 | 27 | 28 | Usage 29 | ============== 30 | 31 | ### Jump 32 | **Objective-C** 33 | ```Objective-C 34 | // Push 35 | [[JYRouter router] push:@"JYViewController"]; 36 | 37 | // Push, Params 38 | NSDictionary *params1 = @{ @"title" : @"JYRouter"}; 39 | [[JYRouter router] push:@"JYViewController" animated:YES params:params1]; 40 | 41 | // Push, Params, Callback 42 | NSDictionary *params2 = @{@"type" : @(0)}; 43 | [[JYRouter router] push:@"JYViewController" animated:YES params:params2 completion:^{ 44 | NSLog(@"🔥🔥🔥Push completion callback🔥🔥🔥"); 45 | }]; 46 | ``` 47 | 48 | **Swift** 49 | ```Swift 50 | // Push 51 | JYRouter().push("JYViewController") 52 | 53 | // Push, Params 54 | let params1 = ["title" : "JYRouter"] 55 | JYRouter().push("JYViewController", animated: true, params: params1) 56 | 57 | // Push, Params, Callback 58 | let params2 = ["title" : "JYRouter"] 59 | JYRouter().push("JYViewController", animated: true, params: params2, completion: { 60 | print("🔥🔥🔥Push completion callback🔥🔥🔥") 61 | }) 62 | ``` 63 | 64 | ### Custom NavigationController 65 | **Objective-C** 66 | ```Objective-C 67 | // Set in AppDelegate 68 | [[JYRouter router] setCustomNavigationClass:[JYNavigationController class]]; 69 | ``` 70 | 71 | **Swift** 72 | ```Swift 73 | // Set in AppDelegate 74 | JYRouter().setCustomNavigationClass(JYNavigationController.self) 75 | ``` 76 | 77 | 78 | 79 | Installation 80 | ============== 81 | 82 | ### CocoaPods 83 | 1. Add `pod 'JYRouter'` to your Podfile. 84 | 2. Run `pod install` or `pod update`. 85 | 3. **Objective-C**: 86 | 1. `#import "JYRouter.h"` 87 | 88 | **Swift**: 89 | 1. Create `"YourProjectName-Bridging-Header.h"` bridging header file 90 | 2. `#import "JYRouter.h"` in the bridging header file 91 | 92 | ### Manually 93 | 1. Download all the files in the `JYRouter` subdirectory. 94 | 2. Add the source files to your Xcode project. 95 | 3. **Objective-C**: 96 | 1. `#import "JYRouter.h"` 97 | 98 | **Swift**: 99 | 1. Create `"YourProjectName-Bridging-Header.h"` bridging header file 100 | 2. `#import "JYRouter.h"` in the bridging header file 101 | 102 | 103 | ### License 104 | JYRouter is released under the MIT license. See LICENSE file for details. 105 | 106 | --- 107 | 108 | 109 | 110 | 中文介绍 111 | ============== 112 | 113 | 基于runtime实现的iOS路由框架 114 | 115 | 116 | 117 | 特性 118 | ============== 119 | 120 | - **兼容性:** 支持Objective-C和Swift 121 | - **易用性:** 支持属性自动赋值和完成回调 122 | - **低耦合:** 无需继承基类或遵循协议,即插即用 123 | - **适用性:** 支持UIViewController之外其他类的跳转 124 | 125 | 126 | 127 | 128 | 使用方法 129 | ============== 130 | 131 | ### Jump 132 | **Objective-C** 133 | ```Objective-C 134 | // Push跳转 135 | [[JYRouter router] push:@"JYViewController"]; 136 | 137 | // Push跳转,附带参数 138 | NSDictionary *params1 = @{@"title" : @"JYRouter"}; 139 | [[JYRouter router] push:@"JYViewController" animated:YES params:params1]; 140 | 141 | // Push跳转,附带参数,完成回调 142 | NSDictionary *params2 = @{@"type" : @(0)}; 143 | [[JYRouter router] push:@"JYViewController" animated:YES params:params2 completion:^{ 144 | NSLog(@"🔥🔥🔥Push完成回调🔥🔥🔥"); 145 | }]; 146 | ``` 147 | 148 | **Swift** 149 | ```Swift 150 | // Push跳转 151 | JYRouter().push("JYViewController") 152 | 153 | // Push跳转,附带参数 154 | let params1 = ["title" : "JYRouter"] 155 | JYRouter().push("JYViewController", animated: true, params: params1) 156 | 157 | // Push跳转,附带参数,完成回调 158 | let params2 = ["title" : "JYRouter"] 159 | JYRouter().push("JYViewController", animated: true, params: params2, completion: { 160 | print("🔥🔥🔥Push完成回调🔥🔥🔥") 161 | }) 162 | ``` 163 | 164 | ### 自定义NavigationController 165 | **Objective-C** 166 | ```Objective-C 167 | // 在AppDelegate设置 168 | [[JYRouter router] setCustomNavigationClass:[JYNavigationController class]]; 169 | ``` 170 | 171 | **Swift** 172 | ```Swift 173 | // 在AppDelegate设置 174 | JYRouter().setCustomNavigationClass(JYNavigationController.self) 175 | ``` 176 | 177 | 178 | 179 | 安装 180 | ============== 181 | 182 | ### CocoaPods 183 | 1. 在 Podfile 中添加 pod 'JYRouter'。 184 | 2. 执行 pod install 或 pod update。 185 | 3. **Objective-C**: 186 | 1. `#import "JYRouter.h"` 187 | 188 | **Swift**: 189 | 1. 建立 `"你的工程名-Bridging-Header.h"`桥接文件 190 | 2. 在该桥接文件中 `#import "JYRouter.h"` 191 | 192 | ### 手动安装 193 | 1. 下载 JYRouter 文件夹内的所有内容。 194 | 2. 将 JYRouter 内的源文件添加(拖放)到你的工程。 195 | 3. **Objective-C**: 196 | 1. `#import "JYRouter.h"` 197 | 198 | **Swift**: 199 | 1. 建立 `"你的工程名-Bridging-Header.h"`桥接文件 200 | 2. 在该桥接文件中 `#import "JYRouter.h"` 201 | 202 | 许可证 203 | ============== 204 | JYRouter 使用 MIT 许可证,详情见 LICENSE 文件。 205 | --------------------------------------------------------------------------------