美文网首页iOS Developer
MBProgressHUD1.0.0源码解读

MBProgressHUD1.0.0源码解读

作者: charlotte2018 | 来源:发表于2017-07-28 19:32 被阅读46次

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

    MBProgressHUD的样式

    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];
            });
        });
    
    
    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];
            });
        });
    
    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);
        }
    }
    
    
    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];
            });
        });
    }
    
    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];
            });
        });
    

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

    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<MBProgressHUDDelegate> 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 <Foundation/Foundation.h>
    
    @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源码解读

        本文链接:https://www.haomeiwen.com/subject/qvaxlxtx.html