android 组件化 蘑菇街,组件化在蘑菇街

本文详细分析了MGJRouter的源码,从Demo的概要、MGJRouter核心实现、注册与调用流程,以及注销操作等方面进行了解析。作者指出,MGJRouter的经典之处在于其设计思想和巧妙使用小技术解决大问题,建议读者下载源码深入学习。
摘要由CSDN通过智能技术生成

零、说点什么吧

周末是一个轻松的日子,于是决定写点什么。名字取得比较大,暂时也没有想到应该怎么命名。刚刚开始仔细的看了一下 MGJRouter 中的代码,所以一边看,也就一边的做点笔记。现在看完了,整理了一下就发出来了。都是以我看代码的顺序来描述的,建议各位大神自行下载代码细细品读!!

也是因为看了一圈的组件化、我更不知道 组件化 到底是什么。尽然这样、那就忘记组件化,看看在代码方面是如何实现组件化的。仅仅是通过 Demo 看大神们的代码到底使用了什么技术点。

蘑菇街的代码,在这里:MGJRouter 下载下来一起看看吧。

本介绍,仅仅是针对 Demo 的代码。

一、Demo 的概要

打开项目 MGJRouterDemo,看到两个控制器 DemoListViewController 与 DemoDetailViewController,结合项目运行起来的效果很好的能看出这两个控制器的实现逻辑。

1.1 List 控制器的列表数据源

当前就控制器的数据源是 titleWithHandlers 与 titles,仔细研究发现 DemoListViewController 中 +registerWithTitle: handler: 被调用于 DemoDetailViewController 中的 +load 方法中。

看完这个逻辑,发现了一个特点:在整个APP 的运行中仅创建了一个 DemoDetailViewController 对象,是一个 target 与 block 相结合的一个优秀技巧。很值得学习与借鉴。

1.2 Detail 控制器的实现

这个有点绕、但是经典就是经典。首先你会发现在 .h 文件中几乎什么都没有,但是能做出不同的显示。这个还是要归功于 +load 中 target 与 block 的巧妙使用。

二、MGJRouter 核心实现

先瞄一眼 MGJRouter 的头文件,清一色的 Class 方法,对于一个工具 Class,我也喜欢这么去设计。首先是因为这样使用特别的方便,其次尽然是工具就尽量不要拖泥带水的搞一些属性在那里。当然、技术是不能一概而论的,但是很多的时候也会发现很多的小伙伴根本不会写工具。关于 MGJRouter 还有一个巧妙的设计, 那就是本质是一个单例,只是没有被暴露。在我看这个代码之前,我还以为这种方式是我的独创,我之前也会这么干。看到一个单例的第一个正常反应是感觉看一下是否重写了类似 -init 这样的方法。可喜可贺,MGJRouter 是一个单纯的单例,没有重写这些方法。

大概看了一下头文件中各个方法的简单注释介绍,看完之后就可以开始分析具体的实现了。具体的入口的都在 DemoDetailViewController 中。

demoBasicUsage 方法

这个方法的原型如下:

- (void)demoBasicUsage

{

[MGJRouter registerURLPattern:@"mgj://foo/bar" toHandler:^(NSDictionary *routerParameters) {

[self appendLog:@"匹配到了 url,以下是相关信息"];

[self appendLog:[NSString stringWithFormat:@"routerParameters:%@", routerParameters]];

}];

[MGJRouter openURL:@"mgj://foo/bar"];

}

上面的代码中做了两件事:注册与调用。在这里我们要注意的是,在很多的时候我们在看优秀的代码的时候,可以先看方法,然后猜想一下大神的逻辑是什么。看到上面的代码,我的猜想是:通过一个 URL 注册信息,后期会通过这个 URL 找到注册的这些信息。,那么问题来了,到底是通过什么样的规则来注册呢?这些信息注册到哪里了呢?带着这些问题,我们开始打断点、并运行代码。

这里需要说明一点:这里仅仅是一个示例,并不是说注册就应该与具体的 openURL:写到一起。如果说在实际的项目开发中写到一起,那还叫 组件化 么?

