本篇博文记录MBProgressHUD源码学习过程,从官方提供的Demo项目入手,一步步了解其代码结构,学习它使用的技术,体会作者的编程思想。

一、结构

我们先来看下MBProgressHUD的结构,查看其类的定义。

1.MBProgressHUD是UIView的子类。

2.属性:

1.
//代理,<MBProgressHUDDelegate>仅定义了一个方法:- (void)hudWasHidden:(MBProgressHUD *)hud;用于执行HUD隐藏之后的操作
@property (weak, nonatomic) id<MBProgressHUDDelegate> delegate;
//执行HUD隐藏之后的操作的Block,目的同上
@property (copy, nullable) MBProgressHUDCompletionBlock completionBlock;
2.
//延迟时间,若任务在graceTime到时之前就完成了,HUD不再展示,即防止为短时间任务显示HUD
@property (assign, nonatomic) NSTimeInterval graceTime;
//最短展示时间,防止HUD隐藏的过快
@property (assign, nonatomic) NSTimeInterval minShowTime;
//配置HUD是否隐藏之后就从其superview上移除。默认NO
@property (assign, nonatomic) BOOL removeFromSuperViewOnHide;
3.
//指定进度条的样式,包括菊花、圆饼、环形、水平进度条、自定义样式和纯文本等
@property (assign, nonatomic) MBProgressHUDMode mode;
//内容(label+indicator+customView)颜色
@property (strong, nonatomic, nullable) UIColor *contentColor;
//显示和隐藏时的动画类型:Fade(淡入淡出)、Zoom(放大显示缩小隐藏)、ZoomIn、ZoomOut
@property (assign, nonatomic) MBProgressHUDAnimation animationType;
//内容框(bezelView)距离中心位置的偏移,例如CGPointMake(0.f, MBProgressMaxOffset),内容框会在底部居中
@property (assign, nonatomic) CGPoint offset;
@property (assign, nonatomic) CGFloat margin;//各元素到HUD的边距
@property (assign, nonatomic) CGSize minSize;//内容框的最小尺寸
@property (assign, nonatomic, getter = isSquare) BOOL square;//强制HUD为方形
@property (assign, nonatomic, getter=areDefaultMotionEffectsEnabled) BOOL defaultMotionEffectsEnabled;//内容框(bezelView)是否受设备加速计的影响,默认YES
4.
@property (assign, nonatomic) float progress;//进度
@property (strong, nonatomic, nullable) NSProgress *progressObject;//进度对象,用于更新进度条
5.
//内容框,即展示实际内容(文本、indicator)的矩形框
@property (strong, nonatomic, readonly) MBBackgroundView *bezelView;
//背景试图,会覆盖整个屏幕
@property (strong, nonatomic, readonly) MBBackgroundView *backgroundView;
//自定义视图用于展示
@property (strong, nonatomic, nullable) UIView *customView;
@property (strong, nonatomic, readonly) UILabel *label;//文本
@property (strong, nonatomic, readonly) UILabel *detailsLabel;//文本下面的详细文本
@property (strong, nonatomic, readonly) UIButton *button;//文本下面的action button

3.其他相关类

(1) MBBackgroundView

  • UIView的子类,在MBPRogressHUD中充当内容框(bezelView)背景视图(backgroundView)两种角色。
  • 提供两种样式:清晰样式(MBProgressHUDBackgroundStyleSolidColor)模糊样式(MBProgressHUDBackgroundStyleBlur)
  • 模糊样式是通过UIVisualEffectViewUIBlurEffect实现的。

(2) MBRoundProgressView

  • UIView的子类,展示为饼状/环形的进度条。

(3) MBBarProgressView

  • UIView的子类,展示为条状的进度条。

(4) MBProgressHUDRoundedButton

  • UIButton的子类,展示位圆角button,作为HUD上的功能按钮。

知识点:HUD中有个button属性如下:

/**
* A button that is placed below the labels. Visible only if a target / action is added.
*/
@property (strong, nonatomic, readonly) UIButton *button;

注意它的注释Visible only if a target / action is added。也就是说,只有给button添加事件之后,该按钮才会展示出来。这是如何做到的呢?那就是重写UIView的函数- (CGSize)intrinsicContentSize:

- (CGSize)intrinsicContentSize {
// Only show if we have associated control events
if (self.allControlEvents == 0) return CGSizeZero;
CGSize size = [super intrinsicContentSize];
// Add some side padding
size.width += 20.f;
return size;
}

这个函数用来设置控件的内置尺寸。可以看到,通过判断allControlEvents的个数来判断button上是否有事件,如果有事件,就在原来内置的尺寸上加20。

