We ship with 49 stickers and the previous cache size of 32 led to
thrasing every time a chat was opened.
Since sticker packs can be as large as 200 stickers and we hold three
pages in cache while the keyboard is open, increase the cache size for
the main app to 600. For the share extension, make it 64 to minimize
memory use while avoiding threashing.
The cost of this cache is just the sticker metadata (unique ID, emoji
description, etc.) so it won't make much difference in memory
utilization.
When profile updates are applied, we diff them to
avoid redundant saves and the resulting work (like
reloading all cells of the conversation).
The diff often failed spuriously because
OWSUserProfileBadgeInfo did not implement
`isEqual:` and instead relied on `NSObject`'s
default implementation using pointer equality.
This commit makes two changes:
1. Implement `-[OWSUserProfileBadgeInfo isEqual:]`
2. Force the ProfileBadge to be loaded prior to
comparing snapshots so the comparison will be
correct.
This significantly reduces the number of database
calls when opening a large chat. It may possibly
increase the amount of DB work needed for smaller
groups by loading the profile badge earlier.
The default cache size for a SQLite connection is 2000KiB, but our
database pool has several reader connections plus a writer connection.
They can't share a cache because that changes SQLite's locking model,
so the next best thing is to limit their caches individually when
we're in a memory-constrained environment. To avoid the caches getting
*too* small, this also removes one of the available readers outside
the main app.
Every single message updates a TSThread model, but only a change in a
member's profile name or phone number, or a change to a group's model,
can update the indexing information. Turn 'shouldBeIndexedForFTS' into
a tri-state 'FTSIndexMode' with options 'never', 'manualUpdates', and
'always', and use 'manualUpdates' for TSThreads. Then explicitly
reindex on any of the changes listed above.
Previously this class used AtomicOptional for its properties, a
convenience wrapper we have for protecting a single value with a lock.
This wrapper trades extra heap allocations for simplicity (stepping
around Swift's prohibitions on non-atomically mutating struct
properties or relying on the addresses of object properties). However,
SignalServiceAddresses are created in sufficient numbers to make this
trade-off a problem.
This commit unboxes all of the properties on a SignalServiceAddress
and manually protects them with a shared dedicated UnfairLock.
(AtomicOptional and AtomicValue also use a shared lock, so this is no
less efficient and could actually lead to *less* contention.)
The UI updates (including adding a new message to conversation) were
being blocked for 1 second because of the animated dismissal of message
quote panel attached to the input field.
The fix is to block UI updates just for the duration of keyboard animations.
textView(_:shouldInteractWith:in:) were deprecated in iOS 10.
This change is purely deletion of code because newer UITextViewDelegate
methods: textView(_:shouldInteractWith:in:interaction:) were already
implemented.
Randall hit an issue where his device would take a few seconds to start
up. His logs indicate that his device is spending time running
LaunchJobs.
The first change here is to make sure we explicitly set the launch job
work at an ultra-high priority. This is okay, since we don't actually
present UI until after we finish these jobs. Running this work at
UserInteractive is appropriate since it quite literally prevents the
user from interacting with the app. There's also no other time-sensitive
UI work we need to be doing (like running animations) that we could be
contending with.
The second change is to add a bit more logging that allows us to monitor
the amount of work these jobs are doing. This will allow us to see if
these jobs are performing an excessive amount of work.
Finally, I moved these LaunchJobs to Swift. Mostly because the ObjC
implementations were block based. The additional code was going to
indent things further and our linter aggressiely indents blocks to begin
with. Moving this to Swift is much more readable.