2.1 注册实现

当代码运行起来之后,你的断点可能会在这里停留一会了:

5e997617c27c

pathComponentsFromURL:

我们先来看一看 pathComponentsFromURL: 方法中都做了什么事:

- (NSArray*)pathComponentsFromURL:(NSString*)URL

{

NSMutableArray *pathComponents = [NSMutableArray array];

if ([URL rangeOfString:@"://"].location != NSNotFound) {

NSArray *pathSegments = [URL componentsSeparatedByString:@"://"];

// 如果 URL 包含协议,那么把协议作为第一个元素放进去

[pathComponents addObject:pathSegments[0]];

// 如果只有协议,那么放一个占位符

URL = pathSegments.lastObject;

if (!URL.length) {

[pathComponents addObject:MGJ_ROUTER_WILDCARD_CHARACTER];

}

}

for (NSString *pathComponent in [[NSURL URLWithString:URL] pathComponents]) {

if ([pathComponent isEqualToString:@"/"]) continue;

if ([[pathComponent substringToIndex:1] isEqualToString:@"?"]) break;

[pathComponents addObject:pathComponent];

}

return [pathComponents copy];

}

这个方法,就是对一个字符串做一个解析操作,那么是如何解析的呢?我先把本 Demo 中用到的解析结果,在这里 Copy 一下:

@[@"mgj", @"foo", @"bar"]

@[@"mgj"]

@[@"mgj", @"search", @":query"]

@[@"mgj", @"~"] 是不是有一种通配符的感觉,对、没错。

如果对上面的结果有歧义,那么可以从上依次的学习一下这个方法中用到的方法:

NSString 中的 pathComponentsFromURL: 方法

关于这个方法,我给出的一个示例如下:

// 定义一个字符串

NSString* URL = @"Coder";

NSArray *pathSegments = [URL componentsSeparatedByString:@"://"];

NSLog(@"%@", pathSegments);

/** 打印结果:

(

Coder

)

*/

// 修改字符串

URL = @"Coder://";

pathSegments = [URL componentsSeparatedByString:@"://"];

NSLog(@"%@", pathSegments);

/** 打印结果:

(

Coder,

""

)

*/

// 修改字符串

URL = @"Coder://HG";

pathSegments = [URL componentsSeparatedByString:@"://"];

NSLog(@"%@", pathSegments);

/** 打印结果:

(

Coder,

HG

)

*/

综上可知:这是一个NSString 与 NSArray 之间的转换。具体的转换规则在上面的这个示例中已经完全的介绍了。上面的是 NSString 转换成 NSArray ,那么 NSArray 又是如何转成 NSString 的呢?

NSURL 的 pathComponents 方法

关于这个方法,我给出的示例代码如下:

// 定义一个字符串

NSURL* URL = [NSURL URLWithString:@"CoderHG/iOS/8968"];

// 执行方法

NSArray* pathComponents = [URL pathComponents];

// 打印

NSLog(@"%@", pathComponents);

/** 打印结果:

(

CoderHG,

iOS,

8968

)

*/

// 修改字符串 带中文

URL = [NSURL URLWithString:@"CoderHG/iOS/8968/朱鸿"];

pathComponents = [URL pathComponents];

// 打印

NSLog(@"%@", pathComponents);

/** 打印结果:

nil

*/

综上所述:这个方法是针对字符串中带有 / 而言的,一旦 URL 中带有中文,则返回为 nil。

NSString 的 substring 方法

关于这个方法,我给出的示例代码如下:

// 定义一个字符串

NSString* coder = @"coder";

NSString* substringToIndex = [coder substringToIndex:1];

NSString* substringFromIndex = [coder substringFromIndex:3];

NSLog(@"To = %@, From = %@", substringToIndex, substringFromIndex);

/** 打印结果:

To = c, From = er

*/

// 直接 crash

NSString* crashString = [coder substringToIndex:10];

NSLog(@"%@", crashString);

终上所述:就是一个字符剪切的方法,但是一定要注意 crash 的情况。

