damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit ceb6eb03fb956e47e88bb26ab8a3bfc9f26f785e
parent b917b4e9d6cc877a41eb636e2e77f7f03cd2c5c5
Author: Daniel D’Aquino <daniel@daquino.me>
Date:   Tue,  7 May 2024 04:31:53 +0000

Implement cache on MutelistManager

To filter muted events on a timeline, we need to check if an event is
muted. However, we need to do so in a very efficient manner, to avoid performance degradation.

This commit improves performance by caching mute statuses for as long as
the mutelist stays the same.

Testing
--------

PASS

Device: iPhone 13 Mini
iOS: 17.4.1
Damus: This commit
Damus baseline: bb8dba6df6e2534dfb193402399b31a4fae8052d
Steps:
1. Downgrade to baseline version, Run SwiftUI profiler on Xcode instruments
2. Scroll down home feed. Try to notice hangs and microhangs on the UI
3. Upgrade to version under test. Start the same profiler test.
4. Check that hangs/microhangs frequency and severity are roughly the same.

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus/Models/MutelistManager.swift | 50+++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 45 insertions(+), 5 deletions(-)

diff --git a/damus/Models/MutelistManager.swift b/damus/Models/MutelistManager.swift @@ -11,10 +11,20 @@ class MutelistManager { let user_keypair: Keypair private(set) var event: NostrEvent? = nil - var users: Set<MuteItem> = [] - var hashtags: Set<MuteItem> = [] - var threads: Set<MuteItem> = [] - var words: Set<MuteItem> = [] + var users: Set<MuteItem> = [] { + didSet { self.reset_cache() } + } + var hashtags: Set<MuteItem> = [] { + didSet { self.reset_cache() } + } + var threads: Set<MuteItem> = [] { + didSet { self.reset_cache() } + } + var words: Set<MuteItem> = [] { + didSet { self.reset_cache() } + } + + var muted_notes_cache: [NoteId: EventMuteStatus] = [:] init(user_keypair: Keypair) { self.user_keypair = user_keypair @@ -46,6 +56,10 @@ class MutelistManager { threads = new_threads words = new_words } + + func reset_cache() { + self.muted_notes_cache = [:] + } func is_muted(_ item: MuteItem) -> Bool { switch item { @@ -119,13 +133,25 @@ class MutelistManager { threads.remove(item) } } + + func event_muted_reason(_ ev: NostrEvent) -> MuteItem? { + if let cached_mute_status = self.muted_notes_cache[ev.id] { + return cached_mute_status.mute_reason() + } + if let reason = self.compute_event_muted_reason(ev) { + self.muted_notes_cache[ev.id] = .muted(reason: reason) + return reason + } + self.muted_notes_cache[ev.id] = .not_muted + return nil + } /// Check if an event is muted given a collection of ``MutedItem``. /// /// - Parameter ev: The ``NostrEvent`` that you want to check the muted reason for. /// - Returns: The ``MuteItem`` that matched the event. Or `nil` if the event is not muted. - func event_muted_reason(_ ev: NostrEvent) -> MuteItem? { + func compute_event_muted_reason(_ ev: NostrEvent) -> MuteItem? { // Events from the current user should not be muted. guard self.user_keypair.pubkey != ev.pubkey else { return nil } @@ -164,4 +190,18 @@ class MutelistManager { return nil } + + enum EventMuteStatus { + case muted(reason: MuteItem) + case not_muted + + func mute_reason() -> MuteItem? { + switch self { + case .muted(reason: let reason): + return reason + case .not_muted: + return nil + } + } + } }