MBProgressHUD1.0.0源码解读

MBProgressHUD提示性的框架,每个app都有,用起来挺方便,最近想读读源码,一看别的框架那么多文件,就发愁,所以先找个简单的读。基本上都通读了吧,UI的实现及逻辑。用时三天左右。

MBProgressHUD的样式

MBProgressHUD1.0.0源码解读_第1张图片
43184065-019D-477D-913E-5E3A0F1ACCE1.png
 MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
    
    hud.label.text = @"Loading...";
    
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        [self doSomeWork];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });

MBProgressHUD1.0.0源码解读_第2张图片
33E59051-854A-4700-9D1F-34FB5A6DBC7F.png
  MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
    
    hud.label.text = @"Loading...";
    hud.detailsLabel.text = @"等着吧!";
    
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        [self doSomeWork];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
MBProgressHUD1.0.0源码解读_第3张图片
CBA79B7F-0476-41A2-B5A5-7F49280AD8F3.png
- (void)determinateExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
   //模式是圆环
    hud.mode = MBProgressHUDModeDeterminate;
    hud.label.text = @"Loading...";
    
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        
        [self doSomeWorkWithProgress];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

- (void)doSomeWorkWithProgress {
    self.canceled = NO;
    // This just increases the progress indicator in a loop.
    float progress = 0.0f;
    while (progress < 1.0f) {
        if (self.canceled)
        {
            NSLog(@"dfdfdfdf");
            break;
        }
        
        progress += 0.01f;
        dispatch_async(dispatch_get_main_queue(), ^{
            // Instead we could have also passed a reference to the HUD
            // to the HUD to myProgressTask as a method parameter.
            [MBProgressHUD HUDForView:self.navigationController.view].progress = progress;
        });
        usleep(50000);
    }
}

MBProgressHUD1.0.0源码解读_第4张图片
808F82DA-24D9-40EF-A9D5-294E4836D955.png
- (void)annularDeterminateExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
    hud.mode = MBProgressHUDModeAnnularDeterminate;
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");
    
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        [self doSomeWorkWithProgress];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}
MBProgressHUD1.0.0源码解读_第5张图片
F81AD0DB-74C3-472E-8A2B-109000F01FFC.png
  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];
        });
    });

首先它把所有的类都写在一个文件了。看起来文件不多。其实人家是没分开。我把它分开了。如图

MBProgressHUD1.0.0源码解读_第6张图片
09694016-D728-437C-835C-2508834180BE.png

我们一步一步的看它怎么走。这是最普通的,也是默认的样式,菊花转哈哈,大体的逻辑就是show之后hidden。

//   类方法创建一个hud
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
//   开启多线程执行一个任务
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        //耗时操作
        [self doSomeWork];
        
//      主线程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });

咱们先看看show。我们走进showHUDAddedTo看看

#pragma mark- 将hud加到这个view上,咱们传的是导航控制器的view,然后有动画效果
+ (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
    //创建hud
    MBProgressHUD *hud = [[self alloc] initWithView:view];
    //如果hud显示完了,消失后将hud移除
    hud.removeFromSuperViewOnHide = YES;
    //将hud加到view上
    [view addSubview:hud];
    //显示动画效果
    [hud showAnimated:animated];
    return hud;
}

去initWithView看看

- (id)initWithView:(UIView *)view {
    //断言,如果view是nil,就直接奔溃,NSAssert后面传两个参数如果第一个参数是no,直接奔了。yes那就继续走。
    NSAssert(view, @"View must not be nil.");
    //看: 它又去调用initWithFrame了,initWithView把它包装起来了,我看头文件把这个接口也开了,用户可以直接调用initWithView去创建一个hud。
    //view.bounds,咱们的hud跟传进来的view一样大
    return [self initWithFrame:view.bounds];
}

去initWithFrame看看,发现就是初始化commonInit

- (instancetype)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        //公共的初始化
        [self commonInit];
    }
    return self;
}