addURLPattern: 方法

上一个方法执行结束之后,就会回到这个方法中来, 这个方法很有意思,具体如下:

- (NSMutableDictionary *)addURLPattern:(NSString *)URLPattern

{

NSArray *pathComponents = [self pathComponentsFromURL:URLPattern];

NSMutableDictionary* subRoutes = self.routes;

for (NSString* pathComponent in pathComponents) {

if (![subRoutes objectForKey:pathComponent]) {

subRoutes[pathComponent] = [[NSMutableDictionary alloc] init];

}

subRoutes = subRoutes[pathComponent];

}

return subRoutes;

}

当从 pathComponentsFromURL: 中返回 pathComponents 数据之后, 对 self.routes 做了一系列的赋值处理。其中 routes 是一个关键的字典,就是用来承载注册信息的,具体是如何承载的呢?

主要是的代码就是在哪个 for 语句中,这是又是一个很奇妙的设计方式。第一次注册

5e997617c27c

image.png

这个数据结构,看起来 玄之又玄 ,弄了一个字典中的字典。

总之,就是通过 pathComponents 中的元素,在 self.routes 中布了一个局,里面什么都没有,都是空字典。 还有一个特点是,将最后一个字典做了 return 了。欲知有何用途,请看下面分解。

通过上面的方法之后, 会到这个方法中来:

addURLPattern: andHandler:

这个方法的原型是:

- (void)addURLPattern:(NSString *)URLPattern andHandler:(MGJRouterHandler)handler

{

NSMutableDictionary *subRoutes = [self addURLPattern:URLPattern];

if (handler && subRoutes) {

subRoutes[@"_"] = [handler copy];

}

}

通过 addURLPattern: 返回的 subRoutes 是根据 URLPattern 在 self.routes 中注册的最后一个字典。

看了这个方法,终于明白返回最后一个字典的原因就是将 注册的 handler 放到通过 _ 作为 key 值放到这个字典中。

到这里,一个简单的注册流程,就走完了。那么问题来了,这个注册流程到底都干了什么事情呢?总结如下:

通过 URLPattern 按照一定的规则解析成一个数组,然后将数组又按照一定的规则布局于 self.routes 中,最后将注册的 handler 放到通过 _ 作为 key 值放到最后一个字典中。

那么问题又来了:注册之后,又该如何使用呢?我的猜想是这样的:

注册仅仅是通过一定的规则,将注册的信息暂存于 self.routes 中,这些信息将服务于后期的 openURL: 操作。具体是如何服务的呢?请看下回分解。

以上是注册的整个流程,接下来看一下在调用 openURL 中又做了什么事?

2.2 openURL 流程

代码一路执行,最终到这里看到了一个莫名的转换,先来看看:

5e997617c27c

image.png

字符串的 stringByAddingPercentEscapesUsingEncoding: 方法,就这个方法,我给出的示例代码如下:

NSString* URL = @"鸿哥最帅";

NSLog(@"%@", URL);

// 打印结果: 鸿哥最帅

