DZNEmptyDataSet框架阅读

#import <DZNEmptyDataSet/UIScrollView+EmptyDataSet.h>
self.tableView.emptyDataSetSource = self;
self.tableView.emptyDataSetDelegate = self;
self.tableView.emptyDataSetSource = self;
OBJC_EXPORT id _Nullable
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
平时用的runtime函数交换方法会改变原始函数的方法名,其对应的C函数就是参数SEL。
void method_exchangeImplementations(方法m1,方法m2)
- (void)setEmptyDataSetSource:(id<DZNEmptyDataSetSource>)datasource
{
if (!datasource || ![self dzn_canDisplay]) {
[self dzn_invalidate];
} objc_setAssociatedObject(self, kEmptyDataSetSource, [[DZNWeakObjectContainer alloc] initWithWeakObject:datasource], OBJC_ASSOCIATION_RETAIN_NONATOMIC); // We add method sizzling for injecting -dzn_reloadData implementation to the native -reloadData implementation
[self swizzleIfPossible:@selector(reloadData)]; // Exclusively for UITableView, we also inject -dzn_reloadData to -endUpdates
if ([self isKindOfClass:[UITableView class]]) {
[self swizzleIfPossible:@selector(endUpdates)];
}
}
static NSMutableDictionary *_impLookupTable;
static NSString *const DZNSwizzleInfoPointerKey = @"pointer";
static NSString *const DZNSwizzleInfoOwnerKey = @"owner";
static NSString *const DZNSwizzleInfoSelectorKey = @"selector"; - (void)swizzleIfPossible:(SEL)selector
{
// Check if the target responds to selector
if (![self respondsToSelector:selector]) {
return;
} // Create the lookup table
if (!_impLookupTable) {
_impLookupTable = [[NSMutableDictionary alloc] initWithCapacity:]; // 3 represent the supported base classes
} // We make sure that setImplementation is called once per class kind, UITableView or UICollectionView.
for (NSDictionary *info in [_impLookupTable allValues]) {
Class class = [info objectForKey:DZNSwizzleInfoOwnerKey];
NSString *selectorName = [info objectForKey:DZNSwizzleInfoSelectorKey]; if ([selectorName isEqualToString:NSStringFromSelector(selector)]) {
if ([self isKindOfClass:class]) {
return;
}
}
}
//1.根据target 返回对应的类class
Class baseClass = dzn_baseClassToSwizzleForTarget(self);
//2.根据class名和selector,创建一个dzn_implement组合key
NSString *key = dzn_implementationKey(baseClass, selector);
//3.根据class名和selector组合key,拿到交换的implement指针。
NSValue *impValue = [[_impLookupTable objectForKey:key] valueForKey:DZNSwizzleInfoPointerKey]; // If the implementation for this class already exist, skip!!
if (impValue || !key || !baseClass) {
return;
} // Swizzle by injecting additional implementation
Method method = class_getInstanceMethod(baseClass, selector);
//4.将C函数dzn_original_implementation设置成Selector的新的IMP,并返回旧的IMP指针。
IMP dzn_newImplementation = method_setImplementation(method, (IMP)dzn_original_implementation); // Store the new implementation in the lookup table(源码注解错误,应该是old implementation,可以点击函数method_setImplementation查看验证)
// 存储旧的reload涵数指针IMP到全局查询表_impLookupTable (正确注释)
NSDictionary *swizzledInfo = @{DZNSwizzleInfoOwnerKey: baseClass,
DZNSwizzleInfoSelectorKey: NSStringFromSelector(selector),
DZNSwizzleInfoPointerKey: [NSValue valueWithPointer:dzn_newImplementation]}; [_impLookupTable setObject:swizzledInfo forKey:key];
}
void dzn_original_implementation(id self, SEL _cmd)
{
// Fetch original implementation from lookup table
Class baseClass = dzn_baseClassToSwizzleForTarget(self);
NSString *key = dzn_implementationKey(baseClass, _cmd); NSDictionary *swizzleInfo = [_impLookupTable objectForKey:key];
NSValue *impValue = [swizzleInfo valueForKey:DZNSwizzleInfoPointerKey]; IMP impPointer = [impValue pointerValue]; // We then inject the additional implementation for reloading the empty dataset
// Doing it before calling the original implementation does update the 'isEmptyDataSetVisible' flag on time.
[self dzn_reloadEmptyDataSet]; // If found, call original implementation
if (impPointer) {
((void(*)(id,SEL))impPointer)(self,_cmd);
}
}
- (void)dzn_reloadEmptyDataSet
//空白视图添加方法
if (!view.superview) {
// Send the view all the way to the back, in case a header and/or footer is present, as well as for sectionHeaders or any other content
if (([self isKindOfClass:[UITableView class]] || [self isKindOfClass:[UICollectionView class]]) && self.subviews.count > ) {
[self insertSubview:view atIndex:];
}
else {
[self addSubview:view];
}
} //更新内部子视图约束
[view setupConstraints];
- (void)setupConstraints
{
// First, configure the content view constaints
// The content view must alway be centered to its superview
NSLayoutConstraint *centerXConstraint = [self equallyRelatedConstraintWithView:self.contentView attribute:NSLayoutAttributeCenterX];
NSLayoutConstraint *centerYConstraint = [self equallyRelatedConstraintWithView:self.contentView attribute:NSLayoutAttributeCenterY]; [self addConstraint:centerXConstraint];
[self addConstraint:centerYConstraint];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options: metrics:nil views:@{@"contentView": self.contentView}]]; // When a custom offset is available, we adjust the vertical constraints' constants
if (self.verticalOffset != && self.constraints.count > ) {
centerYConstraint.constant = self.verticalOffset;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *hitView = [super hitTest:point withEvent:event]; // Return any UIControl instance such as buttons, segmented controls, switches, etc.
if ([hitView isKindOfClass:[UIControl class]]) {
return hitView;
} // Return either the contentView or customView
if ([hitView isEqual:_contentView] || [hitView isEqual:_customView]) {
return hitView;
} return nil;
}
静态类结构

