MJRefresh源码阅读3——干货整理

前言

MJRefresh源码阅读1——结构梳理
MJRefresh源码阅读2——核心类MJRefreshHeader
前面这两篇已经大概梳理清楚了MJRefresh的实现逻辑,但是里面还有一些知识点仍值得我们好好整理整理,以便以后温习。


UIKIT_EXTERN 和 extern的区别:

MJRefresh控件专门新建了MJRefreshConst文件来在里面定义了需要用到的宏和全局常量。说起全局常量,在《52个有效方法》笔记1——熟悉Objective-C这篇笔记里已经说过了如何定义一个全局常量,即以extern关键字为前缀。但是在MJRefresh中却以UIKIT_EXTERN关键字取代了extern

.h文件中:

UIKIT_EXTERN NSString *const MJRefreshHeaderStateIdleText;

.m文件中:

NSString *const MJRefreshHeaderStateIdleText = @"下拉可以刷新";

UIKIT_EXTERNextern到底有什么不同呢?
我们点击发现跳入了UIKitDefines.h宏定义文件的下面几行代码:

#ifdef __cplusplus
#define UIKIT_EXTERN        extern "C" __attribute__((visibility ("default")))
#else
#define UIKIT_EXTERN            extern __attribute__((visibility ("default")))
#endif

下面是我收集到的一段解释资料:

其中__cplusplus 是cpp中的自定义宏,那么定义了这个宏的话表示这是一段cpp的代码,也就是说,上面的代码的含义是:如果这是一段cpp的代码,那么加入extern"C"和其中的代码。

extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。

那extern "C"呢?C++之父在设计C++之时,考虑到当时已经存在了大量的C代码,为了支持原来的C代码和已经写好C库,需要在C++中尽可能的支持C,而 extern "C"就是其中的一个策略。

attribute是GNU C的一种机制,用法为attribute_ ((attribute-list))。当项目需要作为一个库被外包引用的时候通常在编译时可以用参数-fvisibility指定所有符号的可见性。在编译命令中加入 -fvisibility=hidden参数,会将所有默认的public的属性变为hidden。此时,如果对函数设置attribute((visibility ("default")))参数,使特定的函数仍然按默认的public属性处理,则-fvisibility=hidden参数不会对该函数起作用。所以,设置了-fvisibility=hidden参数之后,只有设置了attribute((visibility ("default")))的函数才是对外可见的。

用一句话说就是,UIKIT_EXTERN而不用extern是因为它兼容C++的代码。


利用Method Swizzing调换方法的实现:

关于Method Swizzing,以前已经记过笔记,不想再赘述。
请查看这篇笔记:《52个有效方法》笔记3——探究runtime


善用分类提供便捷的语法糖:

首先MJRefresh就是以UIScrollView的分类的形式给tableView添加了header,可以说这种以分类对原有类进行扩展的方式非常优雅。但不仅如此,我们发现在源码中还可以看到其他两个分类:UIView+MJExtensionUIScrollView+MJExtension
比如UIView+MJExtension可以很便捷地访问/修改所有UIView的坐标尺寸属性。我自己也写了一遍:

@interface UIView (YWFrame)
@property (nonatomic, assign) CGFloat   yw_x;
@property (nonatomic, assign) CGFloat   yw_y;
@property (nonatomic, assign) CGPoint   yw_origin;
@property (nonatomic, assign) CGFloat   yw_width;
@property (nonatomic, assign) CGFloat   yw_height;
@property (nonatomic, assign) CGSize    yw_size;

// 布局
@property (nonatomic, assign, readonly) CGFloat   yw_top;
@property (nonatomic, assign, readonly) CGFloat   yw_bottom;
@property (nonatomic, assign, readonly) CGFloat   yw_left;
@property (nonatomic, assign, readonly) CGFloat   yw_right;
@end
#import "UIView+YWFrame.h"

@implementation UIView (YWFrame)

- (CGFloat)yw_x
{
    return self.frame.origin.x;
}
- (void)setYw_x:(CGFloat)yw_x
{
    CGRect frame = CGRectZero;
    frame.origin.x = yw_x;
    self.frame = frame;
}

- (CGFloat)yw_y
{
    return self.frame.origin.y;
}
- (void)setYw_y:(CGFloat)yw_y
{
    CGRect frame = CGRectZero;
    frame.origin.y = yw_y;
    self.frame = frame;
}