- (void)commonInit {
    // 1.设置一些默认的值
    //动画类型默认的是淡入淡出
    _animationType = MBProgressHUDAnimationFade;
    //hud模式:默认的菊花转
    _mode = MBProgressHUDModeIndeterminate;
    //边缘的距离
    _margin = 20.0f;
    //hud的不透明度1,就是yes
    _opacity = 1.f;
    //启用时,边框中心稍微有些设备加速度计数据的影响。在iOS < 7.0没有影响。默认值为YES,意思就是你晃动手机,hud会变化。
    _defaultMotionEffectsEnabled = YES;

    //默认的内容颜色,根据系统的版本确定
    BOOL isLegacy = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0;
    _contentColor = isLegacy ? [UIColor whiteColor] : [UIColor colorWithWhite:0.f alpha:0.7f];
    
    //透明的背景,先让hud看不见,等着show的时候再看到
    //opaque的讲解http://www.cnblogs.com/xiaofeixiang/p/5149765.html,如果是透明的,应该设置opaque为NO,默认是yes的
    self.opaque = NO;
    self.backgroundColor = [UIColor clearColor];
    self.alpha = 0.0f;
    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    self.layer.allowsGroupOpacity = NO;
    
    //初始化子控件
    [self setupViews];
    //更新指示器
    [self updateIndicators];
//   通知监听屏幕的旋转,来改变hud的frame
    [self registerForNotifications];
}

去setupViews看看,就是hud里的一些子控件,如文本了啥的。

- (void)setupViews {
    
    UIColor *defaultColor = self.contentColor;
    //没有模糊效果,透明的背景,跟hud一样大
    //这个类就是设置hud的背景,如果是iOS7以下背景就是一个普通颜色,如果是iOS7就用UIToolbar的毛玻璃效果,如果iOS7以上就用UIVisualEffectView作为毛玻璃
    MBBackgroundView *backgroundView = [[MBBackgroundView alloc] initWithFrame:self.bounds];
    backgroundView.style = MBProgressHUDBackgroundStyleSolidColor;
    backgroundView.backgroundColor = [UIColor clearColor];
    backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    backgroundView.alpha = 0.f;
    [self addSubview:backgroundView];
    //read属性,所以不能调用set方法,@property (strong, nonatomic, readonly) MBBackgroundView *backgroundView;不能再外头改。
    _backgroundView = backgroundView;
    
    
//   边框view,里头放有菊花,文字,进度条,模糊的
    MBBackgroundView *bezelView = [MBBackgroundView new];
    bezelView.translatesAutoresizingMaskIntoConstraints = NO;
    bezelView.layer.cornerRadius = 5.f;
    bezelView.alpha = 0.f;
    [self addSubview:bezelView];
    _bezelView = bezelView;
//  给bezelView加运动效果,当设备上下左右倾斜会产生视差效果
    [self updateBezelMotionEffects];
    //标题
    UILabel *label = [UILabel new];
    label.adjustsFontSizeToFitWidth = NO;
    label.textAlignment = NSTextAlignmentCenter;
    label.textColor = defaultColor;
    label.font = [UIFont boldSystemFontOfSize:MBDefaultLabelFontSize];
    label.opaque = NO;
    label.backgroundColor = [UIColor clearColor];
    _label = label;
    //标题详情
    UILabel *detailsLabel = [UILabel new];
    detailsLabel.adjustsFontSizeToFitWidth = NO;
    detailsLabel.textAlignment = NSTextAlignmentCenter;
    detailsLabel.textColor = defaultColor;
    detailsLabel.numberOfLines = 0;
    detailsLabel.font = [UIFont boldSystemFontOfSize:MBDefaultDetailsLabelFontSize];
    detailsLabel.opaque = NO;
    detailsLabel.backgroundColor = [UIColor clearColor];
    _detailsLabel = detailsLabel;
    
    UIButton *button = [MBProgressHUDRoundedButton buttonWithType:UIButtonTypeCustom];
    button.titleLabel.textAlignment = NSTextAlignmentCenter;
    button.titleLabel.font = [UIFont boldSystemFontOfSize:MBDefaultDetailsLabelFontSize];
    [button setTitleColor:defaultColor forState:UIControlStateNormal];
    _button = 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];
    }

    UIView *topSpacer = [UIView new];
    topSpacer.translatesAutoresizingMaskIntoConstraints = NO;
    topSpacer.hidden = YES;
    [bezelView addSubview:topSpacer];
    _topSpacer = topSpacer;

    UIView *bottomSpacer = [UIView new];
    bottomSpacer.translatesAutoresizingMaskIntoConstraints = NO;
    bottomSpacer.hidden = YES;
    [bezelView addSubview:bottomSpacer];
    _bottomSpacer = bottomSpacer;
}

去updateIndicators看看,这个里头主要是创建指示器的,比如你看到的菊花,进度条,选择不同的MBProgressHUDMode模式,展示的指示器不同。

