欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS NSCache和NSUrlCache緩存類實現(xiàn)示例詳解

 更新時間:2022年11月09日 14:23:32   作者:風雨_83  
這篇文章主要為大家介紹了iOS NSCache和NSUrlCache緩存類實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

NSCache

NSCache是Foundation框架提供的緩存類的實現(xiàn),使用方式類似于可變字典,最重要的是它是線程安全的,而NSMutableDictionary不是線程安全的,在多線程環(huán)境下使用NSCache是更好的選擇。 類的基本屬性和方法:

#import <Foundation/NSObject.h>
@class NSString;
@protocol NSCacheDelegate;
NS_ASSUME_NONNULL_BEGIN
API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0))
@interface NSCache <KeyType, ObjectType> : NSObject {
@private
    id _delegate;
    void *_private[5];
    void *_reserved;
}
@property (copy) NSString *name;
@property (nullable, assign) id<NSCacheDelegate> delegate;
- (nullable ObjectType)objectForKey:(KeyType)key;
- (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
- (void)removeObjectForKey:(KeyType)key;
- (void)removeAllObjects;
@property NSUInteger totalCostLimit;	// limits are imprecise/not strict
@property NSUInteger countLimit;	// limits are imprecise/not strict
@property BOOL evictsObjectsWithDiscardedContent;
@end
@protocol NSCacheDelegate <NSObject>
@optional
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
@end
NS_ASSUME_NONNULL_END

緩存淘汰策略

通過 GNUstep 提供的源碼,我們得知其對于 NSCache 的處理是計算出一個平均訪問次數(shù),然后釋放的是訪問次數(shù)較少的對象,直到滿足需要釋放大小,也就是 LRU 的機制。通過 swift-corelibs-foundation 源碼我們得知,其首先存儲鏈表結構中是按對象花費內存大小排序的,然后通過用戶有無指定 totalCostLimit 大小限制來依次釋放(先釋放占用較小的對象),直到滿足需要釋放大小。然后再通過個數(shù)限制來釋放,直到滿足需要釋放大?。ㄒ琅f是先釋放較小的對象)。

GNUstepFoundation 源碼地址:github.com/gnustep/lib…

Swift Foundation 源碼地址:github.com/apple/swift…

在內存不足時NSCache會自動釋放存儲的對象。

NSCache的鍵key不會被復制,所以key不需要實現(xiàn)NSCopying協(xié)議。

可以設置緩存的最大數(shù)量,當緩存數(shù)量滿的時候,再添加將先刪除先添加的對象再增加。

唯一一個代理方法是一個對象將被刪除時調用,調用方式有以下幾種:

  • NSCache緩存對象自身被釋放
  • 手動調用removeObjectForKey:方法
  • 手動調用removeAllObjects    
  • 緩存中對象的個數(shù)大于countLimit,或,緩存中對象的總cost值大于totalCostLimit    
  • 程序進入后臺后
  • 收到系統(tǒng)的內存警告

基本用法:

@interface NSCacheViewController ()<NSCacheDelegate>
@property(nonatomic,strong) NSCache *cache;
@end
@implementation NSCacheViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.cache = [[NSCache alloc] init];
    //設置最大緩存數(shù)
    self.cache.countLimit = 5;
    //設置代理,實現(xiàn)代理方法,
    self.cache.delegate = self;
    self.cache.name = @"測試內存";
    for (int i=0; i<10; i++) {
        NSString *str = [NSString stringWithFormat:@"%d",i];
        [self.cache setObject:str forKey:str];
    }
    // Do any additional setup after loading the view.
}
//超出緩存部分會被釋放, 收到內存警告時候系統(tǒng)也會釋放一部分。
-(void)cache:(NSCache *)cache willEvictObject:(id)obj{
    NSLog(@"%@---%@",cache,obj);
}
@end

實際應用 SDWebImage

SDImageCacheConfig中可以配置是否使用內存做緩存,默認為YES

磁盤緩存的最大時長,默認為一周

SDImage中內存緩存SDMemoryCache繼承與NScache,緩存時候會在NSCache和SDMemoryCache的NSMapTable各存一份。讀取時候也優(yōu)先讀取系統(tǒng)cache,如果不存在再讀取SDMemoryCache,這樣做的目標是防止一些系統(tǒng)緩存不可控因素。

// `setObject:forKey:` just call this with 0 cost. Override this is enough
- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g {
    [super setObject:obj forKey:key cost:g];
    if (!self.config.shouldUseWeakMemoryCache) {
        return;
    }
    if (key && obj) {
        // Store weak cache
        SD_LOCK(_weakCacheLock);
        [self.weakCache setObject:obj forKey:key];
        SD_UNLOCK(_weakCacheLock);
    }
}

NSURLCache

使用緩存的目的是為了使應用程序能更快速的響應用戶輸入,是程序高效的運行。有時候我們需要將遠程web服務器獲取的數(shù)據(jù)緩存起來,以空間換取時間,減少對同一個url多次請求,減輕服務器的壓力,優(yōu)化客戶端網(wǎng)絡,讓用戶體驗更良好。

背景:NSURLCache : 在iOS5以前,apple不支持磁盤緩存,在iOS5的時候,允許磁盤緩存,(NSURLCache 是根據(jù)NSURLRequest 來實現(xiàn)的)只支持http,在iOS6以后,支持http和https。

緩存的實現(xiàn)說明:由于GET請求一般用來查詢數(shù)據(jù),POST請求一般是發(fā)大量數(shù)據(jù)給服務器處理(變動性比較大),因此一般只對GET請求進行緩存,而不對POST請求進行緩存。

