Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
lightory committed Apr 24, 2014
2 parents 4bd6e07 + 471f888 commit 07348b6
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 123 deletions.
61 changes: 43 additions & 18 deletions HHRouter/HHRouter.h
Original file line number Diff line number Diff line change
@@ -1,28 +1,53 @@
// The MIT License (MIT)
// The MIT License (MIT)
//
// Copyright (c) 2014 LIGHT lightory@gmail.com
// Copyright (c) 2014 LIGHT lightory@gmail.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#import <Foundation/Foundation.h>

///---------------
/// @name HHRouter
///---------------

typedef id (^HHRouterBlock)(NSDictionary* params);

@interface HHRouter : NSObject

+ (instancetype)shared;
- (void)map:(NSString *)route toControllerClass:(Class)controllerClass;
- (UIViewController *)match:(NSString *)route;

- (void)map:(NSString*)route toControllerClass:(Class)controllerClass;
- (UIViewController*)match:(NSString*)route __attribute__((deprecated));
- (UIViewController*)matchController:(NSString*)route;

- (void)map:(NSString*)route toBlock:(HHRouterBlock)block;
- (HHRouterBlock)matchBlock:(NSString*)route;
- (id)callBlock:(NSString*)route;

@end

///--------------------------------
/// @name UIViewController Category
///--------------------------------

@interface UIViewController (HHRouter)

@property (nonatomic, strong) NSDictionary* params;

@end
236 changes: 166 additions & 70 deletions HHRouter/HHRouter.m
Original file line number Diff line number Diff line change
@@ -1,72 +1,113 @@
// The MIT License (MIT)
// The MIT License (MIT)
//
// Copyright (c) 2014 LIGHT lightory@gmail.com
// Copyright (c) 2014 LIGHT lightory@gmail.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#import "HHRouter.h"
#import <objc/runtime.h>

@interface HHRouter ()
@property (strong, nonatomic) NSMutableDictionary *routes;
@property (strong, nonatomic) NSMutableDictionary* routes;
@end

@implementation HHRouter

+ (instancetype)shared
{
static HHRouter *router = nil;
static HHRouter* router = nil;
static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{
if (!router) {
router = [[self alloc] init];
}
if (!router) {
router = [[self alloc] init];
}
});
return router;
}