- (CGPoint)yw_origin
{
    return self.frame.origin;
}
- (void)setYw_origin:(CGPoint)yw_origin
{
    CGRect frame = CGRectZero;
    frame.origin = yw_origin;
    self.frame = frame;
}

- (CGFloat)yw_width
{
    return self.frame.size.width;
}
- (void)setYw_width:(CGFloat)yw_width
{
    CGRect frame = CGRectZero;
    frame.size.width = yw_width;
    self.frame = frame;
}

- (CGFloat)yw_height
{
    return self.frame.size.height;
}
- (void)setYw_height:(CGFloat)yw_height
{
    CGRect frame = CGRectZero;
    frame.size.height = yw_height;
    self.frame = frame;
}

- (CGSize)yw_size
{
    return self.frame.size;
}
- (void)setYw_size:(CGSize)yw_size
{
    CGRect frame = CGRectZero;
    frame.size = yw_size;
    self.frame = frame;
}


- (CGFloat)yw_top
{
    return self.frame.origin.y;
}

- (CGFloat)yw_bottom
{
    return self.yw_top+self.yw_height;
}

- (CGFloat)yw_left
{
    return self.frame.origin.x;
}

- (CGFloat)yw_right
{
    return self.yw_left+self.yw_width;
}
@end

在layoutSubviews方法里调整布局:

MJRefresh源码中header的子视图创建后并未给设置坐标尺寸,而是在layoutSubviews方法里统一设置调整的。
说起layoutSubviews方法,我们平时比较少用,但是在网上又经常看到它的身影。它究竟是用来干嘛的?它的执行时机是什么?

layoutSubviews的作用:
layoutSubviews是对子视图重新布局。比如,我们想更新子视图的位置的时候,可以通过调用layoutSubviews方法,即可以实现对子视图重新布局。
layoutSubviews默认是不做任何事情的,用到的时候,需要在自类进行重写。

layoutSubviews以下情况会被调用:
1.调用setNeedsLayout方法时会触发执行;
2.初始化不会触发layoutSubviews,但是如果设置了不为CGRectZeroframe的时候就会触发;
3.addSubview:时会触发;
4.viewframe发生改变时会触发;
5.滚动scrollView是会触发;
6.旋转屏幕时会触发。

正如第1种情况,源码中就是在设置子视图的可见性的,重写的setter方法中调用了setNeedsLayout方法。因为当设置header上某子视图隐藏时,同时header上剩下的子视图的布局要发生调整。

- (void)setStateHidden:(BOOL)stateHidden
{
    _stateHidden = stateHidden;
    
    self.stateLabel.hidden = stateHidden;
    [self setNeedsLayout];
}

userInteractionEnabled属性:

简单的说,该属性控制某UIView是否接受并响应用户的交互事件。若为YES,则依照响应链响应事件;若为NO,则代表其不接受交互事件,就像视图层级中没有它一样,UIView会跳过它响应事件。

有两种在开发中经常遇到的事件不响应的情况:

情况一:UIImageView上添加按钮,点击按钮是不会响应事件的,因为UIImageView的这个属性默认是NO,需要将其userInteractionEnabled属性设为YES才行。
情况二:UIButton上覆盖有层透明的view,此时,UIButton是不能响应事件的,需要将该覆盖在上面的viewuserInteractionEnabled属性设为NO才行。


动画配置属性(UIViewAnimationOptions):

在动画执行过程中,默认所有的子视图都是禁止用户交互的,但是你可以通过设置动画的配置属性为UIViewAnimationOptionAllowUserInteraction来允许在UIView动画时响应用户交互,使得UIView在执行动画期间依然能够响应用户事件。

事实上,我们可以给UIView动画的配置属性进行很多配置,详情见:UIViewAnimationOptions类型


日历(NSCalendar):

iOS-时间与日期详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,025评论 4 62
  • Core Animation基础 Core Animation 利用了硬件加速和架构上的优化来实现快速渲染和实时动...
    独木舟的木阅读 1,526评论 0 3
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,125评论 29 470
  • 我们农村人都是比较憨厚老实的,一次一位大妈进城去买衣裳,刚进一家时尚服装店,絮絮叨叨说了半天(大妈是北方人,方言重...
    快乐的Alina阅读 306评论 0 1
  • 区块链的投资机会远远大于其他投资机会。 笑来持有六位数的比特币,当时价值每块5000元。 比特币不依赖任何组织机构...
    3公里对阅读 563评论 0 2