緩存原理:一個NSURLRequest對應一個NSCachedURLResponse

Etag全稱是Entity Tag,一般用于標識URL對象是否發(fā)生了改變。 使用Etag一般會出現(xiàn)如下的請求流程:

Etag有點類似于文件hash或者說是信息摘要。

當進行一次URL請求,服務端會返回'Etag'響應頭,下次瀏覽器請求相同的URL時,瀏覽器會自動將它設置為請求頭'If-None-Match'的值。服務器收到這個請求之后,就開始做信息校驗工作將自己本次產生的Etag與請求傳遞過來的'If-None-Match'對比,如果相同,則返回HTTP狀態(tài)碼304,并且response數(shù)據(jù)體中沒有數(shù)據(jù)。

第二次請求的時候從哪里獲取到'Etag'的值并賦給請求頭'If-None-Match'的?自然是瀏覽器的緩存中取出的。那么瀏覽器收到304狀態(tài)碼之后又干了什么?剛才說到response數(shù)據(jù)體中沒有數(shù)據(jù),但是瀏覽器仍需加載頁面,它會從緩存中讀取上次緩存的頁面。

//
//  NSURLCacheViewController.m
//  DemoTest2022
//
//  Created by wy on 2022/10/19.
//
#import "NSURLCacheViewController.h"
@interface NSURLCacheViewController ()
//去服務器比對資源是否需要更新
@property (nonatomic, strong) NSString *lastModified;
@property (nonatomic, strong) NSString *etag;
@property(nonatomic,strong) UIImageView *imagev;
@end
@implementation NSURLCacheViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.imagev = [[UIImageView alloc] initWithFrame:CGRectMake(0, 100, 100, 100)];
    [self.view addSubview:self.imagev];
    // Do any additional setup after loading the view.
}
-(void)requestTest{
    NSURL *url = [NSURL URLWithString:@"http://via.placeholder.com/50x50.png"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:(NSURLRequestReloadIgnoringCacheData) timeoutInterval:15] ;
    if (self.lastModified) {
        [request setValue:self.lastModified forHTTPHeaderField:@"If-Modified-Since"];
    }
    if (self.etag) {
        [request setValue:self.etag forHTTPHeaderField:@"If-None-Match"];
    }
    [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (error) {
                NSLog(@"error---%@",error);
            }else{
                NSData *tempData = data;
                NSString *responseStr = [[NSString alloc] initWithData:tempData encoding:NSUTF8StringEncoding];
                self.lastModified = [(NSHTTPURLResponse *)response  allHeaderFields][@"Last-Modified"];
                self.etag =[(NSHTTPURLResponse *)response allHeaderFields][@"etag"];
                NSLog(@"response:%@", response);
                dispatch_sync(dispatch_get_main_queue(), ^{
                    self.imagev.image = [UIImage imageWithData:tempData];
                });
            }
        }] resume] ;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self requestTest];
}
@end

這樣每次請求都使用忽略緩存的策略,但是要附帶著"If-None-Match"頭,它的值是上次請求的響應頭"Etag"的值,于是服務器會每次都實時檢查文件的修改狀態(tài),得到一個準確的狀態(tài)值,最后決定返回304還是200。若是200,iOS則直接使用新的response和新的數(shù)據(jù);如果是304,則使用新的response和緩存中的data。

這樣既能夠獲取到最新的數(shù)據(jù)有能夠節(jié)約帶寬。兩全其美。

iOS中定以的URLRequest緩存策略有以下幾種:

typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
    NSURLRequestUseProtocolCachePolicy = 0,
    // 從不讀取緩存,但請求后將response緩存起來
    NSURLRequestReloadIgnoringLocalCacheData = 1,
    NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4,
    NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,
    // 以下兩種在取緩存時,可能取到的是過期數(shù)據(jù)
    NSURLRequestReturnCacheDataElseLoad = 2,// 緩存中沒有才去發(fā)起請求加載,有就不進行網(wǎng)絡請求了
    NSURLRequestReturnCacheDataDontLoad = 3,// 緩存中沒有不加載,絕不發(fā)起網(wǎng)絡請求,緩存中沒有則返回錯誤
    NSURLRequestReloadRevalidatingCacheData = 5,//Unimplemented
};

官方文檔解釋:

NSURLCache類通過將NSURLRequest對象映射到NSCachedURLResponse對象來實現(xiàn)URL加載請求響應的緩存。它提供了一個復合的內存和磁盤緩存,并允許您操作內存和磁盤部分的大小。您還可以控制緩存數(shù)據(jù)持久存儲的路徑。

在iOS中,當系統(tǒng)磁盤空間不足時,磁盤上的緩存可能會被清除,但只有在應用程序未運行時才會清除。

AFNetwork中用法:

總結:

NSCache 特點

  • 使用方便,類似字典
  • l線程安全
  • l內存不足時,NSCache會自動釋放存儲對象
  • NSCache的key不會被拷貝,不需要實現(xiàn)NSCopying協(xié)議
  • lNSDiscardableContent協(xié)議

NSURLCache主要應用與網(wǎng)絡請求數(shù)據(jù)緩存策略,優(yōu)化網(wǎng)絡請求性能優(yōu)化。

以上就是iOS NSCache和NSUrlCache緩存類實現(xiàn)示例詳解的詳細內容,更多關于iOS NSCache NSUrlCache的資料請關注腳本之家其它相關文章!

相關文章

最新評論