SwiftLint
SwiftLint 介绍
- SwiftLint 是
Realm
推出的一款Swift
代码规范检查工具,SwiftLint
基于 Github 公布的 Swift 代码规范 进行代码检查,并且能够很好的和 Xcode 整合 - 配置好所有的设置之后,在
Xcode
中执行编译时,SwiftLint
会自动运行检查,不符合规范的代码会通过警告
或者红色错误
的形式指示出来 - 支持自定义规则,可禁用或者开启某一些规则
Stay Hungry, Stay Foolish
Realm
推出的一款 Swift
代码规范检查工具, SwiftLint
基于 Github 公布的 Swift 代码规范 进行代码检查,并且能够很好的和 Xcode 整合Xcode
中执行编译时,SwiftLint
会自动运行检查,不符合规范的代码会通过 警告
或者 红色错误
的形式指示出来⛵️ URLNavigator 是 Swift 下一个优雅的 URL 路由。它提供了通过 URL 导航到 view controller 的方式。URL 参数的对应关系通过
URLNavigator.register(_:_:)
方法进行设置。URLNavigator 提供了两种方法来设置 URL 参数的对应关系:URLNavigable 和 URLOpenHandler。URLNavigable 通过自定义的初始化方法进行设置,URLOpenHandler 通过一个可执行的闭包进行设置。初始化方法和闭包都接受一个
URL
和占位符
值。
URL 模式可以包含多个占位符。占位符将会被匹配的 URL 中的值替换。使用 <
和 >
来设置占位符。占位符的类型可以设置为:string(默认)
, int
, float
, 和 path
。
例如,myapp://user/<int:id>
将会和下面的 URL 匹配:
myapp://user/123
myapp://user/87
但是,无法和下面的 URL 配置:
myapp://user/devxoul
(类型错误,需要 int)myapp://user/123/posts
(url 的结构不匹配))/user/devxoul
(丢失 scheme)安装 homebrew
,已安装的跳过
1 | $ ruby -e"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" |
安装 ffmpeg
1 | $ brew install ffmpeg |
下载m3u8->mp4
1 | $ ffmpeg -i 视频地址 [输出的文件名.mp4] |
等待下载完成…
常用苹果开发者网页:
注:链接需要先登陆开发者账号才能打开
Masonry是一个轻量级的布局框架,它使用更好的语法包装AutoLayout。 Masonry有自己的布局DSL,它提供了一种描述NSLayoutConstraints的可链接方式,从而使布局代码更简洁,更易读。 Masonry支持iOS和Mac OS X。
先看一下,如果使用原生的 AutoLayout,需要那些代码
子视图离父视图上下左右各有10个像素的间距
1 | UIView *superview = self.view; |
但如果使用 Masonry
的话,代码量以及阅读起来都十分可观
1 | UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10); |
是不是非常简洁,调用起来方便,阅读起来也清晰明了
Masonry 会自动将约束添加到适当的视图中, 且自动调用 view1.translatesAutoresizingMaskIntoConstraints = NO;
看一下 mas_makeConstraints 方法声明
1 | - (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block; |
这个方法传递的参数是一个参数为 MASConstraintMaker
类型的无返回值的 block
,而该方法的返回值则是一个数组。
方法声明中我们看到了一个叫做 NS_NOESCAPE
的宏,NS_NOESCAPE
用于修饰方法中的 block 类型参数,作用是告诉编译器,该 block 在方法返回之前就会执行完毕,而不是被保存起来在之后的某个时候再执行。编译器被告知后,就会相应的进行一些优化。更详细的内容请参考 Add @noescape to public library API
看一下 mas_makeConstraints 方法实现
1 | - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block { |
看一下 MASConstraintMaker
的 init 方法
1 | @interface MASConstraintMaker () <MASConstraintDelegate> |
看一下 block(constraintMaker); 将 constraintMaker
传递给我们,方便使用属性添加约束
1 | make.top.equalTo(superview.mas_top).with.offset(padding.top); |
看下 make.top
make 是 MASConstraintMaker 类型的对象,这个类型封装了一系列只读 MASConstraint 属性,top 就是其中之一,声明和实现如下:
1 | @property (nonatomic, strong, readonly) MASConstraint *top; |
addConstraintWithLayoutAttribute
方法的实现如下:
1 | - (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { |
再来看下 equalTo
方法,也是用 MASConstraint 调用的,并且返回 MASConstraint 对象,方便链式调用1
2
3
4
5
6
7
8
9
10
11
12
13- (MASConstraint * (^)(id attr))equalTo;
- (MASConstraint * (^)(id))equalTo {
return ^id(id attribute) {
return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
};
}
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation { MASMethodNotImplemented(); }
#define MASMethodNotImplemented() \
//
@throw [NSException exceptionWithName:NSInternalInconsistencyException \
reason:[NSString stringWithFormat:@"You must override %@ in a subclass.", NSStringFromSelector(_cmd)] \
userInfo:nil]
而我们在 makeConstraints 的时候,实际调用的是 MASViewConstraint 这个 MASConstraint 子类中的实现:
1 | - (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation { |
该方法接收两个参数,一个表示了对应的属性(mas_top),一个表示了相等关系(NSLayoutRelationEqual),进入方法后会先对我们传入的属性做一个类型判断,我们传入的是一个单个的属性,所以会落入 else 分支,同样是依赖断言做了一系列保护性的判断,并将相等关系和视图属性分别赋值给 layoutRelation 和 secondViewAttribute 属性,并返回 self。
返回 self,看似简简单单的一个操作,却是 Masonry 能够实现链式 DSL 最重要的基石。
superview.mas_top
再来看看传入的 mas_top,这是一个声明在 View+MASAdditions.h 当中的只读属性:
1 | @property (nonatomic, strong, readonly) MASViewAttribute *mas_top; |
.with
1 | - (MASConstraint *)with { |
.offset
1 | - (MASConstraint * (^)(CGFloat offset))offset; |
在配置好想要的约束后,调用 [constraintMaker install];
对视图施加约束
1 | - (NSArray *)install { |
对 constraints 属性做一份 copy后,遍历 constraints 中的所有 MASConstraint 及其子类型的属性,并调用其 install 方法:
1 | - (void)install { |
1 | @implementation UIImage (GIF) |
SDImageCache 是 SDWebImage 中用来处理缓存的类,他是一个单例
SDWebImage 中关于缓存可以分为磁盘缓存 id<SDDiskCache>
和 内存缓存 id<SDMemoryCache>
1 | @interface SDImageCache () |
1 | // 查询缓存操作 |
SDImageCacheConfig 是一个关于缓存设置相关的类
1 | - (instancetype)init { |
SDMemoryCache 继承自 NSCache,实现了 SDMemoryCache 协议,封装了一系列方法,便于扩展
1 | @interface SDMemoryCache <KeyType, ObjectType> : NSCache <KeyType, ObjectType> <SDMemoryCache> |
SDMemoryCache 也使用 NSMapTable 来储存缓存的数据,并加了锁来保证线程安全
那为什么 SDMemoryCache 继承自 NSCache 还要维护一个 NSMapTable 呢,因为 NSCache 对于 value 是强引用的,而 NSMapTable 对于value 是弱引用的!
可以通过config 的 shouldUseWeakMemoryCache 来关闭使用 NSMapTable 管理。
SDMemoryCache 实现了 SDDiskCache 协议,封装了一系列方法,便于扩展
SDWebImage具有缓存支持的异步映像下载程序。并添加了像UI元素分类UIImageView、UIButton、MKAnnotationView,可以直接为这些UI元素添加图片。
功能
支持的图片格式
更多模块
查看 Github,有许多基于 SDWebImage 的三方库。
SDWebImage架构图
时序图
从SDWebImage中提供的架构图中我们可以大概的看出,整个库分为两层,Top Level、Base Module。
核心类
面向UIImageView的是UIImageView+WebCache这个分类,将图片的URL,占位图片直接给这个类,该类提供众多的设置方法,不过最后都会调用以下这个方法.
1 |
|
最后进入的是 UIView+WebCache 的 sd_internalSetImageWithURL方法中
1 |
|
UIView+WebCache通过关联为UIView扩展了几个属性
UIView+WebCacheOperation
中为UIView通过关联添加了一个 sd_operationDictionary
属性,是一个 MapTable
列表,类似于字典<Key:id
主要提供一下几个方法
1 | /// 通过key获取图片下载操作 |
SDWebimageDefine.h -> SDWebImageOptions
1 | typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { |
SDWebImageManager
上面关于图片缓存和下载的调用的是SDWebImageManager里面的方法
1 | SDWebImageManager.m |
大概流程
1 | // 1.判断并处理url |
SDWebImageCombinedOperation 实现了 SDWebImageOperation 代理,而 SDWebImageOperation 里面只有一个cancel方法,上面那个NSMapTable里面的value 类型是 id
1 | /// 取消当前的operation任务 |
YYDiskCache是一个线程安全的缓存,用于存储SQLite支持的键值对和文件系统(类似于NSURLCache的磁盘缓存)。
YYDiskCache具有以下功能:
所以 YYDiskCache 磁盘缓存又分为 文件缓存 和 数据库缓存
1 | /// 根据这个属性进行区分,当大于该值时使用数据库缓存,小于该值使用文件缓存 |
YYDiskCache 维护一个 NSMapTable(Path : YYDiskCache) 来进行缓存操作
NSMapTable: 类似于 NSDictionary 但是可以指定key-value的引用类型,当value的引用类型为 weak 时,当 value 为 nil 时,自动删除key-value
1 | /// 初始化 |
YYDiskCache 使用信号量进行加锁解锁操作。
dispatch_semaphore_t GCD 中信号量,也可以解决资源抢占问题,支持信号通知和信号等待。每当发送一个信号通知,则信号量 +1;每当发送一个等待信号时信号量 -1,;如果信号量为 0 则信号会处于等待状态,直到信号量大于 0(或者超时) 开始执行之后代码。
YYDishCache 使用 YYKVStorage 进行文件缓存处理,并自定义了淘汰算法,删除那些最近时间段内不常用的对象。类似于 YYMemoryCache 与 _YYLinkMap 的关系。
1 | @implementation YYDiskCache { |
1 | // 需要通过Path进行初始化 |
YYDiskCache 在初始化时也会进行一个递归调用的边界检查任务
1 | - (void)_trimRecursively { |
分别调用 YYKVStorage
的相应方法
注意
YYKVStorage是一个基于sqlite和文件系统的键值存储。但作者不建议我们直接使用此类(ps:这个类被封装到了YYDiskCache里,可以通过YYDiskCache间接使用此类),这个类只有一个初始化方法,即initWithPath:type:,初始化后,讲根据path创建一个目录来保存键值数据,初始化后,如果没有得到当前类的实例对象,就表示你不应该对改目录进行读写操作。最后,作者还写了个警告,告诉我们这个类的实例对象并不是线程安全的,你需要确保同一时间只有一条线程访问实例对象,如果你确实需要在多线程中处理大量数据,可以把数据拆分到多个实例对象当中去。
YYKVStorage: YYDiskCache 操作数据的工具类。 YYKVStorage 实现了 文件缓存 和 数据库缓存 功能。可以像操作字典一样使用 key-value 操作数据。
1 | typedef NS_ENUM(NSUInteger, YYKVStorageType) { |
1 | @interface YYKVStorageItem : NSObject |
1 | - (instancetype)initWithPath:(NSString *)path type:(YYKVStorageType)type { |
文件结构
1 | /* |
增
文件名不存在,存数据库类型或者混合存储类型
1 | - (BOOL)saveItemWithKey:(NSString *)key value:(NSData *)value filename:(NSString *)filename extendedData:(NSData *)extendedData { |
删
1 | - (BOOL)removeItemForKey:(NSString *)key { |
查
_db...
直接操作sqlite数据库,又想了解的自己去看,挺全面的
一直想写一写自己读源码的感受与理解,可惜一直未付诸行动。最近闲来无事,索性整理一下,记录于此.
YYCahce 包括 内存缓存(YYMemoryCache) 与 磁盘缓存(YYDiskCache), 而且都是线程安全的!
YYMemoryCache用于对内存缓存进行管理,因为需要高效查询数据,所以 key-value 模式储存。为什么不直接使用字典呢,因为需要保证线程安全。而为什么不直接使用 NSCache 呢,因为 YYMemoryCache 基于自定义的双向链表,提供一种 LRU(least-recently-used: 最近最久少使用的会先删除)
淘汰算法去操作缓存,进行性能优化。