二、代码追踪

了解了MBProgressHUD的基本结构之后,接下来我们就看看具体的功能是如何实现的。HUDDemo提供了15个样例,我们选取纯文本加载(菊花)条状进度条自定义视图进行分析,其他的样例与它们类似。

1.纯文本(Text)

我们先从最简单的纯文本开始。启动HUDDemo项目,点开MBHudDemoViewController.m文件,找到函数- (void)textExample{…},这个函数就是显示纯文本的处理函数:

- (void)textExample {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES]; // Set the text mode to show only text.
hud.mode = MBProgressHUDModeText;
hud.label.text = NSLocalizedString(@"Message here!", @"HUD message title");
// Move to bottm center.
hud.offset = CGPointMake(0.f, MBProgressMaxOffset); [hud hideAnimated:YES afterDelay:3.f];
}

① 进入到函数showHUDAddedTo:animated:中查看MBProgressHUD实例的创建过程:

  • initWithView:->initWithFrame:->commonInit

    使用self.navigationController.view的bounds初始化HUD,然后在commonInit里指定动画类型(Fade)、HUD模式(菊花)、间距(20)、内容颜色(黑色半透明)。除此之外,还设置HUD为完全透明,背景色为clear,配置HUD的尺寸自动调整

    //保证上下间距比例不变、左右间距比例不变,即防止横竖屏切换时HUD位置错误
    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    //让HUD的各个子视图自己控制自己的透明度,使其不受HUD透明度的影响
    self.layer.allowsGroupOpacity = NO;
  • [self setupViews]

    在这个函数中真正执行子视图的创建工作。

    • 背景视图(backgroundView)

      为类MBBackgroundView的实例。MBBackgroundView实例默认会创建成白色半透明模糊效果,并覆盖全屏,但在本例中,创建完成之后会更改其styleMBProgressHUDBackgroundStyleSolidColor,并将背景色设置为透明(clear)。

    • 内容框(bezelView)

      同为类MBBackgroundView实例,是实际展示内容的View(即中间的黑框),包含文本、indicator、进度条等。bezelView会默认创建成白色半透明模糊效果,但frame为0。创建后会设置其边角半径为5。

      知识点:作者为bezelView添加了MotionEffect,也就是说在bezelView显示的时候,它会根据手机的倾斜方向调整自己的位置!

      - (void)updateBezelMotionEffects {
      #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 || TARGET_OS_TV
      MBBackgroundView *bezelView = self.bezelView;
      if (![bezelView respondsToSelector:@selector(addMotionEffect:)]) return; if (self.defaultMotionEffectsEnabled) {
      CGFloat effectOffset = 10.f;
      UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
      effectX.maximumRelativeValue = @(effectOffset);
      effectX.minimumRelativeValue = @(-effectOffset); UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
      effectY.maximumRelativeValue = @(effectOffset);
      effectY.minimumRelativeValue = @(-effectOffset); UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init];
      group.motionEffects = @[effectX, effectY]; [bezelView addMotionEffect:group];
      } else {
      NSArray *effects = [bezelView motionEffects];
      for (UIMotionEffect *effect in effects) {
      [bezelView removeMotionEffect:effect];
      }
      }
      #endif
      }
    • label和detailsLabel

      设置显示文字的label,其中detailsLabel允许多行。

    • button

      MBProgressHUDRoundedButton的实例,作为HUD上的功能按钮,比如进度条下方可以显示一个"取消"按钮。

    • topSpacer和bottomSpacer

      均为UIView的实例,用于调节上下间距的辅助View。

    • 设置label、detailsLabel及button的抗压系数,并添加到父视图上。

      for (UIView *view in @[label, detailsLabel, button]) {
      view.translatesAutoresizingMaskIntoConstraints = NO;//自己手动管理约束
      [view setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisHorizontal];//设置水平抗压缩系数,值越大,越不容易被压缩
      [view setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisVertical];//设置垂直抗压缩系数,值越大,越不容易被压缩
      [bezelView addSubview:view];
      }
  • [self updateIndicators]

    HUD的indicatorUIView的实例,用来记录HUD上显示的视图,进度条、加载图标(菊花)、自定义视图等都是用HUD的indicator属性记录的。在函数- (void)updaetIndicators中,根据HUD的mode值配置不同的indicator。最后会调用[self setNeedsUpdateConstraints]触发约束更新函数-(void)updateConstraints来更新UI。

  • [self registerForNotifications]

    注册通知,处理屏幕旋转的问题。

② 在创建完HUD之后,会调用[hud showAnimated:animated];将HUD展示到屏幕上。事实上,虽然当前HUD已经在屏幕上了,但由于初始化HUD的时候bezelView的frame为0,用户看不到。

