YYCache 源码分析(一)
iOS 开发中总会用到各种缓存,YYCache或许是你最好的选择。性能上有优势,用法也很简单。作者ibireme曾经对比过同类轮子:http://blog.ibireme.com/2015/10/26/yycache/
1.简单架构图
2.YYCache.h方法分析
@interface YYCache : NSObject
// 读取当前数据库名称
@property (copy, readonly) NSString *name;
// memoryCache内存缓存,diskCache文件缓存
@property (strong, readonly) YYMemoryCache *memoryCache;
@property (strong, readonly) YYDiskCache *diskCache;
// 可通过下面三种方法来实例化YYCache对象
- (nullable instancetype)initWithName:(NSString *)name;
- (nullable instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER;
+ (nullable instancetype)cacheWithPath:(NSString *)path;
// 禁止通过下面两个方式实例化对象
- (instancetype)init UNAVAILABLE_ATTRIBUTE;
+ (instancetype)new __attribute__((unavailable("new方法不可用,请用initWithName:")));
// 通过key判断是否缓存了某个东西,第二个法是异步执行,异步回调
- (BOOL)containsObjectForKey:(NSString *)key;
- (void)containsObjectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key, BOOL contains))block;
// 读--通过key读取缓存,第二个法是异步执行,异步回调
- (nullable id<NSCoding>)objectForKey:(NSString *)key;
- (void)objectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key, id<NSCoding> object))block;
// 增、改--缓存对象(可缓存遵从NSCoding协议的对象),第二个法是异步执行,异步回调
- (void)setObject:(nullable id<NSCoding>)object forKey:(NSString *)key;
- (void)setObject:(nullable id<NSCoding>)object forKey:(NSString *)key withBlock:(nullable void(^)(void))block;
// 删--删除缓存
- (void)removeObjectForKey:(NSString *)key;
- (void)removeObjectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key))block;
- (void)removeAllObjects;
- (void)removeAllObjectsWithBlock:(void(^)(void))block;
- (void)removeAllObjectsWithProgressBlock:(nullable void(^)(int removedCount, int totalCount))progress
endBlock:(nullable void(^)(BOOL error))end;
@end
3.YYCache使用
// 0.初始化YYCache
YYCache *cache = [YYCache cacheWithName:@"mydb"];
// 1.缓存普通字符
[cache setObject:@"汉斯哈哈哈" forKey:@"name"];
NSString *name = (NSString *)[cache objectForKey:@"name"];
NSLog(@"name: %@", name);
// 2.缓存模型
[cache setObject:(id<NSCoding>)model forKey:@"user"];
// 3.缓存数组
NSMutableArray *array = @[].mutableCopy;
for (NSInteger i = 0; i < 10; i ++) {
[array addObject:model];
}
// 异步缓存
[cache setObject:array forKey:@"user" withBlock:^{
// 异步回调
NSLog(@"%@", [NSThread currentThread]);
NSLog(@"array缓存完成....");
}];
// 延时读取
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 异步读取
[cache objectForKey:@"user" withBlock:^(NSString * _Nonnull key, id<NSCoding> _Nonnull object) {
// 异步回调
NSLog(@"%@", [NSThread currentThread]);
NSLog(@"%@", object);
}];
});
打印:
2016-06-09 11:35:44.069 YYCache源码分析[13546:949048] <NSThread: 0x7ffd43f14840>{number = 2, name = (null)}
2016-06-09 11:35:44.069 YYCache源码分析[13546:949048] array缓存完成....
2016-06-09 11:35:44.386 YYCache源码分析[13546:949052] <NSThread: 0x7ffd43e01900>{number = 3, name = (null)}
2016-06-09 11:35:44.386 YYCache源码分析[13546:949052] (
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>",
"<UserModel: 0x7ffd44014310>"
)
// 缓存实现,默认同时进行内存缓存与文件缓存
- (void)setObject:(id<NSCoding>)object forKey:(NSString *)key {
[_memoryCache setObject:object forKey:key];
[_diskCache setObject:object forKey:key];
}
// 如果只想内存缓存,可以直接调用`memoryCache`对象
YYCache *cache2 = [YYCache cacheWithName:@"mydb"];
[cache2.memoryCache setObject:@24 forKey:@"age"];
NSLog(@"age缓存在内存:%d", [cache2.memoryCache containsObjectForKey:@"age"]);
NSLog(@"age缓存在文件:%d", [cache2.diskCache containsObjectForKey:@"age"]);
打印:
2016-06-09 21:23:24.326 YYCache源码分析[14512:1085375] age缓存在内存:1
2016-06-09 21:23:24.326 YYCache源码分析[14512:1085375] age缓存在文件:0
4.YYCache.h tips
#if __has_include(<YYCache/YYCache.h>)
#import <YYCache/YYMemoryCache.h>
#import <YYCache/YYDiskCache.h>
#import <YYCache/YYKVStorage.h>
#elif __has_include(<YYWebImage/YYCache.h>)
#import <YYWebImage/YYMemoryCache.h>
#import <YYWebImage/YYDiskCache.h>
#import <YYWebImage/YYKVStorage.h>
#else
#import "YYMemoryCache.h"
#import "YYDiskCache.h"
#import "YYKVStorage.h"
#endif
__has_include:用来检查Frameworks是否引入某个类,
像YYWebImage已经集成YYCache,如果导入过YYWebImage则无需重新导入YYCache
NS_ASSUME_NONNULL_BEGIN
@interface YYCache : NSObject
...
- (nullable instancetype)initWithName:(NSString *)name;
...
@end
NS_ASSUME_NONNULL_END
接口中 nullable 的是少数,一般都为nonnull,为了防止写一大堆 nonnull,Foundation供了一对宏NS_ASSUME_NONNULL_BEGIN、NS_ASSUME_NONNULL_END,包在里面的对象默认加 nonnull 修饰符,如果是nullable的,只需要把 nullable 的指出来就行
- (instancetype)init UNAVAILABLE_ATTRIBUTE;
+ (instancetype)new UNAVAILABLE_ATTRIBUTE;
command+鼠标左键UNAVAILABLE_ATTRIBUTE,
发现宏定义#define UNAVAILABLE_ATTRIBUTE __attribute__((unavailable)),
__attribute__是Clang提供的一种源码注解,方便开发者向编译器表达某种要求,括号里是传达某种命令.
为方便使用,一些常用属性也被Cocoa定义成宏,
比如UNAVAILABLE_ATTRIBUTE、NS_CLASS_AVAILABLE_IOS(9_0).
unavailable告诉编译器该方法失效.
在封装单例或初始化某个类前必须做一些事时,对一些方法禁用是非常不错的选择.
还可以给个message提示:
+ (instancetype)alloc __attribute__((unavailable("alloc方法不可用,请用initWithName:")));
- (instancetype)init __attribute__((unavailable("init方法不可用,请用initWithName:")));
+ (instancetype)new __attribute__((unavailable("new方法不可用,请用initWithName:")));
- (instancetype)copy __attribute__((unavailable("copy方法不可用,请用initWithName:")));
本文只是简单剖析,接下来会分析YYMemoryCache实现原理.
References
http://blog.sunnyxx.com/2016/05/14/clang-attributes/
http://blog.sunnyxx.com/2015/06/12/objc-new-features-in-2015/
YYCache 源码分析(一)的更多相关文章
- YYCache 源码分析(二)
本文分析YYMemoryCache实现原理: YYMemoryCache是内存缓存,所以存取速度非常快,主要用到两种数据结构的LRU淘汰算法 1.LRU Cache的容量是有限的,当Cache的空间都 ...
- iOS常用框架源码分析
SDWebImage NSCache 类似可变字典,线程安全,使用可变字典自定义实现缓存时需要考虑加锁和释放锁 在内存不足时NSCache会自动释放存储的对象,不需要手动干预 NSCache的key不 ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
- java使用websocket,并且获取HttpSession,源码分析
转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...
随机推荐
- MyBatis Generator自动生成MyBatis的映射代码
MyBatis Generator大大简化了MyBatis的数据库的代码编写,有了一个配置文件,就可以直接根据表映射成实体类.Dao类和xml映射.资源地址:MyBatis项目地址:http://my ...
- js获取url中的参数对象、js生成带参数的url
// 获取url中的参数,并返回一个对象 $.getRequestData = function() { var url = location.search; //获取url中"?" ...
- js touch触屏原理分析
之前我们做过许多触屏的特效,那么,今天,我们来分析下js的触屏原理.事实上,大家百度一下js touch基本上可以找到这文章“指尖下的js ——多触式web前端开发之一:对于Touch的处理”,我想这 ...
- HTML用法小摘录
一.网页地址栏上小图标标签添加写法: <link rel="Shortcut Icon" href="~/Content/ico/glasses.ico" ...
- Python使用纯真年代数据库qqwry.dat转换物理位置
PS:网上直接找的,贴出来,方便以后随时用,感谢分享的人. #!/usr/bin/python #encoding: utf-8 import socket import codecs import ...
- 【Java】WSDL 简介
WSDL(网络服务描述语言,Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问. 什么是 WSD ...
- CentOS 5升级Python版本(2.4>2.7)
安装SALT时,需要这样作,公司有一批REDHAT5的,弄起来... 然后却是: Missing Dependency: python(abi) = 2.6 is needed by package ...
- VS在Release模式下,难道还可以Debug?
就是这段代码: int main(int argc, char *argv[]) { QApplication a(argc, argv); cxcxsdee w; w.show(); QString ...
- 使用SSH代理上IPV6(使用SSH端口转发)
这几个月在国外待着,一直担心我的六维账户怎么办,那可是个宝贝啊.我看网上说可以用六飞啊神马的在IPV6下上IPV6的网站,但是冒失现在六维封禁了非学校的IPV6地址,所以这些软件就不顶用了. 想到以前 ...
- 【HDOJ】2405 Marbles in Three Baskets
BFS+状态压缩. /* 2405 */ #include <iostream> #include <queue> #include <cstdio> #inclu ...