iOS开发- 缓存(TMCache是如何缓存的?)

TMCache 是Tumblr使用的缓存系统(github:https://github.com/tumblr/TMCache),它由两部分组成:磁盘缓存和内存缓存。(目前已经停止维护)

特点:

1. 由GCD支持

2. 线程安全

3. 如果收到内存警告或者APP进入后台, 内存缓存将被清理。磁盘缓存需要手动清理,或者设置时间/大小限制

4. 能够缓存任何支持NSCoding的对象(最重要的就是UIImage),通过key存取

TMCache由三个类构成,TMCache,TMDiskCache和TMMemoryCache。TMCache对TMDiskCache和TMMemoryCache进行了封装,其本身并未做实质的缓存工作。

TMCache:

TMCache拥有一个concurrent queue,基本上所有存取对象的操作都在这个queue中进行,可以进行异步或者同步存取(异步方法是主体,同步方法是通过信号量将异步变为同步的)。

异步取对象方法

- TMCache先在TMMemoryCache中取,如果没有再在TMDiskCache中取

- 另外每次将block添加到queue之前,都要捕获self ,并且在block中判断self是否还存在(如果在block的过程中,self在其他地方因为某种原因被释放了,此时block保持了self,容易造成内存泄漏,因为使用__weak)。

- 在TMDiskCache中取到对象之后,立即将对象存到TMMemoryCache,这样下次就直接可以从TMMemoryCache中获取了

- (void)objectForKey:(NSString *)key block:(TMCacheObjectBlock)block
{
    if (!key || !block)
        return;

    __weak TMCache *weakSelf = self;

    dispatch_async(_queue, ^{
        TMCache *strongSelf = weakSelf;
        if (!strongSelf)
            return;

        __weak TMCache *weakSelf = strongSelf;

        [strongSelf->_memoryCache objectForKey:key block:^(TMMemoryCache *cache, NSString *key, id object) {
            TMCache *strongSelf = weakSelf;
            if (!strongSelf)
                return;

            if (object) {
                [strongSelf->_diskCache fileURLForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
                    // update the access time on disk
                }];

                __weak TMCache *weakSelf = strongSelf;

                dispatch_async(strongSelf->_queue, ^{
                    TMCache *strongSelf = weakSelf;
                    if (strongSelf)
                        block(strongSelf, key, object);
                });
            } else {
                __weak TMCache *weakSelf = strongSelf;

                [strongSelf->_diskCache objectForKey:key block:^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
                    TMCache *strongSelf = weakSelf;
                    if (!strongSelf)
                        return;

                    [strongSelf->_memoryCache setObject:object forKey:key block:nil];

                    __weak TMCache *weakSelf = strongSelf;

                    dispatch_async(strongSelf->_queue, ^{
                        TMCache *strongSelf = weakSelf;
                        if (strongSelf)
                            block(strongSelf, key, object);
                    });
                }];
            }
        }];
    });
}

异步存对象的方法:

- 同时存到磁盘和内存中,使用dispatch_group_create();dispatch_group_enter(group);dispatch_group_leave(group)和

dispatch_group_notify(group,queue,block)保持两个操作的同步(两个操作都完成后,才算是成功)

- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMCacheObjectBlock)block
{
    if (!key || !object)
        return;

    dispatch_group_t group = nil;
    TMMemoryCacheObjectBlock memBlock = nil;
    TMDiskCacheObjectBlock diskBlock = nil;

    if (block) {
        group = dispatch_group_create();
        dispatch_group_enter(group);
        dispatch_group_enter(group);

        memBlock = ^(TMMemoryCache *cache, NSString *key, id object) {
            dispatch_group_leave(group);
        };

        diskBlock = ^(TMDiskCache *cache, NSString *key, id <NSCoding> object, NSURL *fileURL) {
            dispatch_group_leave(group);
        };
    }

    [_memoryCache setObject:object forKey:key block:memBlock];
    [_diskCache setObject:object forKey:key block:diskBlock];

    if (group) {
        __weak TMCache *weakSelf = self;
        dispatch_group_notify(group, _queue, ^{
            TMCache *strongSelf = weakSelf;
            if (strongSelf)
                block(strongSelf, key, object);
        });

        #if !OS_OBJECT_USE_OBJC
        dispatch_release(group);
        #endif
    }
}

 同步存对象:

- 使用dispatch_semaphore_t将上述异步方法变为同步。

- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key
{
    if (!object || !key)
        return;

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    [self setObject:object forKey:key block:^(TMCache *cache, NSString *key, id object) {
        dispatch_semaphore_signal(semaphore);
    }];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    #if !OS_OBJECT_USE_OBJC
    dispatch_release(semaphore);
    #endif
}

 TMDiskCache

- 拥有一个serialed queue,基本所有存取操作都在这个queue中进行,由于是串行queue,所有保证了线程安全。

-初始化时,扫描缓存所在的文件夹,用dictionary记录每个缓存对象文件的修改日期(最后一次访问的日期),大小,并在以后的存、取缓存时更新(将来用作删除缓存的依据)

- 以磁盘文件的url(处理后)为key,使用NSKeyedUnarchiver进行存取(每次取,都要更新最后一次访问日期)

 - 拥有will/didAddObjectBlock,will/didRemoveObjectBlock,will/didRemoveAllObjectsBlock在进行相关操作前后分别调用

TMMemoryCache:

- 拥有一个并行(concurrent) queue,存对象,和删除对象的时候,使用dispatch_barrier_async,保证线程安全