③ 配置HUD实例的属性

hud.mode = MBProgressHUDModeText;//设置hud只显示纯文本
hud.label.text = NSLocalizedString(@"Message here!", @"HUD message title");//设置文本内容
hud.offset = CGPointMake(0.f, MBProgressMaxOffset);//设置hud相对于中心位置的偏移

在mode的setter函数中会调用- (void)updateIndicators,根据mode的新值重新配置indicator,然后调用- (void)setNeedsUpdateConstraints触发-(void)updateConstraints来更新UI。而在offset的setter函数中会直接调用- (void)setNeedsUpdateConstraints触发-(void)updateConstraints来更新UI。

④ 在函数- (void)updateConstraints中更新布局:

  • 删除所有控件的constraints
  • 通过NSLayoutConstraint重新设置constraints
//1.以屏幕中心为基准,应用offset。priority = 998
CGPoint offset = self.offset;
NSMutableArray *centeringConstraints = [NSMutableArray array];
//x
[centeringConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.f constant:offset.x]];
//y
[centeringConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.f constant:offset.y]];
//为每个constraints设置priority
[self applyPriority:998.f toConstraints:centeringConstraints];
[self addConstraints:centeringConstraints]; //2.设置最小间距约束,priority = 999
NSMutableArray *sideConstraints = [NSMutableArray array];
[sideConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=margin)-[bezel]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(bezel)]];
[sideConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=margin)-[bezel]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(bezel)]];
[self applyPriority:999.f toConstraints:sideConstraints];
[self addConstraints:sideConstraints]; //3.bezel的最小尺寸约束 priority = 997
CGSize minimumSize = self.minSize;
if (!CGSizeEqualToSize(minimumSize, CGSizeZero)) {
NSMutableArray *minSizeConstraints = [NSMutableArray array];
[minSizeConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:minimumSize.width]];
[minSizeConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:minimumSize.height]];
[self applyPriority:997.f toConstraints:minSizeConstraints];
[bezelConstraints addObjectsFromArray:minSizeConstraints];
} //4.方形约束 priority=997
if (self.square) {
NSLayoutConstraint *square = [NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeWidth multiplier:1.f constant:0];
square.priority = 997.f;
[bezelConstraints addObject:square];
} //5.根据margin和设置上下spacer的间距约束
[topSpacer addConstraint:[NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:margin]];
[bottomSpacer addConstraint:[NSLayoutConstraint constraintWithItem:bottomSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:margin]]; [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bottomSpacer attribute:NSLayoutAttributeHeight multiplier:1.f constant:0.f]]; //6.设置bezel子视图(topSpacer、label、detailLabel、button、bottomSpacer)的约束
[subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
// Center in bezel
[bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f]];
// Ensure the minimum edge margin is kept
[bezelConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=margin)-[view]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(view)]];
// Element spacing
if (idx == 0) {
// First, ensure spacing to bezel edge
[bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeTop multiplier:1.f constant:0.f]];
} else if (idx == subviews.count - 1) {
// Last, ensure spacing to bezel edge
[bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
}
if (idx > 0) {
// Has previous
NSLayoutConstraint *padding = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:subviews[idx - 1] attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f];
[bezelConstraints addObject:padding];
[paddingConstraints addObject:padding];
}
}];
[bezel addConstraints:bezelConstraints];
self.bezelConstraints = bezelConstraints; self.paddingConstraints = [paddingConstraints copy];
[self updatePaddingConstraints];//在该函数里,根据子视图的可视性(hidden),设置子视图的上下间距(为4)

通过上面的priority可以知道优先级:最小间距约束>bezel的偏移约束>bezel最小尺寸约束=方形约束。因此,如果你设置了hud.square = YES,但是实际bezel并没有变为方形,则很可能是因为上面的这几个约束之间存在冲突,系统采用了高优先级的约束而忽略了square约束。不信你可以把square优先级改为1000试试看:)

知识点:这里出现了一个宏NSDictionaryOfVariableBindings,它可以用来方便的创建NSDictionary:

UIView *view1 = [UIView new];
UIView *view2 = [UIView new];
NSDictionary *dict = NSDictionaryOfVariableBindings(view1,view2);//{@"view1":view1,@"view2":view2}

总结:

​ 至此,我们来总结下纯文本HUD的整个创建及显示流程:

  1. 调用[MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES]创建HUD实例:包括配置属性默认值(动画类型、HUD样式、间距、内容颜色等),初始化view(backgroundView、bezelView、label、detailLabel、button、topSpacer、bottomSpacer),且会默认创建一个indicator。之后hud会显示在屏幕上,但由于约束未触发,因此用户看不到。
  2. hud.mode = MBProgressHUDModeText。HUD会根据mode的值去隐藏indicator,并更新约束。
  3. hud.label.text = NSLocalizedString(@"Message here!", @"HUD message title")设置要显示的文字。
  4. hud.offset = CGPointMake(0.f, MBProgressMaxOffset)设置bezelView的偏移属性:让其显示在最底部。并更新约束。
  5. [hud hideAnimated:YES afterDelay:3.f]设置一个延迟timer,在3s之后隐藏hud。隐藏之后调用completionBlock和代理方法- (void)hudWasHidden:(MBProgressHUD *)hud;

2.加载(菊花)

加载样式表现为一个旋转的菊花,底部也可包含"Loading…"等字样提示。我们以包含"Loading…"字样的HUD为例剖析其内部原理。代码如下:

- (void)labelExample {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES]; // Set the label text.
hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");
// You can also adjust other label properties if needed.
// hud.label.font = [UIFont italicSystemFontOfSize:16.f]; dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
[self doSomeWork];
dispatch_async(dispatch_get_main_queue(), ^{
[hud hideAnimated:YES];
});
});
}
  • 调用MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];创建HUD实例,过程跟纯文本是一样的。
  • hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");配置提示文案为"Loading"。
  • 之后在global_queue里面执行任务,完成任务之后回到主线程隐藏HUD。

通过分析纯文本HUD的创建过程我们知道,hud在初始化的时候,它的mode默认为MBProgressHUDModeIndeterminate,也就是说单纯的调用MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];创建出来的HUD就是带有菊花加载控件的HUD,我们接下来做的就是给它的label赋上文案即可。

3.条状进度条

MBProgressHUD提供了三种样式的进度条:条状、饼状、环状。其中饼状和环状差不多,接下来我们分析下条状进度条的实现原理:

- (void)barDeterminateExample {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES]; // Set the bar determinate mode to show task progress.
hud.mode = MBProgressHUDModeDeterminateHorizontalBar;
hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title"); dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
// Do something useful in the background and update the HUD periodically.
[self doSomeWorkWithProgress];
dispatch_async(dispatch_get_main_queue(), ^{
[hud hideAnimated:YES];
});
});
}
  • 调用MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];创建HUD实例,过程跟纯文本是一样的。
  • hud.mode = MBProgressHUDModeDeterminateHorizontalBar;设置mode为条状进度条。在mode的setter方法中会调用- (void)updateIndicator创建进度条indicator。
  • 进度条indicator是类MBBarProgressView的实例。创建时默认宽为120,高为20,内容高度(intrinsicContentSize)为10。它的样式是在- (void)drawRect中绘制的。在其progress属性的setter方法中调用了-(void)setNeedsDisplay从而触发- (void)drawRect来更新进度。
  • hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");配置HUD提示文案为"Loading"。

4.自定义视图

MBProgressHUD提供了显示自定义视图的功能。在Demo中是展示一个对勾。

- (void)customViewExample {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES]; // Set the custom view mode to show any view.
hud.mode = MBProgressHUDModeCustomView;
// Set an image view with a checkmark.
UIImage *image = [[UIImage imageNamed:@"Checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
hud.customView = [[UIImageView alloc] initWithImage:image];
// Looks a bit nicer if we make it square.
hud.square = YES;
// Optional label text.
hud.label.text = NSLocalizedString(@"Done", @"HUD done title"); [hud hideAnimated:YES afterDelay:3.f];
}
  • 调用MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];创建HUD实例,过程跟纯文本是一样的。
  • hud.mode = MBProgressHUDModeCustomView;设置mode为自定义视图。接下来将需要展示的自定义视图赋值给hud的customView属性。在customView属性的setter方法中会调用- (void)updateIndicatorscustomView添加到HUD上。
  • 为了让界面美观,规定hud显示为方形:hud.square = YES;
  • hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");配置HUD提示文案为"Loading"。

至此,我们已经简单了解了MBProgressHUD的整个代码结构及使用流程,这已经足够我们去创建和使用符合我们需求的HUD了。但其实MBProgressHUD的源码中还包含不少高级的技术细节,我们将在下篇文章中一个个分析学习。

