日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SDMemoryCache中的NSMapTable

發(fā)布時間:2025/7/14 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SDMemoryCache中的NSMapTable 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

帶著問題學(xué)習(xí)L

NSMapTable看名字是一個映射表,官方文檔描述為:類似于字典的集合,但具有更廣泛的可用內(nèi)存語義。

問題1:NSDictionary內(nèi)存語義怎么就不廣泛了呢?

- (void)setObject:(ObjectType)anObject forKey:(KeyType <NSCopying>)aKey; 復(fù)制代碼

如上是NSDictionary的賦值方法,明顯可以看出key必須要遵循NSCoping協(xié)議,那么我們做個小實驗。

//teacher遵守了NSCoping協(xié)議 Teacher * teacher = [[Teacher alloc] init]; NSMutableDictionary * dictest = [[NSMutableDictionary alloc] initWithCapacity:2]; {Student * student = [[Student alloc] init];NSLog(@"student:%@",student);[dictest setObject:student forKey:teacher]; }NSLog(@"dictest:%@\nteacher:%@",dictest,teacher);//打印結(jié)果 student:<Student: 0x600002383e60> dictest:{"<Teacher: 0x6000023d5780>" = "<Student: 0x600002383e60>"; } teacher:<Teacher: 0x600002383e40> 復(fù)制代碼

可以看出作為key的teacher地址變了,而student地址跟原來相同,并且跳出作用于也沒有釋放,那么結(jié)論如下:

  • 其實akey是對原本的key執(zhí)行了copy。而anObject是對對象進(jìn)行了強引用。 這樣可以看出來確實NSDictionary的key內(nèi)存語義只有copy,確實不廣泛。

那么我們回到NSMapTable上來,官方文檔描述如下:

映射表的模型和NSDictionary具有以下的差異:

  • 可以給鍵或者值添加弱引用語義,當(dāng)其中一個對象移除時同時移除該條目
  • 可以給鍵或者值添加拷貝語義,也可以使用指針標(biāo)識進(jìn)行等值判斷
  • 作為一個集合類型,它可以包含任意指針(內(nèi)容不限于對象)

如下:可以給鍵值設(shè)置任意內(nèi)存語義,常見的有三種NSPointerFunctionsWeakMemory、NSPointerFunctionsStrongMemory、NSPointerFunctionsCopyIn。分別是強引用,弱引用和拷貝。那么下面這樣初始化的映射表就跟NSDictionary無異了。

NSMapTable * table = [[NSMapTable alloc] initWithKeyOptions: NSPointerFunctionsCopyIn valueOptions:NSPointerFunctionsStrongMemory capacity:2]; 復(fù)制代碼

問題2:修改內(nèi)存key、value的語義對于這種映射的集合類型的差異在于哪呢?

其實就在于查詢、刪除、賦值這些操作上,看如下的例子:

NSMapTable * table = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsWeakMemory valueOptions:NSPointerFunctionsStrongMemory capacity:2];NSMutableDictionary * dic = [[NSMutableDictionary alloc] initWithCapacity:2];Teacher * teacher = [[Teacher alloc] init];teacher.name = @"老師";teacher.old = @"31";Student * student1 = [[Student alloc] init];student1.name = @"學(xué)生1";student1.old = @"21";Student * student2 = [[Student alloc] init];student2.name = @"學(xué)生2";student2.old = @"22";Student * student3 = [[Student alloc] init];student3.name = @"學(xué)生3";student3.old = @"23";[dic setObject:@[student1,student2,student3] forKey:teacher];[dic setObject:@[student1,student2] forKey:teacher];[table setObject:@[student1,student2,student3] forKey:teacher];[table setObject:@[student1,student2] forKey:teacher];NSLog(@"\n teacher:%@\ndic:%@\n table:%@",teacher,dic,table);//打印結(jié)果 teacher:<Teacher: 0x6000007ea6a0> dic:{"<Teacher: 0x6000007ea980>" = ("<Student: 0x6000007ea820>","<Student: 0x6000007ea8e0>");"<Teacher: 0x6000007ea940>" = ("<Student: 0x6000007ea820>","<Student: 0x6000007ea8e0>","<Student: 0x6000007ea840>"); }table:NSMapTable { [5] <Teacher: 0x6000007ea6a0> -> ("<Student: 0x6000007ea820>","<Student: 0x6000007ea8e0>" ) } 復(fù)制代碼