dispatch_barrier_async,作用是在开始执行barrier block时,检查并行队列中是否有其他正在执行的block,如果有就先将它们执行完而且不执行其他尚未执行的block,然后再执行barrier block,barrier block执行完毕后,再执行其他block

- 拥有didReceiveMemoryWarningBlock,didEnterBackgroundBlock,对内存警告和进入后台进行处理

- 使用dictionary存储key和缓存对象

时间: 2024-12-23 09:03:15

iOS开发- 缓存(TMCache是如何缓存的?)的相关文章

iOS开发 -李洪强-清除缓存

// //  SetViewController.m //  dfhx // //  Created by dfhx_iMac_001 on 16/4/5. //  Copyright © 2016年 luoyun. All rights reserved. // #import "SetViewController.h" @interface SetViewController ()<UITableViewDelegate,UITableViewDataSource> @

iOS开发UI篇—UITableviewcell的性能优化和缓存机制

iOS开发UI篇—UITableviewcell的性能问题 一.UITableviewcell的一些介绍 UITableView的每一行都是一个UITableViewCell,通过dataSource的 tableView:cellForRowAtIndexPath:方法来初始化每?行 UITableViewCell内部有个默认的子视图:contentView,contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图 辅助指示视图的作?是显示一个表示动作的

iOS开发网络篇—数据缓存

iOS开发网络篇—数据缓存 一.关于同一个URL的多次请求 有时候,对同一个URL请求多次,返回的数据可能都是一样的,比如服务器上的某张图片,无论下载多少次,返回的数据都是一样的. 上面的情况会造成以下问题 (1)用户流量的浪费 (2)程序响应速度不够快 解决上面的问题,一般考虑对数据进行缓存. 二.缓存 为了提高程序的响应速度,可以考虑使用缓存(内存缓存\硬盘缓存) 第一次请求数据时,内存缓存中没有数据,硬盘缓存中没有数据. 缓存数据的过程 当服务器返回数据时,需要做以下步骤 (1)使用服务器

IOS开发之异步加载网络图片并缓存本地实现瀑布流(二)

/* * @brief 图片加载通用函数 * @parma imageName 图片名 */ - (void)imageStartLoading:(NSString *)imageName{ NSURL *url = [NSURL URLWithString:imageName]; if([_fileUtil hasCachedImage:url]){ UIImageView *imageView = [[UIImageView alloc] init]; NSString *path = [_

iOS开发—清除缓存

iOS开发—清除缓存 一.修改了系统的头文件 报错示例: fatal error: file '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.1.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h' has been modified si

iOS开发swift版异步加载网络图片(带缓存和缺省图片)

iOS开发之swift版异步加载网络图片 与SDWebImage异步加载网络图片的功能相似,只是代码比较简单,功能没有SD的完善与强大,支持缺省添加图片,支持本地缓存. 异步加载图片的核心代码如下:  func setZYHWebImage(url:NSString?, defaultImage:NSString?, isCache:Bool){         var ZYHImage:UIImage?         if url == nil {             return   

iOS开发&gt;学无止境 - Cell异步图片加载优化,缓存机制详解

作者:勤奋的笨老头 网址:http://www.jianshu.com/p/02ab2b74c451 最近研究了一下UITbleView中异步加载网络图片的问题,iOS应用经常会看到这种界面.一个tableView上显示一些标题.详情等内容,在加上一张图片.这里说一下这种思路. 为了防止图片多次下载,我们需要对图片做缓存,缓存分为内存缓存于沙盒缓存,我们当然两种都要实现. 由于tableViewCell是有重用机制的,也就是说,内存中只有当前可见的cell数目的实例,滑动的时候,新显示cell会

iOS开发&gt;学无止境 - 方法缓存

摘要 只 要用到Objective-C,我们每天都会跟方法调用打交道.我们都知道Objective-C的方法决议是动态的,但是在底层一个方法究竟是怎么找到 的,方法缓存又是怎么运作的却鲜为人知.本文主要从源码角度探究了Objective-C在runtime层的方法决议(Method resolving)过程和方法缓存(Method cache)的实现. 简介 本文作者来自美团酒店旅游事业群iOS研发组.我们致力于创造价值.提升效率.追求卓越.欢迎大家加入我们(简历请发送到邮箱 [email pr

玩转iOS开发 - 数据缓存

Why Cache 有时候.对同一个URL请求多次,返回的数据可能都是一样的,比方server上的某张图片.不管下载多少次,返回的数据都是一样的. 上面的情况会造成下面问题 (1)用户流量的浪费 (2)程序响应速度不够快 解决上面的问题.一般考虑对数据进行缓存. 数据缓存 为了提高程序的响应速度,能够考虑使用缓存(内存缓存\硬盘缓存)r 第一次请求数据时,内存缓存中没有数据.硬盘缓存中没有数据. 缓存数据的过程: ? 当server返回数据时,须要做下面步骤 (1)使用server的数据(比方解

iOS开发网络缓存原理

一.关于同一个URL的多次请求 有时候,对同一个URL请求多次,返回的数据可能都是一样的,比如服务器上的某张图片,无论下载多少次,返回的数据都是一样的. 上面的情况会造成以下问题 (1)用户流量的浪费 (2)程序响应速度不够快 解决上面的问题,一般考虑对数据进行缓存. 二.缓存 为了提高程序的响应速度,可以考虑使用缓存(内存缓存\硬盘缓存) 第一次请求数据时,内存缓存中没有数据,硬盘缓存中没有数据. 缓存数据的过程 当服务器返回数据时,需要做以下步骤 (1)使用服务器的数据(比如解析.显示) (