- (void)map:(NSString *)route toControllerClass:(Class)controllerClass
- (void)map:(NSString*)route toBlock:(HHRouterBlock)block
{
NSArray *pathComponents = [self pathComponentsFromRoute:route];

NSInteger index = 0;
NSMutableDictionary *subRoutes = self.routes;
while (index < pathComponents.count) {
NSString *pathComponent = pathComponents[index];
if (![subRoutes objectForKey:pathComponent]) {
subRoutes[pathComponent] = [[NSMutableDictionary alloc] init];
NSMutableDictionary* subRoutes = [self subRoutesToRoute:route];

subRoutes[@"_"] = [block copy];
}

- (UIViewController*)matchController:(NSString*)route
{
NSDictionary* params = [self paramsInRoute:route];
Class controllerClass = params[@"controller_class"];

UIViewController* viewController = [[controllerClass alloc] init];

if ([viewController respondsToSelector:@selector(setParams:)]) {
[viewController performSelector:@selector(setParams:)
withObject:[params copy]];
}
return viewController;
}

- (UIViewController*)match:(NSString*)route
{
return [self matchController:route];
}

- (HHRouterBlock)matchBlock:(NSString*)route
{
NSDictionary* params = [self paramsInRoute:route];
HHRouterBlock routerBlock = [params[@"block"] copy];
HHRouterBlock returnBlock = ^id(NSDictionary* aParams)
{
if (routerBlock) {
return routerBlock([params copy]);
}
subRoutes = subRoutes[pathComponent];
index++;
return nil;
};

return [returnBlock copy];
}

- (id)callBlock:(NSString*)route
{
NSDictionary* params = [self paramsInRoute:route];
HHRouterBlock routerBlock = [params[@"block"] copy];

if (routerBlock) {
return routerBlock([params copy]);
}
subRoutes[@"_"] = controllerClass;
return nil;
}

- (UIViewController *)match:(NSString *)route
// extract params in a route
- (NSDictionary*)paramsInRoute:(NSString*)route
{
NSMutableDictionary *params = [NSMutableDictionary dictionary];
NSMutableDictionary* params = [NSMutableDictionary dictionary];

params[@"route"] = [self stringFromFilterAppUrlScheme:route];

NSMutableDictionary *subRoutes = self.routes;
NSArray *pathComponents = [self pathComponentsFromRoute:[self stringFromFilterAppUrlScheme:route]];
for (NSString *pathComponent in pathComponents) {

NSMutableDictionary* subRoutes = self.routes;
NSArray* pathComponents =
[self pathComponentsFromRoute:[self stringFromFilterAppUrlScheme:route]];
for (NSString* pathComponent in pathComponents) {
BOOL found = NO;
NSArray *subRoutesKeys = subRoutes.allKeys;
for (NSString *key in subRoutesKeys) {
NSArray* subRoutesKeys = subRoutes.allKeys;
for (NSString* key in subRoutesKeys) {
if ([key isEqualToString:pathComponent]) {
found = YES;
subRoutes = subRoutes[key];
Expand All @@ -78,76 +119,131 @@ - (UIViewController *)match:(NSString *)route
break;
}
}
if (!found) return nil;
if (!found) {
return nil;
}
}

// Extract Params From Query.
NSArray *pathInfo = [route componentsSeparatedByString:@"?"];
NSArray* pathInfo = [route componentsSeparatedByString:@"?"];
if (pathInfo.count > 1) {
NSString *paramsString = [pathInfo objectAtIndex:1];
NSArray *paramStringArr = [paramsString componentsSeparatedByString:@"&"];
for (NSString *paramString in paramStringArr) {
NSArray *paramArr = [paramString componentsSeparatedByString:@"="];
NSString* paramsString = [pathInfo objectAtIndex:1];
NSArray* paramStringArr = [paramsString componentsSeparatedByString:@"&"];
for (NSString* paramString in paramStringArr) {
NSArray* paramArr = [paramString componentsSeparatedByString:@"="];
if (paramArr.count > 1) {
NSString *key = [paramArr objectAtIndex:0];
NSString *value = [paramArr objectAtIndex:1];
NSString* key = [paramArr objectAtIndex:0];
NSString* value = [paramArr objectAtIndex:1];
params[key] = value;
}
}
}

Class controllerClass = subRoutes[@"_"];
UIViewController *viewController = [[controllerClass alloc] init];
if ([viewController respondsToSelector:@selector(setParams:)]) {
[viewController performSelector:@selector(setParams:) withObject:[params copy]];
Class class = subRoutes[@"_"];
if (class_isMetaClass(object_getClass(class))) {
if ([class isSubclassOfClass:[UIViewController class]]) {
params[@"controller_class"] = subRoutes[@"_"];
} else {
return nil;
}
} else {
if (subRoutes[@"_"]) {
params[@"block"] = [subRoutes[@"_"] copy];
}
}
return viewController;

return [NSDictionary dictionaryWithDictionary:params];
}

#pragma mark - Private
- (NSMutableDictionary *)routes

- (NSMutableDictionary*)routes
{
if (!_routes) {
_routes = [[NSMutableDictionary alloc] init];
}
return _routes;
}

- (NSArray *)pathComponentsFromRoute:(NSString *)route
- (NSArray*)pathComponentsFromRoute:(NSString*)route
{
NSMutableArray *pathComponents = [NSMutableArray array];
for (NSString *pathComponent in route.pathComponents) {
if ([pathComponent isEqualToString:@"/"]) continue;
if ([[pathComponent substringToIndex:1] isEqualToString:@"?"]) break;
[pathComponents addObject:pathComponent];
}

return [pathComponents copy];
}

- (NSString *)stringFromFilterAppUrlScheme:(NSString *)string
- (NSString*)stringFromFilterAppUrlScheme:(NSString*)string
{
//filter out the app URL compontents.
for (NSString *appUrlScheme in [self appUrlSchemes]) {
// filter out the app URL compontents.
for (NSString* appUrlScheme in [self appUrlSchemes]) {
if ([string hasPrefix:[NSString stringWithFormat:@"%@:", appUrlScheme]]) {
return [string substringFromIndex:appUrlScheme.length + 1];
}
}

return string;
}

- (NSArray *)appUrlSchemes
- (NSArray*)appUrlSchemes
{
NSMutableArray *appUrlSchemes = [NSMutableArray array];

NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
for (NSDictionary *dic in infoDictionary[@"CFBundleURLTypes"]) {
NSString *appUrlScheme = dic[@"CFBundleURLSchemes"][0];
NSMutableArray* appUrlSchemes = [NSMutableArray array];

NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];

for (NSDictionary* dic in infoDictionary[@"CFBundleURLTypes"]) {
NSString* appUrlScheme = dic[@"CFBundleURLSchemes"][0];
[appUrlSchemes addObject:appUrlScheme];
}

return [appUrlSchemes copy];
}

- (NSMutableDictionary*)subRoutesToRoute:(NSString*)route
{
NSArray* pathComponents = [self pathComponentsFromRoute:route];

NSInteger index = 0;
NSMutableDictionary* subRoutes = self.routes;

while (index < pathComponents.count) {
NSString* pathComponent = pathComponents[index];
if (![subRoutes objectForKey:pathComponent]) {
subRoutes[pathComponent] = [[NSMutableDictionary alloc] init];
}
subRoutes = subRoutes[pathComponent];
index++;
}
return subRoutes;
}

- (void)map:(NSString*)route toControllerClass:(Class)controllerClass
{
NSMutableDictionary* subRoutes = [self subRoutesToRoute:route];

subRoutes[@"_"] = controllerClass;
}

@end

#pragma mark - UIViewController Category

@implementation UIViewController (HHRouter)

static char kAssociatedParamsObjectKey;

- (void)setParams:(NSDictionary*)paramsDictionary
{
objc_setAssociatedObject(self, &kAssociatedParamsObjectKey, paramsDictionary,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSDictionary*)params
{
return objc_getAssociatedObject(self, &kAssociatedParamsObjectKey);
}

@end
Loading

0 comments on commit 07348b6

Please sign in to comment.