YYCache

作者: Code_人生 | 来源:发表于2019-10-08 16:42 被阅读0次

    一、YYMemoryCache

    1、来到YYCache.m- (void)setObject:(nullable id<NSCoding>)object forKey:(NSString *)key;

    - (void)setObject:(id<NSCoding>)object forKey:(NSString *)key {
        [_memoryCache setObject:object forKey:key];
        [_diskCache setObject:object forKey:key];
    }
    
    - (void)setObject:(id)object forKey:(id)key {
        [self setObject:object forKey:key withCost:0];
    }
    
    - (void)setObject:(id)object forKey:(id)key withCost:(NSUInteger)cost {
        if (!key) return;
        if (!object) {
            [self removeObjectForKey:key];
            return;
        }
        pthread_mutex_lock(&_lock);
        _YYLinkedMapNode *node = CFDictionaryGetValue(_lru->_dic, (__bridge const void *)(key));
        NSTimeInterval now = CACurrentMediaTime();
        if (node) {
            _lru->_totalCost -= node->_cost;
            _lru->_totalCost += cost;
            node->_cost = cost;
            node->_time = now;
            node->_value = object;
            [_lru bringNodeToHead:node];
        } else {
            node = [_YYLinkedMapNode new];
            node->_cost = cost;
            node->_time = now;
            node->_key = key;
            node->_value = object;
            [_lru insertNodeAtHead:node];
        }
        if (_lru->_totalCost > _costLimit) {
            dispatch_async(_queue, ^{
                [self trimToCost:_costLimit];
            });
        }
        if (_lru->_totalCount > _countLimit) {
            _YYLinkedMapNode *node = [_lru removeTailNode];
            if (_lru->_releaseAsynchronously) {
                dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
                dispatch_async(queue, ^{
                    [node class]; //hold and release in queue
                });
            } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [node class]; //hold and release in queue
                });
            }
        }
        pthread_mutex_unlock(&_lock);
    }
    
    • __weak 对象释放后,指向对象的指针会置空
    • __unsafe_unretained 对象释放后,变成野指针 BAD_ACCESS
    @interface _YYLinkedMapNode : NSObject {
        @package
        __unsafe_unretained _YYLinkedMapNode *_prev; // retained by dic
        __unsafe_unretained _YYLinkedMapNode *_next; // retained by dic
        id _key;
        id _value;
        NSUInteger _cost;
        NSTimeInterval _time;
    }
    @end
    

    二、YYDiskCache

    • 文件&数据库结合的方式
    2.1 存
    - (void)setObject:(id<NSCoding>)object forKey:(NSString *)key {
        if (!key) return;
        if (!object) {
            [self removeObjectForKey:key];
            return;
        }
        
        NSData *extendedData = [YYDiskCache getExtendedDataFromObject:object];
        NSData *value = nil;
        if (_customArchiveBlock) {
            value = _customArchiveBlock(object);
        } else {
            @try {
                value = [NSKeyedArchiver archivedDataWithRootObject:object];
            }
            @catch (NSException *exception) {
                // nothing to do...
            }
        }
        if (!value) return;
        NSString *filename = nil;
        if (_kv.type != YYKVStorageTypeSQLite) {
            if (value.length > _inlineThreshold) {
                filename = [self _filenameForKey:key];
            }
        }
        
        Lock();
        [_kv saveItemWithKey:key value:value filename:filename extendedData:extendedData];
        Unlock();
    }
    
    - (BOOL)saveItemWithKey:(NSString *)key value:(NSData *)value filename:(NSString *)filename extendedData:(NSData *)extendedData {
        if (key.length == 0 || value.length == 0) return NO;
        if (_type == YYKVStorageTypeFile && filename.length == 0) {
            return NO;
        }
        
        if (filename.length) {
            if (![self _fileWriteWithName:filename data:value]) {
                return NO;
            }
            if (![self _dbSaveWithKey:key value:value fileName:filename extendedData:extendedData]) {
                [self _fileDeleteWithName:filename];
                return NO;
            }
            return YES;
        } else {
            if (_type != YYKVStorageTypeSQLite) {
                NSString *filename = [self _dbGetFilenameWithKey:key];
                if (filename) {
                    [self _fileDeleteWithName:filename];
                }
            }
            return [self _dbSaveWithKey:key value:value fileName:nil extendedData:extendedData];
        }
    }
    
    - (BOOL)_dbSaveWithKey:(NSString *)key value:(NSData *)value fileName:(NSString *)fileName extendedData:(NSData *)extendedData {
        NSString *sql = @"insert or replace into manifest (key, filename, size, inline_data, modification_time, last_access_time, extended_data) values (?1, ?2, ?3, ?4, ?5, ?6, ?7);";
        sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
        if (!stmt) return NO;
        
        int timestamp = (int)time(NULL);
        sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
        sqlite3_bind_text(stmt, 2, fileName.UTF8String, -1, NULL);
        sqlite3_bind_int(stmt, 3, (int)value.length);
        if (fileName.length == 0) {
            sqlite3_bind_blob(stmt, 4, value.bytes, (int)value.length, 0);
        } else {
            sqlite3_bind_blob(stmt, 4, NULL, 0, 0);
        }
        sqlite3_bind_int(stmt, 5, timestamp);
        sqlite3_bind_int(stmt, 6, timestamp);
        sqlite3_bind_blob(stmt, 7, extendedData.bytes, (int)extendedData.length, 0);
        
        int result = sqlite3_step(stmt);
        if (result != SQLITE_DONE) {
            if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite insert error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
            return NO;
        }
        return YES;
    }
    
    2.2 取
    - (id<NSCoding>)objectForKey:(NSString *)key {
        if (!key) return nil;
        Lock();
        YYKVStorageItem *item = [_kv getItemForKey:key];
        Unlock();
        if (!item.value) return nil;
        
        id object = nil;
        if (_customUnarchiveBlock) {
            object = _customUnarchiveBlock(item.value);
        } else {
            @try {
                object = [NSKeyedUnarchiver unarchiveObjectWithData:item.value];
            }
            @catch (NSException *exception) {
                // nothing to do...
            }
        }
        if (object && item.extendedData) {
            [YYDiskCache setExtendedData:item.extendedData toObject:object];
        }
        return object;
    }
    
    - (YYKVStorageItem *)getItemForKey:(NSString *)key {
        if (key.length == 0) return nil;
        YYKVStorageItem *item = [self _dbGetItemWithKey:key excludeInlineData:NO];
        if (item) {
            [self _dbUpdateAccessTimeWithKey:key];
            if (item.filename) {
                item.value = [self _fileReadWithName:item.filename];
                if (!item.value) {
                    [self _dbDeleteItemWithKey:key];
                    item = nil;
                }
            }
        }
        return item;
    }
    
    - (YYKVStorageItem *)_dbGetItemWithKey:(NSString *)key excludeInlineData:(BOOL)excludeInlineData {
        NSString *sql = excludeInlineData ? @"select key, filename, size, modification_time, last_access_time, extended_data from manifest where key = ?1;" : @"select key, filename, size, inline_data, modification_time, last_access_time, extended_data from manifest where key = ?1;";
        sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
        if (!stmt) return nil;
        sqlite3_bind_text(stmt, 1, key.UTF8String, -1, NULL);
        
        YYKVStorageItem *item = nil;
        int result = sqlite3_step(stmt);
        if (result == SQLITE_ROW) {
            item = [self _dbGetItemFromStmt:stmt excludeInlineData:excludeInlineData];
        } else {
            if (result != SQLITE_DONE) {
                if (_errorLogsEnabled) NSLog(@"%s line:%d sqlite query error (%d): %s", __FUNCTION__, __LINE__, result, sqlite3_errmsg(_db));
            }
        }
        return item;
    }
    

    相关文章

      网友评论

          本文标题:YYCache

          本文链接:https://www.haomeiwen.com/subject/xvoluctx.html