Apply count limits to all NSCache, clean up caching.
This commit is contained in:
parent
13205bb635
commit
82aab5ea12
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ const CGFloat kMaxIPadTextViewHeight = 142;
|
||||
|
||||
_conversationStyle = conversationStyle;
|
||||
_receivedSafeAreaInsets = UIEdgeInsetsZero;
|
||||
_suggestedStickerViewCache = [NSCache new];
|
||||
_suggestedStickerViewCache = [[NSCache alloc] initWithCountLimit:12];
|
||||
|
||||
self.inputToolbarDelegate = inputToolbarDelegate;
|
||||
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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 }
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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)"
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user