YYKit源码探究(五十六) —— NSData分类之Hash(一)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了YYKit源码探究(五十六) —— NSData分类之Hash(一)相关的知识,希望对你有一定的参考价值。

参考技术A

上一篇主要介绍了NSDate的 Date modify 分类部分,这一篇主要看一下 NSData 分类的 Hash 部分。

下面我们看一下框架结构。

下面我们看一下API

下面我们看一下方法实现。

该方法返回的是md2 hash小写字母字符串。

方法实现

该方法返回的是md2 hash的NSData对象。

方法实现

该方法返回的是md4 hash小写字母字符串。

方法实现

该方法返回的是md4 hash的NSData对象。

方法实现

该方法返回的是md5 hash小写字母字符串。

方法实现

该方法返回的是md5 hash的NSData对象。

方法实现

该方法返回的是sha1 hash小写字母字符串。

方法实现

该方法返回的是sha1 hash的NSData对象。

方法实现

该方法返回的是sha224 hash小写字母字符串。

方法实现

该方法返回的是sha224 hash的NSData对象。

方法实现

该方法返回的是sha256 hash小写字母字符串。

方法实现

该方法返回的是sha256 hash的NSData对象。

方法实现

该方法返回的是sha384 hash小写字母字符串。

方法实现

该方法返回的是sha384 hash的NSData对象。

方法实现

该方法返回的是sha512 hash小写字母字符串。

方法实现

该方法返回的是sha512 hash的NSData对象。

方法实现

该方法返回的是md5和指定的key进行加密返回的小写字母字符串。

方法实现

该方法返回的是md5和指定的key进行加密返回的N。
SData数据。

方法实现

该方法返回的是SHA1指定的key进行加密返回的小写字母字符串。

方法实现

该方法返回的是SHA1和指定的key进行加密返回的N。
SData数据。

方法实现

该方法返回的是SHA224指定的key进行加密返回的小写字母字符串。

方法实现

该方法返回的是SHA224和指定的key进行加密返回的NSData数据。

方法实现

该方法返回的是SHA256指定的key进行加密返回的小写字母字符串。

方法实现

该方法返回的是SHA256和指定的key进行加密返回的NSData数据。

方法实现

该方法返回的是SHA384指定的key进行加密返回的小写字母字符串。

方法实现

该方法返回的是SHA384和指定的key进行加密返回的NSData数据。

方法实现

该方法返回的是SHA512指定的key进行加密返回的小写字母字符串。

方法实现

该方法返回的是SHA512和指定的key进行加密返回的NSData数据。

方法实现

该方法返回的是crc32 hash小写字符串。

方法实现

该方法返回的是crc32 hash值。

方法实现

YYKit源码阅读 - YYCache

前言

本篇用来记录下阅读YYKit中YYCache的一些理解和收获,着重解决两个问题:

  1.YYCache在内存和磁盘各自存取方式。

  2.YYCache使用怎样的数据结构来进行数据的存储。怎样确保多线程下的数据操作的安全性。

首先我们来看一下YYCache包含的文件。在本篇中我们并不像之前那样每个属性,每个方法都展示出来解释,主要还是针对问题。

技术分享图片

YYMemoryCache

YYMemoryCache是存储键值对的快速内存缓存,区别于NSDictionary,其键是retain而非copy。它的API与NSCache相似并且都是线程安全的。但它也与NSCache有一些不同点:

  • YYMemoryCache使用LRU也就是最近最少使用来移除objects;NSCache是不确切的。
  • YYMemoryCache可以通过对象数量,对象空间总量以及失效时间来控制;NSCache在此也是不确切的。
  • YYMemoryCache可以配置在当收到内存警告或者app进入后台是来自动移除掉objects。

同时YYMemoryCache的访问方法的时间复杂度均为O(1)。

在.m文件中我们发现有一个_YYLinkedMap对象

技术分享图片