在這個例子中,可以看出明顯的差別。我們創(chuàng)建了一個NSMutableDictionary對象和一個key是弱引用value是強引用的映射表。都是以teacher為key設(shè)置類兩遍值。前者dic對于同樣一個key生成了兩個key-value,后者maptable只要一個。那么這個是為什么呢?? 關(guān)鍵在于映射集合在設(shè)置key的時候要判斷當(dāng)前集合中是否包含此key,也就是說是否包含key和要設(shè)置的key相等,因為key也是一個對象,那么這個問題又回歸到判斷兩個對象是否相等上了,那么判斷過程是怎么樣的呢? 其實是這樣的,首先會判斷兩個對象的hash值是否相等,如果hash值相等再進(jìn)入isEqualTo方法判斷,以解決散列沖突問題。對于上面例子里面dictionary來說因為key是copy出來的兩個對象自然不相等,對于dictionary就是兩個不相同的key,對于mapTable來說,key是弱引用而來是相同對象hash值一定是相同的,所以會當(dāng)作相同key處理。 那么我們知道了這些。

問題3:如何將dictionary改造成跟上面一樣呢?

從Teacher類入手,重寫hash和isequal方法,如下:

@implementation Teacher - (id)copyWithZone:(NSZone *)zone{Teacher * teacher = [[Teacher alloc] init];teacher.name = self.name;teacher.old = self.old;return teacher; } - (BOOL)isEqual:(id)object{NSLog(@"是否相等");if (![object isKindOfClass:[Teacher class]]){return NO;}if ([((Teacher *)object).name isEqualToString:self.name] && [((Teacher *)object).old isEqualToString:self.old]){return YES;}return NO; } - (NSUInteger)hash{NSUInteger hash = self.name.hash+self.old.hash;NSLog(@"地址%@hash:%@",self,@(hash));return hash; } @end 復(fù)制代碼

接下來我們回到SDMemoryCache中。

self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0]; 復(fù)制代碼

如上,SDMemoryCache中存在與一個key強引用,value弱引用的映射表,意思是存儲的值銷毀的時候,self.weakCache會安全(代碼里加了信號量鎖)的刪除對應(yīng)的key-value。

// `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 cacheLOCK(self.weakCacheLock);// Do the real copy of the key and only let NSMapTable manage the key's lifetime// Fixes issue #2507 https://github.com/SDWebImage/SDWebImage/issues/2507[self.weakCache setObject:obj forKey:[[key mutableCopy] copy]];UNLOCK(self.weakCacheLock);} }- (id)objectForKey:(id)key {id obj = [super objectForKey:key];if (!self.config.shouldUseWeakMemoryCache) {return obj;}if (key && !obj) {// Check weak cacheLOCK(self.weakCacheLock);obj = [self.weakCache objectForKey:key];UNLOCK(self.weakCacheLock);if (obj) {// Sync cacheNSUInteger cost = 0;if ([obj isKindOfClass:[UIImage class]]) {cost = [(UIImage *)obj sd_memoryCost];}[super setObject:obj forKey:key cost:cost];}}return obj; } 復(fù)制代碼

當(dāng)打開shouldUseWeakMemoryCache的時候賦值的時候可以將值同樣付給weakCache,取值的時候如果緩存中沒有同樣會在weakCache里面找,因為weakCache存儲的是引用不會有有額外的內(nèi)存開銷且weak不會影響對象的生命周期,所以在NSCache被清理,且對象沒有被釋放的情況下,同樣可以在weakCache中取到緩存,在一定意義增加了緩存的廣度,減少了請求次數(shù)。那么weakCache存在的意義就在于此。

能力有限,有理解偏頗之處望及時指出,感激不盡。

總結(jié)

以上是生活随笔為你收集整理的SDMemoryCache中的NSMapTable的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。