Apply count limits to all NSCache, clean up caching.

This commit is contained in:
Matthew Chen 2021-06-22 11:50:42 -03:00
parent 13205bb635
commit 82aab5ea12
23 changed files with 65 additions and 207 deletions

View File

@ -153,7 +153,6 @@
346129991FD1E4DA00532771 /* SignalApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129971FD1E4D900532771 /* SignalApp.m */; };
346129A51FD1F09100532771 /* OWSContactsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129A21FD1F09100532771 /* OWSContactsManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
346129A61FD1F09100532771 /* OWSContactsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129A31FD1F09100532771 /* OWSContactsManager.m */; };
346129AD1FD1F34E00532771 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346129AC1FD1F34E00532771 /* ImageCache.swift */; };
346129AF1FD1F5D900532771 /* SystemContactsFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346129AE1FD1F5D900532771 /* SystemContactsFetcher.swift */; };
346129B41FD1F7E800532771 /* OWSProfileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129B11FD1F7E800532771 /* OWSProfileManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
346129B51FD1F7E800532771 /* OWSProfileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129B21FD1F7E800532771 /* OWSProfileManager.m */; };
@ -515,7 +514,6 @@
4556FA681F54AA9500AF40DD /* DebugUIProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4556FA671F54AA9500AF40DD /* DebugUIProfile.swift */; };
455A16DD1F1FEA0000F86704 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DB1F1FEA0000F86704 /* Metal.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
455AC69E1F4F8B0300134004 /* ImageCacheTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */; };
45638BDC1F3DD0D400128435 /* DebugUICalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */; };
45666F581D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */; };
4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4579431D1E7C8CE9008ED0C0 /* Pastelog.m */; };
@ -1193,7 +1191,6 @@
346129981FD1E4DA00532771 /* SignalApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalApp.h; sourceTree = "<group>"; };
346129A21FD1F09100532771 /* OWSContactsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsManager.h; sourceTree = "<group>"; };
346129A31FD1F09100532771 /* OWSContactsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsManager.m; sourceTree = "<group>"; };
346129AC1FD1F34E00532771 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
346129AE1FD1F5D900532771 /* SystemContactsFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SystemContactsFetcher.swift; sourceTree = "<group>"; };
346129B11FD1F7E800532771 /* OWSProfileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProfileManager.h; sourceTree = "<group>"; };
346129B21FD1F7E800532771 /* OWSProfileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProfileManager.m; sourceTree = "<group>"; };
@ -1588,7 +1585,6 @@
4556FA671F54AA9500AF40DD /* DebugUIProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUIProfile.swift; sourceTree = "<group>"; };
455A16DB1F1FEA0000F86704 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCacheTest.swift; sourceTree = "<group>"; };
45638BDB1F3DD0D400128435 /* DebugUICalling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUICalling.swift; sourceTree = "<group>"; };
45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScrubbingLogFormatterTest.m; sourceTree = "<group>"; };
456D0FD51F63094D008499CD /* km */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = km; path = translations/km.lproj/Localizable.strings; sourceTree = "<group>"; };
@ -2471,7 +2467,6 @@
3476236124081F8900D4FB6F /* GroupManager+SignalMessaging.swift */,
34E6003924251AD50026AD4B /* GroupViewUtils.swift */,
4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */,
346129AC1FD1F34E00532771 /* ImageCache.swift */,
4C9C50FD22F36FA40054A33F /* OutboundMessage+OWS.swift */,
34BEDB1421C80BC9007B0EAE /* OWSAnyTouchGestureRecognizer.h */,
34BEDB1521C80BCA007B0EAE /* OWSAnyTouchGestureRecognizer.m */,
@ -3993,7 +3988,6 @@
B660F6AD1C29868000687D6E /* FunctionalUtilTest.m */,
345AE2B52317048200DB6225 /* GRDBFinderTest.swift */,
4C9D347923679C13006A4307 /* GroupAndContactStreamTest.swift */,
455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */,
34C1A93A2656E904004FA478 /* MiscTest.swift */,
34843B25214327C9004DED45 /* OWSOrphanDataCleanerTest.m */,
45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */,
@ -5270,7 +5264,6 @@
32FC387926295FA50086C32B /* LoopingVideoView.swift in Sources */,
3478506B1FD9B78A007B8332 /* NoopCallMessageHandler.swift in Sources */,
340872CA2239563500CB25B0 /* AttachmentApprovalViewController.swift in Sources */,
346129AD1FD1F34E00532771 /* ImageCache.swift in Sources */,
32275883264367520037E73A /* SpamCaptchaViewController.swift in Sources */,
3465948424352FE900E5C510 /* OWSTableViewController.swift in Sources */,
3425A5A22631E051006D5863 /* CVText.swift in Sources */,
@ -5907,7 +5900,6 @@
452D1AF12081059C00A67F7F /* StringAdditionsTest.swift in Sources */,
4C2A538C23C5462300D28CD8 /* CVMessageMappingTest.swift in Sources */,
4C4BC6C32102D697004040C9 /* ContactDiscoveryOperationTest.swift in Sources */,
455AC69E1F4F8B0300134004 /* ImageCacheTest.swift in Sources */,
34E8A8D12085238A00B272B1 /* ProtoParsingTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -1204,12 +1204,9 @@ fileprivate extension CVComponentState {
// TODO: Now that we're caching the displayable text on the view items,
// I'm not sure if we still need this cache.
private static let displayableTextCache: NSCache<NSString, DisplayableText> = {
let cache = NSCache<NSString, DisplayableText>()
// Cache the results for up to 1,000 messages.
cache.countLimit = 1000
return cache
}()
//
// Cache the results for up to 1,000 messages.
private static let displayableTextCache = NSCache<NSString, DisplayableText>(countLimit: 1000)
static func displayableText(cacheKey: String,
mentionStyle: Mention.Style,

View File

@ -7,14 +7,8 @@ import Foundation
@objc
public class CVMediaCache: NSObject {
private static func buildMediaCache(countLimit: Int) -> NSCache<NSString, AnyObject> {
let cache = NSCache<NSString, AnyObject>()
cache.countLimit = countLimit
return cache
}
private let stillMediaCache = buildMediaCache(countLimit: 16)
private let animatedMediaCache = buildMediaCache(countLimit: 8)
private let stillMediaCache = NSCache<NSString, AnyObject>(countLimit: 16)
private let animatedMediaCache = NSCache<NSString, AnyObject>(countLimit: 8)
private let stillMediaViewCache = MediaInnerCache<String, ReusableMediaView>(maxSize: 12)
private let animatedMediaViewCache = MediaInnerCache<String, ReusableMediaView>(maxSize: 6)
@ -84,15 +78,13 @@ public class CVMediaCache: NSObject {
private class MediaInnerCache<KeyType: Hashable, ValueType> {
private let maxSize: UInt
private var cache = OrderedDictionary<KeyType, ValueType>()
private var cache: LRUCache<KeyType, ValueType>
@objc
public required init(maxSize: UInt = 0) {
public required init(maxSize: Int = 0) {
AssertIsOnMainThread()
self.maxSize = maxSize
cache = LRUCache<KeyType, ValueType>(maxSize: maxSize)
}
// MARK: - API
@ -100,30 +92,18 @@ private class MediaInnerCache<KeyType: Hashable, ValueType> {
func get(_ key: KeyType) -> ValueType? {
AssertIsOnMainThread()
guard let value = cache[key] else {
return nil
}
cache.moveExistingKeyToFirst(key)
return value
return cache.get(key: key)
}
func set(value: ValueType, forKey key: KeyType) {
AssertIsOnMainThread()
guard maxSize > 0 else {
return
}
cache.remove(key: key)
cache.prepend(key: key, value: value)
if cache.count > maxSize {
cache.removeSubrange(Int(maxSize)...)
}
cache.set(key: key, value: value)
}
func removeAllObjects() {
AssertIsOnMainThread()
cache.removeAll()
cache.clear()
}
}

View File

@ -127,7 +127,7 @@ const CGFloat kMaxIPadTextViewHeight = 142;
_conversationStyle = conversationStyle;
_receivedSafeAreaInsets = UIEdgeInsetsZero;
_suggestedStickerViewCache = [NSCache new];
_suggestedStickerViewCache = [[NSCache alloc] initWithCountLimit:12];
self.inputToolbarDelegate = inputToolbarDelegate;

View File

@ -125,7 +125,7 @@ NSString *const kArchiveButtonPseudoGroup = @"kArchiveButtonPseudoGroup";
{
_blocklistCache = [OWSBlockListCache new];
[_blocklistCache startObservingAndSyncStateWithDelegate:self];
_threadViewModelCache = [NSCache new];
_threadViewModelCache = [[NSCache alloc] initWithCountLimit:32];
_threadMapping = [ThreadMapping new];
}

View File

@ -69,7 +69,8 @@ class GroupDescriptionPreviewView: ManualLayoutView {
)
private static let moreTextPlusPrefixLength = (moreTextPrefix + moreText).utf16.count
private static let textThatFitsCache = NSCache<NSString, NSString>()
private let textThatFitsCache = NSCache<NSString, NSString>(countLimit: 128)
func truncateVisibleTextIfNecessary() {
// When using autolayout, we need to initially set the text
// to the full text otherwise the view will never get any width.
@ -85,7 +86,7 @@ class GroupDescriptionPreviewView: ManualLayoutView {
// If we have already determine the attributed text for
// this size + description, use it.
if let cachedText = Self.textThatFitsCache.object(forKey: cacheKey) {
if let cachedText = textThatFitsCache.object(forKey: cacheKey) {
return setTextThatFits(cachedText as String)
}
@ -94,7 +95,7 @@ class GroupDescriptionPreviewView: ManualLayoutView {
setTextThatFits(textThatFits)
// Cache the text that fits for this size + description.
Self.textThatFitsCache.setObject(textThatFits as NSString, forKey: cacheKey)
textThatFitsCache.setObject(textThatFits as NSString, forKey: cacheKey)
}
setTextThatFits(textThatFits)

View File

@ -1,62 +0,0 @@
//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import XCTest
@testable import Signal
class ImageCacheTest: SignalBaseTest {
var imageCache: ImageCache!
let firstVariation = UIImage(color: .red, size: CGSize(square: 1))
let secondVariation = UIImage(color: .blue, size: CGSize(square: 1))
let otherImage = UIImage(color: .green, size: CGSize(square: 1))
let cacheKey1 = "cache-key-1" as NSString
let cacheKey2 = "cache-key-2" as NSString
override func setUp() {
super.setUp()
self.imageCache = ImageCache()
imageCache.setImage(firstVariation, forKey: cacheKey1, diameter: 100)
imageCache.setImage(secondVariation, forKey: cacheKey1, diameter: 200)
imageCache.setImage(otherImage, forKey: cacheKey2, diameter: 100)
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testSetGet() {
XCTAssertEqual(firstVariation, imageCache.image(forKey: cacheKey1, diameter: 100))
XCTAssertEqual(secondVariation, imageCache.image(forKey: cacheKey1, diameter: 200))
XCTAssertNotEqual(secondVariation, imageCache.image(forKey: cacheKey1, diameter: 100))
XCTAssertEqual(otherImage, imageCache.image(forKey: cacheKey2, diameter: 100))
XCTAssertNil(imageCache.image(forKey: cacheKey2, diameter: 200))
}
func testRemoveAllForKey() {
// sanity check
XCTAssertEqual(firstVariation, imageCache.image(forKey: cacheKey1, diameter: 100))
XCTAssertEqual(otherImage, imageCache.image(forKey: cacheKey2, diameter: 100))
imageCache.removeAllImages(forKey: cacheKey1)
XCTAssertNil(imageCache.image(forKey: cacheKey1, diameter: 100))
XCTAssertNil(imageCache.image(forKey: cacheKey1, diameter: 200))
XCTAssertEqual(otherImage, imageCache.image(forKey: cacheKey2, diameter: 100))
}
func testRemoveAll() {
XCTAssertEqual(firstVariation, imageCache.image(forKey: cacheKey1, diameter: 100))
imageCache.removeAllImages()
XCTAssertNil(imageCache.image(forKey: cacheKey1, diameter: 100))
XCTAssertNil(imageCache.image(forKey: cacheKey1, diameter: 200))
XCTAssertNil(imageCache.image(forKey: cacheKey2, diameter: 100))
}
}

View File

@ -81,7 +81,7 @@ public class StickerKeyboard: CustomKeyboard {
updatePageConstraints()
}
private let reusableStickerViewCache = NSCache<StickerInfo, StickerReusableView>()
private let reusableStickerViewCache = NSCache<StickerInfo, StickerReusableView>(countLimit: 32)
private func reloadStickers() {
let oldStickerPacks = stickerPacks

View File

@ -235,7 +235,7 @@ public class StickerPackCollectionView: UICollectionView {
return StickerView.stickerView(forStickerInfo: stickerInfo, dataSource: stickerPackDataSource)
}
private let reusableStickerViewCache = NSCache<StickerInfo, StickerReusableView>()
private let reusableStickerViewCache = NSCache<StickerInfo, StickerReusableView>(countLimit: 32)
private func reusableStickerView(forStickerInfo stickerInfo: StickerInfo) -> StickerReusableView {
let view: StickerReusableView = {
if let view = reusableStickerViewCache.object(forKey: stickerInfo) { return view }

View File

@ -298,7 +298,7 @@ extension Wallpaper {
fileprivate extension Wallpaper {
static let appSharedDataDirectory = URL(fileURLWithPath: OWSFileSystem.appSharedDataDirectoryPath())
static let wallpaperDirectory = URL(fileURLWithPath: "Wallpapers", isDirectory: true, relativeTo: appSharedDataDirectory)
static let cache = NSCache<NSString, UIImage>()
static let cache = NSCache<NSString, UIImage>(countLimit: 3)
static func ensureWallpaperDirectory() throws {
guard OWSFileSystem.ensureDirectoryExists(wallpaperDirectory.path) else {

View File

@ -66,10 +66,8 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
_signalAccounts = @[];
_systemContactsFetcher = [SystemContactsFetcher new];
_systemContactsFetcher.delegate = self;
_cnContactCache = [NSCache new];
_cnContactCache.countLimit = 50;
_cnContactAvatarCache = [NSCache new];
_cnContactAvatarCache.countLimit = 25;
_cnContactCache = [[NSCache alloc] initWithCountLimit:50];
_cnContactAvatarCache = [[NSCache alloc] initWithCountLimit:25];
OWSSingletonAssert();

View File

@ -66,7 +66,7 @@ public extension GroupV2Params {
return ciphertext
}
private static let decryptedBlobCache = NSCache<NSData, NSData>()
private static let decryptedBlobCache = NSCache<NSData, NSData>(countLimit: 16)
private static let decryptedBlobCacheMaxItemSize: UInt = 4 * 1024
fileprivate func decryptBlob(_ ciphertext: Data) throws -> Data {
@ -90,7 +90,7 @@ public extension GroupV2Params {
return try uuid(forUuidCiphertext: uuidCiphertext)
}
private static let decryptedUuidCache = NSCache<NSData, NSUUID>()
private static let decryptedUuidCache = NSCache<NSData, NSUUID>(countLimit: 256)
func uuid(forUuidCiphertext uuidCiphertext: UuidCiphertext) throws -> UUID {
let cacheKey = (groupSecretParamsData + uuidCiphertext.serialize().asData) as NSData
@ -117,7 +117,7 @@ public extension GroupV2Params {
return userId
}
private static let decryptedProfileKeyCache = NSCache<NSData, NSData>()
private static let decryptedProfileKeyCache = NSCache<NSData, NSData>(countLimit: 256)
func profileKey(forProfileKeyCiphertext profileKeyCiphertext: ProfileKeyCiphertext,
uuid: UUID) throws -> Data {

View File

@ -398,7 +398,7 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
}
}
private let changeCache = NSCache<NSString, ChangeCacheItem>()
private let changeCache = NSCache<NSString, ChangeCacheItem>(countLimit: 5)
private class ChangeCacheItem: NSObject {
let groupChanges: [GroupV2Change]

View File

@ -1478,7 +1478,7 @@ public class GroupsV2Impl: NSObject, GroupsV2Swift {
}
}
private let groupInviteLinkPreviewCache = NSCache<NSData, GroupInviteLinkPreview>()
private let groupInviteLinkPreviewCache = NSCache<NSData, GroupInviteLinkPreview>(countLimit: 5)
private func groupInviteLinkPreviewCacheKey(groupSecretParamsData: Data) -> NSData {
groupSecretParamsData as NSData

View File

@ -466,7 +466,7 @@ public class AvatarBuilder: NSObject {
}
// TODO: Tune configuration of this NSCache.
private let requestToContentCache: NSCache<NSString, AvatarContent> = NSCache(countLimit: 1024)
private let requestToContentCache = NSCache<NSString, AvatarContent>(countLimit: 1024)
private func avatarContent(forRequest request: Request,
transaction: SDSAnyReadTransaction) -> AvatarContent? {
@ -487,7 +487,7 @@ public class AvatarBuilder: NSObject {
}
// TODO: Tune configuration of this NSCache.
private let contentToImageCache: NSCache<NSString, UIImage> = NSCache(countLimit: 128)
private let contentToImageCache = NSCache<NSString, UIImage>(countLimit: 128)
private func avatarImage(forAvatarContent avatarContent: AvatarContent) -> UIImage? {
let cacheKey = avatarContent.cacheKey
@ -1058,14 +1058,3 @@ extension AvatarBuilder {
}
}
}
// MARK: -
@objc
public extension NSCache {
convenience init(countLimit: Int) {
self.init()
self.countLimit = countLimit
}
}

View File

@ -1,57 +0,0 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
import UIKit
class ImageCacheRecord: NSObject {
var variations: [CGFloat: UIImage]
init(variations: [CGFloat: UIImage]) {
self.variations = variations
}
}
/**
* A two dimensional hash, allowing you to store variations under a single key.
* This is useful because we generate multiple diameters of an image, but when we
* want to clear out the images for a key we want to clear out *all* variations.
*/
@objc
public class ImageCache: NSObject {
let backingCache: NSCache<AnyObject, ImageCacheRecord>
public override init() {
self.backingCache = NSCache()
}
@objc
public func image(forKey key: AnyObject, diameter: CGFloat) -> UIImage? {
guard let record = backingCache.object(forKey: key) else {
return nil
}
return record.variations[diameter]
}
@objc
public func setImage(_ image: UIImage, forKey key: AnyObject, diameter: CGFloat) {
if let existingRecord = backingCache.object(forKey: key) {
existingRecord.variations[diameter] = image
backingCache.setObject(existingRecord, forKey: key)
} else {
let newRecord = ImageCacheRecord(variations: [diameter: image])
backingCache.setObject(newRecord, forKey: key)
}
}
@objc
public func removeAllImages() {
backingCache.removeAllObjects()
}
@objc
public func removeAllImages(forKey key: AnyObject) {
backingCache.removeObject(forKey: key)
}
}

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
@ -175,7 +175,7 @@ public extension ContactDiscoveryTask {
public extension ContactDiscoveryTask {
private static let unfairLock = UnfairLock()
private static let undiscoverableUserCache = NSCache<NSString, NSDate>()
private static let undiscoverableUserCache = NSCache<NSString, NSDate>(countLimit: 256)
fileprivate static func markUsersAsRecentlyKnownToBeUndiscoverable(_ addresses: [SignalServiceAddress]) {
guard !addresses.isEmpty else {

View File

@ -5,6 +5,7 @@
#import <SignalServiceKit/ContactsManagerProtocol.h>
#import <SignalServiceKit/FunctionalUtil.h>
#import <SignalServiceKit/PhoneNumberUtil.h>
#import <SignalServiceKit/SignalServiceKit-Swift.h>
#import <libPhoneNumber_iOS/NBPhoneNumber.h>
NS_ASSUME_NONNULL_BEGIN
@ -37,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
if (self) {
_nbPhoneNumberUtil = [[NBPhoneNumberUtil alloc] init];
_countryCodesFromCallingCodeCache = [NSMutableDictionary new];
_parsedPhoneNumberCache = [NSCache new];
_parsedPhoneNumberCache = [[NSCache alloc] initWithCountLimit:256];
}
return self;

View File

@ -9,7 +9,7 @@ class DownloadStickerOperation: CDNDownloadOperation {
// MARK: - Cache
private static let cache = NSCache<NSString, NSURL>()
private static let cache = NSCache<NSString, NSURL>(countLimit: 256)
public class func cachedUrl(for stickerInfo: StickerInfo) -> URL? {
guard let stickerUrl = cache.object(forKey: stickerInfo.asKey() as NSString) else {

View File

@ -873,7 +873,7 @@ public class StickerManager: NSObject {
private static let cacheQueue = DispatchQueue(label: "stickerManager.cacheQueue")
// This cache shoud only be accessed on cacheQueue.
private var suggestedStickersCache = NSCache<NSString, NSArray>()
private var suggestedStickersCache = NSCache<NSString, NSArray>(countLimit: 5)
// We clear the cache every time we install or uninstall a sticker.
private func clearSuggestedStickersCache() {

View File

@ -214,7 +214,7 @@ class GRDBFullTextSearchFinder: NSObject {
private static let serialQueue = DispatchQueue(label: "org.signal.fts")
// This should only be accessed on serialQueue.
private static let ftsCache: NSCache<NSString, NSString> = NSCache()
private static let ftsCache = NSCache<NSString, NSString>(countLimit: 128)
private class func cacheKey(collection: String, uniqueId: String) -> String {
return "\(collection).\(uniqueId)"

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
@objc
@ -28,6 +28,8 @@ public class AnyLRUCache: NSObject {
}
}
// MARK: -
// A simple LRU cache bounded by the number of entries.
public class LRUCache<KeyType: Hashable & Equatable, ValueType> {
@ -103,3 +105,16 @@ public class LRUCache<KeyType: Hashable & Equatable, ValueType> {
cacheOrder.removeAll()
}
}
// MARK: -
@objc
public extension NSCache {
@objc(initWithCountLimit:)
public convenience init(countLimit: Int) {
self.init()
// TODO: We might set count limit to zero in NSE?
self.countLimit = countLimit
}
}

View File

@ -84,8 +84,11 @@ private class ModelCacheAdapter<KeyType: AnyObject & Hashable, ValueType: BaseMo
let cacheName: String
init(cacheName: String) {
let cacheCountLimit: Int
init(cacheName: String, cacheCountLimit: Int) {
self.cacheName = cacheName
self.cacheCountLimit = cacheCountLimit
}
}
@ -133,7 +136,7 @@ private class ModelReadCache<KeyType: AnyObject & Hashable, ValueType: BaseModel
// NSCache's default behavior is opaque.
// We're currently only using this to cache
// small models, but that could change.
fileprivate let nsCache = NSCache<KeyType, ModelCacheValueBox<ValueType>>()
fileprivate let nsCache: NSCache<KeyType, ModelCacheValueBox<ValueType>>
private let adapter: ModelCacheAdapter<KeyType, ValueType>
@ -151,6 +154,7 @@ private class ModelReadCache<KeyType: AnyObject & Hashable, ValueType: BaseModel
init(mode: Mode, adapter: ModelCacheAdapter<KeyType, ValueType>) {
self.mode = mode
self.adapter = adapter
self.nsCache = NSCache(countLimit: adapter.cacheCountLimit)
switch mode {
case .read:
@ -649,7 +653,7 @@ public class UserProfileReadCache: NSObject {
}
private let cache: ModelReadCacheWrapper<KeyType, ValueType>
private let adapter = Adapter(cacheName: "UserProfile")
private let adapter = Adapter(cacheName: "UserProfile", cacheCountLimit: 32)
@objc
public override init() {
@ -718,7 +722,7 @@ public class SignalAccountReadCache: NSObject {
}
private let cache: ModelReadCacheWrapper<KeyType, ValueType>
private let adapter = Adapter(cacheName: "SignalAccount")
private let adapter = Adapter(cacheName: "SignalAccount", cacheCountLimit: 32)
@objc
public override init() {
@ -786,7 +790,7 @@ public class SignalRecipientReadCache: NSObject {
}
private let cache: ModelReadCacheWrapper<KeyType, ValueType>
private let adapter = Adapter(cacheName: "SignalRecipient")
private let adapter = Adapter(cacheName: "SignalRecipient", cacheCountLimit: 32)
@objc
public override init() {
@ -851,7 +855,7 @@ public class ThreadReadCache: NSObject {
}
private let cache: ModelReadCacheWrapper<KeyType, ValueType>
private let adapter = Adapter(cacheName: "TSThread")
private let adapter = Adapter(cacheName: "TSThread", cacheCountLimit: 32)
@objc
public override init() {
@ -925,7 +929,7 @@ public class InteractionReadCache: NSObject {
}
private let cache: ModelReadCacheWrapper<KeyType, ValueType>
private let adapter = Adapter(cacheName: "TSInteraction")
private let adapter = Adapter(cacheName: "TSInteraction", cacheCountLimit: 256)
@objc
public override init() {
@ -1003,7 +1007,7 @@ public class AttachmentReadCache: NSObject {
}
private let cache: ModelReadCacheWrapper<KeyType, ValueType>
private let adapter = Adapter(cacheName: "TSAttachment")
private let adapter = Adapter(cacheName: "TSAttachment", cacheCountLimit: 256)
@objc
public override init() {
@ -1067,7 +1071,7 @@ public class InstalledStickerCache: NSObject {
}
private let cache: ModelReadCacheWrapper<KeyType, ValueType>
private let adapter = Adapter(cacheName: "InstalledSticker")
private let adapter = Adapter(cacheName: "InstalledSticker", cacheCountLimit: 32)
@objc
public override init() {