其内包含了一个可变字典,一个head节点,一个tail节点以及其他属性。这里的可变字典使用的是CoreFoundation对象,更加底层,性能更好。字典内保存的是_YYLinkedMapNode对象

技术分享图片

包含一个前驱节点,一个后继节点。看到这两个名词就知道了使用的链表结构而且是双向链表。但是使用双向链表的目的是什么呢?我们来看下

_YYLinkedMap中定义的方法 

技术分享图片

这里我们主要来看下insertNodeAtHead和bringNodeToHead两个方法的实现

- (void)insertNodeAtHead:(_YYLinkedMapNode *)node {
    //将node存入字典中
    CFDictionarySetValue(_dic, (__bridge const void *)(node->_key), (__bridge const void *)(node));
    //空间总量增加
    _totalCost += node->_cost;
    //对象数量增加
    _totalCount++;
    
    //如果已经存在head
    if (_head) {
        //将新添加的node作为head
        node->_next = _head;
        _head->_prev = node;
        _head = node;
    } else {
        //将新添加的node同时作为head和tail
        _head = _tail = node;
    }
}

- (void)bringNodeToHead:(_YYLinkedMapNode *)node {
    //node为head就不操作
    if (_head == node) return;
    
    //分别处理node为tail和node为中间节点的情况
    if (_tail == node) {
        _tail = node->_prev;
        _tail->_next = nil;
    } else {
        node->_next->_prev = node->_prev;
        node->_prev->_next = node->_next;
    }
    //node变更为head
    node->_next = _head;
    node->_prev = nil;
    _head->_prev = node;
    _head = node;
}

其中head是作为MRU的,而tail是作为LRU的。每次从字典中取出缓存时就将此次所取node移到链表的头部,而尾部就是最不常用的node。

我们从YYMemoryCache的成员变量中可以看到有一个pthread_mutex_t,这是一个互斥锁。互斥锁常用的几个方法大概有下面几个

  • pthread_mutex_init,锁的初始化

  • pthread_mutex_lock,加锁

  • pthread_mutex_unlock,解锁

  • pthread_mutex_trylock,pthread_mutex_lock的非阻塞版本

基本上YYMemoryCache所有暴露在外的属性以及隐藏在内的dictionary的操作均存在锁操作。举个例子

- (void)_trimToCost:(NSUInteger)costLimit {
    BOOL finish = NO;
    pthread_mutex_lock(&_lock);
    if (costLimit == 0) {
        [_lru removeAll];
        finish = YES;
    } else if (_lru->_totalCost <= costLimit) {
        finish = YES;
    }
    pthread_mutex_unlock(&_lock);
    if (finish) return;
    
    NSMutableArray *holder = [NSMutableArray new];
    while (!finish) {
        if (pthread_mutex_trylock(&_lock) == 0) {
            if (_lru->_totalCost > costLimit) {
                _YYLinkedMapNode *node = [_lru removeTailNode];
                if (node) [holder addObject:node];
            } else {
                finish = YES;
            }
            pthread_mutex_unlock(&_lock);
        } else {
            usleep(10 * 1000); //10 ms
        }
    }
    if (holder.count) {
        dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
        dispatch_async(queue, ^{
            [holder count]; // release in queue
        });
    }
}

该方法的目的是根据设置的最大cost来删除缓存。方法里面有两个值得注意的地方一个是使用了usleep函数。看到usleep一定会想到sleep,区别在于usleep一般以ns作为计量单位而当休眠时间达到s的量级会使用sleep。还有就是将holder数组捕获到queue的block内用于在置顶queue中释放holder。

YYDiskCache

未完待续 

以上是关于YYKit源码探究(五十六) —— NSData分类之Hash(一)的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer(五十六)之链表中环的入口结点

YYKit源码阅读 - YYCache

爱创课堂每日一题第五十六天-对前端界面工程师这个职位是怎么样理解的?它的前景会怎么样?

YYKit源码学习——YYMemoryCache

珍珠港的山本五十六的演员是谁

将十六进制值存储到 NSData