- (void)updateIndicators {
    
//    typedef NS_ENUM(NSInteger, MBProgressHUDMode) {
//        /// 默认模式,使用系统自带的指示器 ,不能显示进度,只能是菊花不停地转呀转
//        MBProgressHUDModeIndeterminate,
//        /// 用饼图显示进度
//        MBProgressHUDModeDeterminate,
//        /// 进度条
//        MBProgressHUDModeDeterminateHorizontalBar,
//        /// 圆环
//        MBProgressHUDModeAnnularDeterminate,
//        /// 自定义视图
//        MBProgressHUDModeCustomView,
//        /// 只显示文字
//        MBProgressHUDModeText
//    };
    
    //先拿到指示器
    UIView *indicator = self.indicator;
    //指示器是菊花吗?
    BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]];
//  指示器是进度条吗?
    BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]];
//    获取hud的模式
    MBProgressHUDMode mode = self.mode;
//   默认模式
    if (mode == MBProgressHUDModeIndeterminate) {
        //如果不是菊花就走下面的代码
        if (!isActivityIndicator) {
            // Update to indeterminate indicator
            [indicator removeFromSuperview];
            indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
            [(UIActivityIndicatorView *)indicator startAnimating];
            [self.bezelView addSubview:indicator];
        }
    }
    // 进度条
    else if (mode == MBProgressHUDModeDeterminateHorizontalBar) {
        // 进度条
        [indicator removeFromSuperview];
        indicator = [[MBBarProgressView alloc] init];
        [self.bezelView addSubview:indicator];
    }
//    用饼图显示进度或者圆环
    else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) {
        if (!isRoundIndicator) {
            // Update to determinante indicator
            [indicator removeFromSuperview];
            indicator = [[MBRoundProgressView alloc] init];
            [self.bezelView addSubview:indicator];
        }
        if (mode == MBProgressHUDModeAnnularDeterminate) {
            [(MBRoundProgressView *)indicator setAnnular:YES];
        }
    }
//    自定义视图
    else if (mode == MBProgressHUDModeCustomView && self.customView != indicator) {
        // Update custom view indicator
        [indicator removeFromSuperview];
        indicator = self.customView;
        [self.bezelView addSubview:indicator];
    }
//     只显示文字
    else if (mode == MBProgressHUDModeText) {
        [indicator removeFromSuperview];
        indicator = nil;
    }
    indicator.translatesAutoresizingMaskIntoConstraints = NO;
    self.indicator = indicator;
//    如果是进度条就设置进度---用kvc
    if ([indicator respondsToSelector:@selector(setProgress:)]) {
        [(id)indicator setValue:@(self.progress) forKey:@"progress"];
    }

    [indicator setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisHorizontal];
    [indicator setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisVertical];
//  给hud的内容设置颜色。换皮肤
    [self updateViewsForColor:self.contentColor];
    
//    1.[layoutView setNeedsUpdateConstraints]:告诉layoutView需要更新约束,在下次计算或者更新约束会更新约束
//    2.[layoutView updateConstraintsIfNeeded]:告诉layoutView立即更新约束,
//    3.updateConstraints:系统更新约束的实际方法
//    4.[layoutView setNeedsLayout]:告诉layoutView页面需要更新,但不立即执行
//    5.[layoutView layoutIfNeeded]:告诉layoutView页面布局立即更新
//    6.layoutSubviews:系统重写布局的实际方法
//    stackoverflow上有关于上面几个方法的深入解答并分享了作者的实用经验:
//    如果仅想要立即改变约束,调用setNeedsLayout
//    如果改变view的一些属性(如offsets)可能会导致布局的改变,那么调用setNeedsUpdateConstraints,更多的时候后面需要加setNeedsLayout。
//    如果想要立即改变布局,如会形成新的frame,那么需要在调用layoutIfNeeded。
//    http://www.vienta.me/2015/05/18/AutoLayout-%E6%B5%85%E6%9E%90%E5%8A%A8%E7%94%BB%EF%BC%88III%EF%BC%89/
    [self setNeedsUpdateConstraints];
}

初始化说了一大堆。东西有点多啊。要有点耐心,我来回看了好几遍呢MBProgressHUD *hud = [[self alloc] initWithView:view];算是说完了,咱们接下来就看看这个[hud showAnimated:animated];看看hud怎么做动画的。

