Don't cache CNContact.

pull/1/head
Matthew Chen 7 years ago
parent d3d9d2e64c
commit b9e2963f47

@ -36,7 +36,7 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
@property (nonatomic, readonly) SystemContactsFetcher *systemContactsFetcher; @property (nonatomic, readonly) SystemContactsFetcher *systemContactsFetcher;
@property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection; @property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection;
@property (nonatomic, readonly) YapDatabaseConnection *dbWriteConnection; @property (nonatomic, readonly) YapDatabaseConnection *dbWriteConnection;
@property (nonatomic, readonly) NSCache<NSString *, CNContact *> *cnContactCache; @property (nonatomic, readonly) AnyLRUCache *cnContactCache;
@end @end
@ -61,8 +61,7 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
_signalAccounts = @[]; _signalAccounts = @[];
_systemContactsFetcher = [SystemContactsFetcher new]; _systemContactsFetcher = [SystemContactsFetcher new];
_systemContactsFetcher.delegate = self; _systemContactsFetcher.delegate = self;
_cnContactCache = [NSCache new]; _cnContactCache = [[AnyLRUCache alloc] initWithMaxSize:50];
_cnContactCache.countLimit = 50;
OWSSingletonAssert(); OWSSingletonAssert();
@ -145,11 +144,14 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
return nil; return nil;
} }
CNContact *_Nullable cnContact = [self.cnContactCache objectForKey:contactId]; CNContact *_Nullable cnContact;
if (!cnContact) { @synchronized(self.cnContactCache) {
cnContact = [self.systemContactsFetcher fetchCNContactWithContactId:contactId]; cnContact = (CNContact * _Nullable)[self.cnContactCache getWithKey:contactId];
if (cnContact) { if (!cnContact) {
[self.cnContactCache setObject:cnContact forKey:contactId]; cnContact = [self.systemContactsFetcher fetchCNContactWithContactId:contactId];
if (cnContact) {
[self.cnContactCache setWithKey:contactId value:cnContact];
}
} }
} }

@ -24,26 +24,46 @@ public class AnyLRUCache: NSObject {
} }
// A simple LRU cache bounded by the number of entries. // A simple LRU cache bounded by the number of entries.
//
// TODO: We might want to observe memory pressure notifications.
public class LRUCache<KeyType: Hashable & Equatable, ValueType> { public class LRUCache<KeyType: Hashable & Equatable, ValueType> {
private var cacheMap: [KeyType: ValueType] = [:] private var cacheMap: [KeyType: ValueType] = [:]
private var cacheOrder: [KeyType] = [] private var cacheOrder: [KeyType] = []
private let maxSize: Int private let maxSize: Int
@objc
public init(maxSize: Int) { public init(maxSize: Int) {
self.maxSize = maxSize self.maxSize = maxSize
NotificationCenter.default.addObserver(self,
selector: #selector(didReceiveMemoryWarning),
name: NSNotification.Name.UIApplicationDidReceiveMemoryWarning,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func didReceiveMemoryWarning() {
SwiftAssertIsOnMainThread(#function)
cacheMap.removeAll()
cacheOrder.removeAll()
}
private func updateCacheOrder(key: KeyType) {
cacheOrder = cacheOrder.filter { $0 != key }
cacheOrder.append(key)
} }
public func get(key: KeyType) -> ValueType? { public func get(key: KeyType) -> ValueType? {
guard let value = cacheMap[key] else { guard let value = cacheMap[key] else {
// Miss
return nil return nil
} }
// Update cache order. // Hit
cacheOrder = cacheOrder.filter { $0 != key } updateCacheOrder(key: key)
cacheOrder.append(key)
return value return value
} }
@ -51,9 +71,7 @@ public class LRUCache<KeyType: Hashable & Equatable, ValueType> {
public func set(key: KeyType, value: ValueType) { public func set(key: KeyType, value: ValueType) {
cacheMap[key] = value cacheMap[key] = value
// Update cache order. updateCacheOrder(key: key)
cacheOrder = cacheOrder.filter { $0 != key }
cacheOrder.append(key)
while cacheOrder.count > maxSize { while cacheOrder.count > maxSize {
guard let staleKey = cacheOrder.first else { guard let staleKey = cacheOrder.first else {

Loading…
Cancel
Save