URL = [URL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSLog(@"%@", URL);

// 打印结果: %E9%B8%BF%E5%93%A5%E6%9C%80%E5%B8%85

URL = [URL stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSLog(@"%@", URL);

// 打印结果:鸿哥最帅

这个方法就是一个字符转义用的,主要是处理中文的情况。

下一步,跳进这个方法中来:

5e997617c27c

image.png

这里需要注意的是,这个方法传进来的 URL 是经过转义的。在往下,是一个 for 循环。主要就是查看当前传进来的 URL 是否被注册过,如果在 self.routes 任意一个节点中没有找到像匹配的节点,那么就直接返回 nil。在这个 for 循环中的技术点,数组排序的很简单,可以忽略,先来看一下这个方法:

+ (BOOL)checkIfContainsSpecialCharacter:(NSString *)checkedString {

NSCharacterSet *specialCharactersSet = [NSCharacterSet characterSetWithCharactersInString:specialCharacters];

return [checkedString rangeOfCharacterFromSet:specialCharactersSet].location != NSNotFound;

}

看方法的命名就知道,这个方法是用来检查 checkedString 是否包含特殊字符串的 ** specialCharacters(/?&.),的确,NSCharacterSet** 这东西挺厉害的,至少面试的时候面试官可能会这样的问:你用过 OC 中的集合么?如果说你回答了字典与数组,那么就等于面试官什么都没有问,如果说你回答了 NSSet,在强调一下 NSCharacterSet,恐怕面试官会爱上你的。关于这个,我给出的示例代码如下:

NSCharacterSet *specialCharactersSet = [NSCharacterSet characterSetWithCharactersInString:specialCharacters];

NSString* text = @"CoderHG";

NSRange rang = [text rangeOfCharacterFromSet:specialCharactersSet];

NSLog(@"%zd, %zd", rang.location, rang.length);

// 打印结果: 9223372036854775807, 0

text = @"Coder?HG";

rang = [text rangeOfCharacterFromSet:specialCharactersSet];

NSLog(@"%zd, %zd", rang.location, rang.length);

// 打印结果: 5, 1

text = @"C/?oder/?HG?";

rang = [text rangeOfCharacterFromSet:specialCharactersSet options:NSBackwardsSearch];

NSLog(@"%zd, %zd", rang.location, rang.length);

// 打印结果: 11, 1

关于 NSURLComponents,我的示例代码如下:

NSString* url = @"http://coder.com?coder=iOS&name=HG";

// Extract Params From Query.

NSArray *queryItems = [[NSURLComponents alloc] initWithURL:[[NSURL alloc] initWithString:url] resolvingAgainstBaseURL:false].queryItems;

NSMutableDictionary* parameters = [NSMutableDictionary dictionary];

for (NSURLQueryItem *item in queryItems) {

parameters[item.name] = item.value;

}

NSLog(@"%@", parameters);

/** 打印结果:

{

coder = iOS;

name = HG;

}

*/

明白了,原来是为了获取 URL 后面的参数的。想当年某些人使用一个一个的截取,然后一个一个的去拼接的。

2.3 注销操作

注销方法 +deregisterURLPattern:

主要是这个方法:

- (void)removeURLPattern:(NSString *)URLPattern

{

NSMutableArray *pathComponents = [NSMutableArray arrayWithArray:[self pathComponentsFromURL:URLPattern]];

// 只删除该 pattern 的最后一级

if (pathComponents.count >= 1) {

// 假如 URLPattern 为 a/b/c, components 就是 @"a.b.c" 正好可以作为 KVC 的 key

NSString *components = [pathComponents componentsJoinedByString:@"."];

NSMutableDictionary *route = [self.routes valueForKeyPath:components];

if (route.count >= 1) {

NSString *lastComponent = [pathComponents lastObject];

[pathComponents removeLastObject];

// 有可能是根 key,这样就是 self.routes 了

route = self.routes;

if (pathComponents.count) {

NSString *componentsWithoutLast = [pathComponents componentsJoinedByString:@"."];

route = [self.routes valueForKeyPath:componentsWithoutLast];

}

[route removeObjectForKey:lastComponent];

}

}

}

在注册分析的过程中已经发现,所谓的注册就是通过 URL 按照一定的规则将消息存于 self.routes 中,那么销毁正好相反。

至此整个流程也就差不多了, 还有没介绍到的,其实都有包括了。

三、想法

看完之后,也发现在 MGJRouter 中也没有什么高深莫测的技术点,但是这是一个很经典的代码。经典于设计思想、经典于使用小技术解决大问题。

建议大家下载源码仔细品读,会让你收获更多!

很多的时候我们不是不懂技术,而是不知道如何是使用我们已知的技术。

谢谢!

智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息服务的重要性。随着技术的成熟和政策环境的优,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能、个性和协同,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息建设的智能和应用多样趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息服务的重要性。随着技术的成熟和政策环境的优,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能、个性和协同,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息建设的智能和应用多样趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小损失函数。 11. **正则(Regularization)**:技术如 Dropout、L1/L2 正则等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值