- (void)showAnimated:(BOOL)animated {
    //#define MBMainThreadAssert() NSAssert([NSThread isMainThread], @"MBProgressHUD needs to be accessed on the main thread.");
    //如果不是在主线程执行这段代码就直接奔溃了。
    MBMainThreadAssert();
    [self.minShowTimer invalidate];
//    全局的,记录下时候要动画
    self.useAnimation = animated;
    
//    hud--show没有完成。
//    get方法用self.finished和self.hasFinished都可以,set方法必须是finished。作用语意上更好理解。是否完成。
//    @property(nonatomic,assign,getter=hasFinished) BOOL finished;
    self.finished = NO;
    
    // graceTime默认是0,当你设置了值之后,如2s,那么hud会在2s之后显示。它的作用是防止任务非常短,hud显示后立马消失,体验效果不好。如果你的任务是在1s内完成,那么hud是不显示的。
    if (self.graceTime > 0.0) {
//        graceTimer作用就是延迟的去show HUD。
//        NSTimer的深入讲解看我的这个文章http://www.jianshu.com/p/19aab8570ce3
        NSTimer *timer = [NSTimer timerWithTimeInterval:self.graceTime target:self selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];
        //这种方式创建的timer是不会自动加入NSRunLoop的,得自己添加
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        self.graceTimer = timer;
    } 
//    如果graceTime是0的话,也就是没设置值,那就直接展示hud
    else {
        [self showUsingAnimation:self.useAnimation];
    }
}

去showUsingAnimation看看

- (void)showUsingAnimation:(BOOL)animated
{
    //删除之前的所有动画,防止动画引用view导致内存泄漏,我遇到过这个坑
    [self.bezelView.layer removeAllAnimations];
    [self.backgroundView.layer removeAllAnimations];

    [self.hideDelayTimer invalidate];
    
    //记录hud显示的日期,用来跟hide的date做计算,得出hud展示的时间
    self.showStarted = [NSDate date];
    self.alpha = 1.0f;
    
    //如果是进度条,那就用CADisplayLink来刷新它,每秒60次的频率来体现进度的变化。
    [self setNSProgressDisplayLinkEnabled:YES];
    
    if (animated) {
        [self animateIn:YES withType:self.animationType completion:nil];
    }else{
//    取消警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        self.bezelView.alpha = self.opacity;
#pragma clang diagnostic pop
        self.backgroundView.alpha = 1.f;
        
    }
    
}

[self animateIn:YES withType:self.animationType completion:nil];看看

/**
 @param animatingIn show就是yes,hide是no
 @param type 动画类型三种,淡入淡出,放大,缩小
 */
- (void)animateIn:(BOOL)animatingIn withType:(YBProgressHUDAnimation)type completion:(void(^)(BOOL finished))completion
{
    //自动确定正确的缩放动画类型
    if (type == YBProgressHUDAnimationZoom) {
        type = animatingIn ? YBProgressHUDAnimationZoomIn : YBProgressHUDAnimationZoomOut;
    }
    CGAffineTransform small = CGAffineTransformMakeScale(0.5f, 0.5f);
    CGAffineTransform large = CGAffineTransformMakeScale(1.5f, 1.5f);
    
    //设置开始的状态
    UIView *bezelView = self.bezelView;
    if (animatingIn && bezelView.alpha == 0.f && type == YBProgressHUDAnimationZoomIn) {
        bezelView.transform = small;
    }else if (animatingIn && bezelView.alpha == 0.f && type == YBProgressHUDAnimationZoomOut)
    {
        bezelView.transform = large;
    }
    
    //执行动画
    dispatch_block_t animations = ^{
        if (animatingIn) {
            bezelView.transform = CGAffineTransformIdentity;
        } else if (!animatingIn && type == YBProgressHUDAnimationZoomIn) {
            bezelView.transform = large;
        } else if (!animatingIn && type == YBProgressHUDAnimationZoomOut) {
            bezelView.transform = small;
        }
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        bezelView.alpha = animatingIn ? self.opacity : 0.f;
#pragma clang diagnostic pop
        self.backgroundView.alpha = animatingIn ? 1.f : 0.f;
    };
    
    //如果是iOS7+就执行spring动画,否则就执行下面的动画
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 || TARGET_OS_TV
    if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0) {
        [UIView animateWithDuration:0.3 delay:0. usingSpringWithDamping:1.f initialSpringVelocity:0.f options:UIViewAnimationOptionBeginFromCurrentState animations:animations completion:completion];
        return;
    }
#endif
    
    [UIView animateWithDuration:0.3 delay:0. options:UIViewAnimationOptionBeginFromCurrentState animations:animations completion:completion];
    
}

show方法就说完了。重点啥的都在代码的注释里了。

hide 让HUD消失

