iOS 路由跳转
项目中我们会有很多的页面,我们就需要不断的push或者present
如果我们能够实现路由跳转(像网页一样通过一个URL地址去访问)就会方便很多
那么我们今天就来讨论下页面使用路由跳转
一、首先我们要清楚一些基本概念
1、scheme
每个app都有自己独立的沙盒、互相独立。这样阻碍了app之间的通信。
苹果给我们的通信是通过URL Schemes。只要每个app定义了自己的Schemes,便能实现app之间跳转。
苹果系统原生的app、比如打电话tel://等。还有一些第三方的,比如支付宝alipay://
其实scheme 就是://前面的英文字符
路由跳转就是约定一个url。也就是根据scheme进行跳转
2、NSURL
/* Any URL is composed of these two basic pieces. The full URL would be the concatenation of [myURL scheme], ':', [myURL resourceSpecifier] */ @property (nullable, readonly, copy) NSString *scheme; @property (nullable, readonly, copy) NSString *resourceSpecifier; /* If the URL conforms to rfc 1808 (the most common form of URL), the following accessors will return the various components; otherwise they return nil. The litmus test for conformance is as recommended in RFC 1808 - whether the first two characters of resourceSpecifier is @"//". In all cases, they return the component's value after resolving the receiver against its base URL. */ @property (nullable, readonly, copy) NSString *host; @property (nullable, readonly, copy) NSNumber *port; @property (nullable, readonly, copy) NSString *user; @property (nullable, readonly, copy) NSString *password; @property (nullable, readonly, copy) NSString *path; @property (nullable, readonly, copy) NSString *fragment; @property (nullable, readonly, copy) NSString *parameterString API_DEPRECATED("The parameterString method is deprecated. Post deprecation for applications linked with or after the macOS 10.15, and for all iOS, watchOS, and tvOS applications, parameterString will always return nil, and the path method will return the complete path including the semicolon separator and params component if the URL string contains them.", macosx(10.2,10.15), ios(2.0,13.0), watchos(2.0,6.0), tvos(9.0,13.0)); @property (nullable, readonly, copy) NSString *query;
例如:
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com/test/mypath?test=baiduhome&number=123"];
scheme http
host www.baidu.com
path /test/mypath
query test=baiduhome&number=123
二、实现原理
1、创建一个单例对象拥有一个可变字典,用来保存键值对
2、以query之前为key 类名为value 在每个页面的load方法中完成注册
3、在每个页面实现具体跳转逻辑
例如:
NSURL *url = [NSURL URLWithString:@"project://test/mypath?test=baiduhome&number=123"];
key project://test/mypath
value TestViewController
SchemeProtocol
typedef void(^SchemeCompletion)(id objc); @protocol SchemeProtocol <NSObject> // 跳转方法 + (void)SchemeData:(NSDictionary *)data url:(NSString *)url completion:(SchemeCompletion)handler; @end
SchemeTool
@interface SchemeTool() @property (nonatomic,strong) NSMutableDictionary *modules; @end @implementation SchemeTool #pragma mark - Instancet + (instancetype)shared { static SchemeTool * schemeTool = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ schemeTool = [[SchemeTool alloc] init]; }); return schemeTool; } - (instancetype)init{ self = [super init]; if (self) { _modules = [[NSMutableDictionary alloc] init]; } return self; }
// 注册 url与Class绑定
+ (void)registerModule:(Class)moduleClass pathName:(NSString *)pathName{
[iComeSchemeTool shared].modules[pathName] = moduleClass;
}
// 跳转 通过url实现跳转
+ (void)receiveSchemeURL:(NSURL *)schemeURL completion:(SchemeCompletion)handler{
NSString *query = schemeURL.query;
NSString *key = [[schemeURL.absoluteString componentsSeparatedByString:@"?"] firstObject];
// 通过url找到对应Class
Class ocClass = [SchemeTool shared].modules[key];
// 判断是否实现跳转方法
if (ocClass &&
[ocClass respondsToSelector:@selector(SchemeData:url:completion:)]){
// 解析query
NSDictionary *dic = [SchemeTool queryDicWithStr:query];
// 调用跳转方法
[[ocClass class] SchemeData:dic url:schemeURL.absoluteString completion:handler];
}else {
// 未实现跳转方法
}
}
// 解析query
+ (NSDictionary *)queryDicWithStr:(NSString *)queryStr{
NSMutableDictionary *dict = [NSMutableDictionary new];
NSArray *paramArray = [queryStr componentsSeparatedByString:@"&"];
for (NSString *param in paramArray) {
if (param && param.length) {
NSRange range = [param rangeOfString:@"="];
if (range.location != NSNotFound) {
NSString *keyStr = [param substringToIndex:range.location];
NSString *valueStr = [param substringFromIndex:range.location+range.length];
dict[keyStr] = valueStr;
}else{
dict[param] = param;
}
}
}
return dict;
}
TestViewController
@implementation TestViewController
+ (void)load {
// 注册 url与Class 绑定
[SchemeTool registerModule:[self class] pathName:@"project://test/mypath"];
}
// 跳转方法
+ (void) SchemeData:(NSDictionary *)data url:(NSString *)url completion:(SchemeCompletion)handler { TestViewController *vc = [[TestViewController alloc] init]; vc.test = data[@"test"]; [[WOWSUtils getCurrentVC] pushViewController:vc]; }