---
title: "Keeping A SwiftUI App Quiet When Nothing Changed"
url: https://deallocatedobjects.com/posts/keeping-a-swiftui-app-quiet-when-nothing-changed
author: Jake Marsh
published: 2026-11-12
updated: 2026-11-12
topics: ["Apple", "Xcode & Tools"]
description: "@Published doesn’t compare values. Assign the same value and it still tells every observer that something changed. Here’s a small test: Swift That matters most in code that runs on a timer."
---

# Keeping A SwiftUI App Quiet When Nothing Changed

By Jake Marsh, November 12, 2026. HTML: https://deallocatedobjects.com/posts/keeping-a-swiftui-app-quiet-when-nothing-changed

`@Published` doesn't compare values. Assign the same value and it still tells every observer that something changed. Here's a small test:

```swift
final class Store: ObservableObject {
    @Published var isLoading = false
    @Published var error: String? = nil
}

let store = Store()
var count = 0
let sink = store.objectWillChange.sink { count += 1 }

for _ in 0..<5 {
    store.isLoading = false
    store.error = nil
}
print(count) // 10
```

That matters most in code that runs on a timer. [Postage](https://postageformac.com/?ref=deallocated-post), my Mac email client, refreshes in the background every minute on my Mac, and most of those refreshes find nothing new. The store's routine bookkeeping came to about five assignments plus two per account each time. Each one republishes the store and re-renders every window observing it.

So the refresh now checks before it assigns:

```swift title="EmailStore.swift"
if error != nil { error = nil }
if isLoading { isLoading = false }
if !hasAttemptedLoad { hasAttemptedLoad = true }

let total = known.reduce(0) { $0 + $1.messageCount }
if serverTotalCount != total { serverTotalCount = total }
```

`removeDuplicates()` won't help here. It filters what a subscriber to `$isLoading` sees, while SwiftUI is listening to `objectWillChange`, which has already fired.

### The Same Check Further Down

Once the UI was quiet, the same pattern showed up in two other places in that refresh.

The Dock badge was set per folder and per account on every pass. `EmailStore` is the only thing in the app that writes the badge, so it can remember the last value:

```swift
private var lastBadgeCount: Int?

private func setBadgeIfChanged(_ count: Int) {
    guard lastBadgeCount != count else { return }
    lastBadgeCount = count
    UNUserNotificationCenter.current().setBadgeCount(count)
}
```

If you use this, make sure nothing else sets the badge, or the remembered value goes stale.

The database got one commit per folder to store each mailbox's sync state, even when it hadn't moved. IMAP makes this check easy: if `UIDVALIDITY` and `UIDNEXT` match what's stored, nothing new has arrived, and there's nothing to write:

```swift
let state = MailboxSyncState(uidValidity: selection.uidValidity, uidNext: selection.uidNext)
if state != previousState {
    db.setMailboxState(state, accountEmail: scope.accountEmail, mailbox: scope.mailbox)
}
```

To find this in your own app, start with whatever runs on a timer and look at what it does when nothing has changed.