MBProgressHUD源码(上)的更多相关文章

  1. 在Activiti官方源码上提交的两个bugfix

    前段时间在Activiti官方源码上提交了两个bugfix,截图为证. 第1个是BPMN model输出的bug:

  2. [转]MBProgressHUD 源码分析

    源码来源: https://github.com/jdg/MBProgressHUD 版本:0.9.1 MBProgressHUD是一个显示HUD窗口的第三方类库,用于在执行一些后台任务时,在程序中显 ...

  3. 使用git将Android源码上传到github

    下面举Android的Browser源码通过git保存到github上 首先在github.com官网new repository一个仓库 在Repository name哪里填入Browser然后创 ...

  4. 从源码上分析ListView的addHeaderView和setAdapter的调用顺序

    ListView想要添加headerview的话,就要通过addHeaderView这个方法,然后想要为ListView设置数据的话,就要调用setAdapter方法了.但是,在调用addHeader ...

  5. 从源码上理解Netty并发工具-Promise

    前提 最近一直在看Netty相关的内容,也在编写一个轻量级的RPC框架来练手,途中发现了Netty的源码有很多亮点,某些实现甚至可以用苛刻来形容.另外,Netty提供的工具类也是相当优秀,可以开箱即用 ...

  6. 硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理

    前提 很早之前就打算看一次JUC线程池ThreadPoolExecutor的源码实现,由于近段时间比较忙,一直没有时间整理出源码分析的文章.之前在分析扩展线程池实现可回调的Future时候曾经提到并发 ...

  7. 源码上看 .NET 中 StringBuilder 拼接字符串的实现

    前几天写了一篇StringBuilder与TextWriter二者之间区别的文章(链接).当时提了一句没有找到相关源码,于是随后有很多热心人士给出了相关的源码链接(链接),感谢大家.这几天抽了点时间查 ...

  8. 带着萌新看springboot源码11(springboot启动原理 源码上)

    通过前面这么多讲解,springboot原理应该也大概有个轮廓了,一些基本的配置,从客户端url到controller(配置一些要用的组件,servlet三大组件,处理器映射器,拦截器,视图解析器这些 ...

  9. 带着萌新看springboot源码8(spring ioc源码上)

    emmm.....这次先不说springboot原理,先好好回顾一下以前的注解版spring原理,先把spring原理了解清晰了,再看springboot原理更容易. 要说起spring,最重要的就是 ...

随机推荐

  1. git合并多次commit提交

    在开发项目工程中经常会遇到为了一个需求产生多次提交记录.有些是可以接受的,比如按照功能点不同进行的提交.但往往会存在这种,只为了一个小东西进行改动,比如多余文件的提交.书写不规范而不得不提交的情况.多 ...

  2. IDEA使用svn拉取多模块项目

    如果没有安装过svn客户端,安装的时候需要选择安装第二个工具,如下图所示 安装小乌龟, 自行搜索, 注意点是需要选择安装第二个工具 因为默认是不安装的, 而这个组件是集成到IDEA ”必须的” . 如 ...

  3. 纸壳CMS现已支持自定义扩展字段

    简介 纸壳CMS是开源免费的可视化内容管理系统. GitHub https://github.com/SeriaWei/ZKEACMS 自定义字段 纸壳CMS现已支持自定义字段,在不修改代码的情况下, ...

  4. QPNP 8909 8916 充电相关(2)【转】

    上一篇主要讲电池相关的一些知识,上节忘记讲了,电池一般分为电量计电池和非电流计电池,电量计电池,就不需要用pmu8916的IC,当然这只是只,不需要BMS来计算soc,而jni层也需要读取电流计的电池 ...

  5. 二叉搜索树中第K小的元素

    给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: root = [ ...

  6. AcWing 901. 滑雪

    地址 https://www.acwing.com/problem/content/description/903/ 题目描述给定一个R行C列的矩阵,表示一个矩形网格滑雪场. 矩阵中第 i 行第 j ...

  7. 关于sublime建立python工程的说明

    https://www.zhihu.com/question/22681628此链接说明的不错,可以参考. 为了方便使用sublime,难免要定义一些快捷键,https://www.whidy.net ...

  8. A1100 Mars Numbers (20 分)

    一.技术总结 这一题可以使用map进行想打印存储,因为数据量不是很大,最后直接输出.但是还是觉得没有必要. 主要考虑两个问题,首先是数字转化为字符串,实质就是进制转化,但是有点不同,如果十位有数字,个 ...

  9. Educational Codeforces Round 76 (Rated for Div. 2) C. Dominated Subarray 水题

    C. Dominated Subarray Let's call an array

  10. Tensorflow分布式部署和开发

    关于tensorflow的分布式训练和部署, 官方有个英文的文档介绍,但是写的比较简单, 给的例子也比较简单,刚接触分布式深度学习的可能不太容易理解.在网上看到一些资料,总感觉说的不够通俗易懂,不如自 ...