本篇博文记录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. 代码这样写更优雅,15篇 Python 技术热文

    http://mp.weixin.qq.com/s?__biz=MzA4MjEyNTA5Mw==&mid=2652565527&idx=1&sn=840c1ce854afc29 ...

  2. css3动画如何解决动画的播放、暂停和重新开始

    0921自我总结 css3如何解决动画的播放.暂停和重新开始 一.解决的本质思路 播放的解决思路 先定义好动画效果通过类名的增加达到样式的出现 暂停的解决思路 我们播放动画时,如要暂停动画,就要用到a ...

  3. 如何去除小程序button的边框

    小程序button 自带样式,就算用 border:none: background:none ,还是会有一条细的边框 使用:after选择器就可以去除 button::after{ border:n ...

  4. Shell变量概述

    目录 1. Shell变量概述 1.定义变量,变量名=变量值.不能出现"-横杠"命令 2.引用变量,$变量名 3.查看变量,set显示所有变量,包括自定义变量和环境变量 4.取消变 ...

  5. 读书笔记_python网络编程3_(3)

    3.TCP:传输控制协议 第一个版本在1974年定义,建立在网际层协议(IP)提供的数据包传输技术之上.TCP使程序可以使用连续的数据流进行相互通信. 除非网络原因导致连接中断/冻结,TCP都能保证将 ...

  6. mssql sqlserver 添加表注释和添加列注释的方法分享

     转自: http://www.maomao365.com/?p=8919 摘要: 下文讲述使用sql脚本对数据表或数据列添加注释(备注说明)的方法分享,如下所示: 实验环境:sql server 2 ...

  7. 如何将RAC数据库的 RMAN Disk 备份 Restore 到另一个节点上的单个实例 (Doc ID 415579.1)

    HowTo Restore RMAN Disk backups of RAC Database to Single Instance On Another Node (Doc ID 415579.1) ...

  8. numpy和matplotlib的pyplot函数的简单应用实现

  9. 四、读取一系列dcm图片,然后重新写入

    一.程序功能 读取一系列的CT dcm图片,然后重新写入到一个文件夹 二.代码 #pragma warning(disable:4996) #include "itkGDCMImageIO. ...

  10. leetcode 双周赛9 进击的骑士

    一个坐标可以从 -infinity 延伸到 +infinity 的 无限大的 棋盘上,你的 骑士 驻扎在坐标为 [0, 0] 的方格里. 骑士的走法和中国象棋中的马相似,走 “日” 字:即先向左(或右 ...