DZNEmptyDataSet框架阅读的更多相关文章
- DZNEmptyDataSet框架简介
给大家推荐一个设置页面加载失败时显示加载失败等的框架. 下载地址:DZNEmptyDataSet https://github.com/dzenbot/DZNEmptyDataSet 上效果首先在你的 ...
- 软件体系架构之ssh框架阅读笔记
首先我们要了解一下什么是ssh框架? SSH是 struts+spring+hibernate的一个集成框架,是目前比较流行的一种Web应用程序开源框架. ssh框架系统从职责上分为四层:web层 业 ...
- DRF框架和Vue框架阅读目录
Vue框架目录 (一)Vue框架(一)——Vue导读.Vue实例(挂载点el.数据data.过滤器filters).Vue指令(文本指令v-text.事件指令v-on.属性指令v-bind.表单指令v ...
- ios开发——实用技术篇OC篇&iOS的主要框架
iOS的主要框架 阅读目录 Foundation框架为所有的应用程序提供基本系统服务 UIKit框架提供创建基于触摸用户界面的类 Core Data框架管着理应用程序数据模型 Core ...
- 深入理解jQuery框架-框架结构
这是本人结合资料视频总结出来的jQuery大体框架结构,如果大家都熟悉了之后,相信你们也会写出看似高档的js框架: jquery框架的总体结构 (function(w, undefined){ //定 ...
- jQuery源代码框架思路
開始计划时间读源代码,第一节jQuery框架阅读思路整理 (function(){ jQuery = function(){}; jQuery一些变量和函数和给jQuery对象加入一些方法和属性 ex ...
- Spring源码分析专题 —— 阅读指引
阅读源码的意义 更深入理解框架原理,印象更深刻 学习优秀的编程风格.编程技巧.设计思想 解决实际问题,如修复框架中的bug,或是参考框架源码,结合实际业务需求编写一个独有的框架 阅读源码的方法 首先是 ...
- 一步步去阅读koa源码,整体架构分析
阅读好的框架的源码有很多好处,从大神的视角去理解整个框架的设计思想.大到架构设计,小到可取的命名风格,还有设计模式.实现某类功能使用到的数据结构和算法等等. 使用koa 其实某个框架阅读源码的时候,首 ...
- 结合个人经历总结的前端入门方法 (转自https://github.com/qiu-deqing/FE-learning)
结合个人经历总结的前端入门方法 (https://github.com/qiu-deqing/FE-learning),里面有很详细的介绍. 之前一直想学习前端的,都不知道怎么下手都一年了啥也没学到, ...
随机推荐
- HDU1711 Number Sequence 题解 KMP算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711 题目大意:最基础的字符串匹配,只不过这里用整数数组代替了字符串. 给你两个数组 \(a[1..N ...
- HDU 1286
欧拉函数 φ函数的值 通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数.φ(1)=1 ...
- Git篇
安装之后第一步 安装 Git 之后,你要做的第一件事情就是去配置你的名字和邮箱,因为每一次提交都需要这些信息: git config --global user.name "bukas&qu ...
- P1041 查找元素
题目描述 现在告诉你一个长度为 \(n\) 的有序数组 \(a_1, a_2, ..., a_n\) ,以及 \(q\) 次询问,每次询问会给你一个数 \(x\) ,对于每次询问,你需要确定在数组中是 ...
- 2018.12.7 浪在ACM 集训队第八次测试赛
2018.12.7 浪在ACM 集训队第八次测试赛 https://blog.csdn.net/QLU_minoz/article/details/84886717 感谢苗学林同学C题和D题题解 ...
- <mvc:annotation-driven /><context:annotation-config/><context:component-scan/>
<context:annotation-config/> 隐式地向 Spring容器注册AutowiredAnnotationBeanPostProcessor. RequiredAnno ...
- 2018-8-10-win10-uwp-获得缩略图
title author date CreateTime categories win10 uwp 获得缩略图 lindexi 2018-08-10 19:16:51 +0800 2018-2-13 ...
- Spring注解之@Autowired、@Qualifier、@Resource、@Value
前言 @Autowired.@Qualifier.@Resource.@Value四个注解都是用于注入数据的,他们的作用就和在xml配置文件中的bean标签中写一个标签的作用是一样的!本篇中特别要讲解 ...
- windows系统下的maven项目放到linux系统中运行时报org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnection这种异常的解决办法
这个错误的解决办法其实很简单你把连接mysql数据库的那个jar包换成linux版本的就行了: linux版本的连接mysql数据库的jar包链接:http://files.cnblogs.com/f ...
- DOCKER学习_006:Docker存储驱动
一 镜像的分层特性 在说docker的文件系统之前,我们需要先想清楚一个问题.我们知道docker的启动是依赖于image,docker在启动之前,需要先拉取image,然后启动.多个容器可以使用同一 ...