- (void)hideAnimated:(BOOL)animated {
    //如果要不是在主线程就奔溃(断言)
    YBMainThreadAssert();
    //把延迟显示hud的定时器销毁,因为showAnimated的时候如果graceTime>0会被创建.
    [self.graceTimer invalidate];
    self.useAnimation = animated;
    self.finished = YES;
    //如果设置了minShow时间,计算出HUD显示的时间长短interv,如果interv小于minShow,那么推迟隐藏,也就是minShow之后隐藏。这么做也是为了防止hud刚显示就隐藏导致效果不好。
    if (self.minShowTime > 0.0 && self.showStarted)
    {
        //任务所用的时间,这个就是通过show的日期和hide的日期差值得出来的
        NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:self.showStarted];
        if (interv < self.minShowTime)
        {
            //推迟隐藏hud
            NSTimer *timer = [NSTimer timerWithTimeInterval:(self.minShowTime - interv) target:self selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO];
            [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
            self.minShowTimer = timer;
            return;
        }
        
    }
    //立即隐藏hud
    [self hideUsingAnimation:self.useAnimation];
    
}

去hideUsingAnimation看看, [self animateIn:NO withType:self.animationType completion:^(BOOL finished)这个在show里讲了

- (void)hideUsingAnimation:(BOOL)animated {
    
    if (animated && self.showStarted) {
        self.showStarted = nil;
        [self animateIn:NO withType:self.animationType completion:^(BOOL finished) {
            [self done];
        }];
        
    }else{
        self.showStarted = nil;
        self.bezelView.alpha = 0.0f;
        self.backgroundView.alpha = 1.0f;
        [self done];
        
    }
    
}

看看done

- (void)done {
    //这个hideDelayTimer是hide方法执行后,延迟隐藏hud的,
    [self.hideDelayTimer invalidate];
    //将CADisplayLink给释放了
    [self setNSProgressDisplayLinkEnabled:NO];

    if (self.hasFinished) {
        self.alpha = 0.0f;
        //将hud移除
        if (self.removeFromSuperViewOnHide) {
            [self removeFromSuperview];
        }
    }
    //hide完hud后的回调,有block和delegate两种。
    MBProgressHUDCompletionBlock completionBlock = self.completionBlock;
    if (completionBlock) {
        completionBlock();
    }
    id delegate = self.delegate;
    if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
        [delegate performSelector:@selector(hudWasHidden:) withObject:self];
    }
}

CADisplayLink刷新

- (void)setNSProgressDisplayLinkEnabled:(BOOL)enabled {
   // 这里使用 CADisplayLink 来刷新progress的变化。因为如果使用kvo机制来监听的话可能会非常消耗主线程(因为频率可能非常快)。
    if (enabled && self.progressObject) {
        // Only create if not already active.
        if (!self.progressObjectDisplayLink) {
            self.progressObjectDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateProgressFromProgressObject)];
        }
    } else {
        self.progressObjectDisplayLink = nil;
    }
}

- (void)setProgressObjectDisplayLink:(CADisplayLink *)progressObjectDisplayLink {
    if (progressObjectDisplayLink != _progressObjectDisplayLink) {
        [_progressObjectDisplayLink invalidate];
        
        _progressObjectDisplayLink = progressObjectDisplayLink;
        //添加到NSRunLoop,主消息循环
        [_progressObjectDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    }
}

参考文章progresshttp://www.jianshu.com/p/c35a81c3b9eb

绘制进度条

MBProgressHUD的绘制都是在drawRect里的然后调用setNeedsDisplay刷新。这个没啥好说的。http://www.jianshu.com/p/d379dbcaa867

保护老属性

为了保护老的属性,做成@interface MBProgressHUD (Deprecated)分类。在分类的属性的set和get方法里设置新属性和返回新属性,在你用分类的属性的时候给你提示这个属性弃用,用新的。如这个demo

#import 

@interface Person : NSObject

@property(nonatomic,strong)NSString *name;

@end

@interface Person (Dep)

@property(nonatomic,strong)NSString *namehaha;

@end


#import "Person.h"

@implementation Person



@end


@implementation Person (Dep)

- (NSString *)namehaha{
    
    return self.name;
    
}

- (void)setNamehaha:(NSString *)namehaha
{
    self.name = namehaha;
}


@end

收获的知识

  1. 哪些接口哪些属性需要开放。哪些是在属性里强制read的。保护其封装性。

  2. graceTimer,hideDelayTimer,minShowTimer用的到位。

  3. 高频率刷新CADisplayLink的使用。

  4. NSAssert断言的使用。

5.为了保护老的属性,做成@interface MBProgressHUD (Deprecated)分类。在分类的属性的set和get方法里设置新属性和返回新属性,在你用分类的属性的时候给你提示这个属性弃用,用新的,这个第一次看见。很好支持之后的版本。还可以这么用啊。佩服。

总结

好几次看的实在是麻烦,想想如果我看完了它,会成长好多,以后其他的三方简单的控件就会简单很多。其实看框架也是磨性子的过程。让我能够静下心来去学习一些东西。

你可能感兴趣的:(MBProgressHUD1.0.0源码解读)